Merge "Revert the mandatory backups feature."
diff --git a/Android.bp b/Android.bp
index aeb3ceb..cb7f7a2 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1221,7 +1221,7 @@
     "--hide HiddenSuperclass --hide DeprecationMismatch --hide UnavailableSymbol " +
     "--hide SdkConstant --hide HiddenTypeParameter --hide Todo --hide Typo"
 
-doc_defaults {
+stubs_defaults {
     name: "metalava-api-stubs-default",
     srcs: [
         ":opt-telephony-srcs",
@@ -1246,10 +1246,9 @@
     ],
     local_sourcepaths: frameworks_base_subdirs,
     installable: false,
-    metalava_enabled: true,
-    metalava_annotations_enabled: true,
-    metalava_previous_api: ":last-released-public-api",
-    metalava_merge_annotations_dirs: [
+    annotations_enabled: true,
+    previous_api: ":last-released-public-api",
+    merge_annotations_dirs: [
         "metalava-manual",
         "ojluni-annotated-stubs",
     ],
@@ -1481,7 +1480,7 @@
     ],
 }
 
-droiddoc {
+droidstubs {
     name: "hiddenapi-lists-docs",
     defaults: ["metalava-api-stubs-default"],
     arg_files: [
@@ -1540,7 +1539,7 @@
     ],
 }
 
-droiddoc {
+droidstubs {
     name: "api-stubs-docs",
     defaults: ["metalava-api-stubs-default"],
     api_filename: "public_api.txt",
@@ -1562,7 +1561,7 @@
     },
 }
 
-droiddoc {
+droidstubs {
     name: "system-api-stubs-docs",
     defaults: ["metalava-api-stubs-default"],
     api_tag_name: "SYSTEM",
@@ -1586,7 +1585,7 @@
     },
 }
 
-droiddoc {
+droidstubs {
     name: "test-api-stubs-docs",
     defaults: ["metalava-api-stubs-default"],
     api_tag_name: "TEST",
diff --git a/api/current.txt b/api/current.txt
index e31f8a0..2c2bc5f 100755
--- a/api/current.txt
+++ b/api/current.txt
@@ -934,6 +934,7 @@
     field public static final int minSdkVersion = 16843276; // 0x101020c
     field public static final int minWidth = 16843071; // 0x101013f
     field public static final int minimumHorizontalAngle = 16843901; // 0x101047d
+    field public static final int minimumUiTimeout = 16844174; // 0x101058e
     field public static final int minimumVerticalAngle = 16843902; // 0x101047e
     field public static final int mipMap = 16843725; // 0x10103cd
     field public static final int mirrorForRtl = 16843726; // 0x10103ce
@@ -2874,10 +2875,12 @@
     method public int getCapabilities();
     method public deprecated java.lang.String getDescription();
     method public java.lang.String getId();
+    method public int getMinimumUiTimeoutMillis();
     method public android.content.pm.ResolveInfo getResolveInfo();
     method public java.lang.String getSettingsActivityName();
     method public java.lang.String loadDescription(android.content.pm.PackageManager);
     method public java.lang.CharSequence loadSummary(android.content.pm.PackageManager);
+    method public void setMinimumUiTimeoutMillis(int);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int CAPABILITY_CAN_CONTROL_MAGNIFICATION = 16; // 0x10
     field public static final int CAPABILITY_CAN_PERFORM_GESTURES = 32; // 0x20
@@ -42654,6 +42657,7 @@
     method public static int[] getSubscriptionIds(int);
     method public java.util.List<android.telephony.SubscriptionPlan> getSubscriptionPlans(int);
     method public boolean isNetworkRoaming(int);
+    method public static boolean isValidSubscriptionId(int);
     method public void removeOnOpportunisticSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnOpportunisticSubscriptionsChangedListener);
     method public void removeOnSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnSubscriptionsChangedListener);
     method public void setSubscriptionOverrideCongested(int, boolean, long);
@@ -49546,6 +49550,7 @@
     method public deprecated java.util.List<android.content.pm.ServiceInfo> getAccessibilityServiceList();
     method public java.util.List<android.accessibilityservice.AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int);
     method public java.util.List<android.accessibilityservice.AccessibilityServiceInfo> getInstalledAccessibilityServiceList();
+    method public int getMinimumUiTimeoutMillis();
     method public void interrupt();
     method public static boolean isAccessibilityButtonSupported();
     method public boolean isEnabled();
diff --git a/api/system-current.txt b/api/system-current.txt
index 1e1c621..e2c59cb 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -6785,7 +6785,6 @@
     method public static android.content.pm.PackageInfo getLoadedPackageInfo();
     method public static int loadWebViewNativeLibraryFromPackage(java.lang.String, java.lang.ClassLoader);
     method public static void prepareWebViewInZygote();
-    field public static final java.lang.String CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY = "persist.sys.webview.vmsize";
     field public static final int LIBLOAD_ADDRESS_SPACE_NOT_RESERVED = 2; // 0x2
     field public static final int LIBLOAD_FAILED_JNI_CALL = 7; // 0x7
     field public static final int LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES = 4; // 0x4
diff --git a/api/test-current.txt b/api/test-current.txt
index 0f89dfd..28e9734 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -1336,30 +1336,47 @@
     method public void writeRawZigZag64(long);
   }
 
-  public final class ProtoOutputStream {
+  public final class ProtoInputStream extends android.util.proto.ProtoStream {
+    ctor public ProtoInputStream(java.io.InputStream, int);
+    ctor public ProtoInputStream(java.io.InputStream);
+    ctor public ProtoInputStream(byte[]);
+    method public int decodeZigZag32(int);
+    method public long decodeZigZag64(long);
+    method public java.lang.String dumpDebugData();
+    method public void end(long);
+    method public int getFieldNumber();
+    method public int getOffset();
+    method public int getWireType();
+    method public boolean isNextField(long) throws java.io.IOException;
+    method public int nextField() throws java.io.IOException;
+    method public boolean readBoolean(long) throws java.io.IOException;
+    method public byte[] readBytes(long) throws java.io.IOException;
+    method public double readDouble(long) throws java.io.IOException;
+    method public float readFloat(long) throws java.io.IOException;
+    method public int readInt(long) throws java.io.IOException;
+    method public long readLong(long) throws java.io.IOException;
+    method public java.lang.String readString(long) throws java.io.IOException;
+    method public void skip() throws java.io.IOException;
+    method public long start(long) throws java.io.IOException;
+    field public static final int NO_MORE_FIELDS = -1; // 0xffffffff
+  }
+
+  public final class ProtoOutputStream extends android.util.proto.ProtoStream {
     ctor public ProtoOutputStream();
     ctor public ProtoOutputStream(int);
     ctor public ProtoOutputStream(java.io.OutputStream);
     ctor public ProtoOutputStream(java.io.FileDescriptor);
     method public static int checkFieldId(long, long);
-    method public static int convertObjectIdToOrdinal(int);
     method public void dump(java.lang.String);
     method public void end(long);
     method public deprecated void endObject(long);
     method public deprecated void endRepeatedObject(long);
     method public void flush();
     method public byte[] getBytes();
-    method public static int getDepthFromToken(long);
-    method public static int getObjectIdFromToken(long);
-    method public static boolean getRepeatedFromToken(long);
-    method public static int getSizePosFromToken(long);
-    method public static int getTagSizeFromToken(long);
     method public static long makeFieldId(int, long);
-    method public static long makeToken(int, boolean, int, int, int);
     method public long start(long);
     method public deprecated long startObject(long);
     method public deprecated long startRepeatedObject(long);
-    method public static java.lang.String token2String(long);
     method public void write(long, double);
     method public void write(long, float);
     method public void write(long, int);
@@ -1416,6 +1433,27 @@
     method public void writeTag(int, int);
     method public deprecated void writeUInt32(long, int);
     method public deprecated void writeUInt64(long, long);
+  }
+
+  public class ProtoParseException extends java.lang.RuntimeException {
+    ctor public ProtoParseException(java.lang.String);
+  }
+
+  public abstract class ProtoStream {
+    ctor public ProtoStream();
+    method public static int convertObjectIdToOrdinal(int);
+    method public static int getDepthFromToken(long);
+    method public static java.lang.String getFieldCountString(long);
+    method public static java.lang.String getFieldIdString(long);
+    method public static java.lang.String getFieldTypeString(long);
+    method public static int getObjectIdFromToken(long);
+    method public static int getOffsetFromToken(long);
+    method public static boolean getRepeatedFromToken(long);
+    method public static int getTagSizeFromToken(long);
+    method public static java.lang.String getWireTypeString(int);
+    method public static long makeFieldId(int, long);
+    method public static long makeToken(int, boolean, int, int, int);
+    method public static java.lang.String token2String(long);
     field public static final long FIELD_COUNT_MASK = 16492674416640L; // 0xf0000000000L
     field public static final long FIELD_COUNT_PACKED = 5497558138880L; // 0x50000000000L
     field public static final long FIELD_COUNT_REPEATED = 2199023255552L; // 0x20000000000L
@@ -1435,6 +1473,7 @@
     field public static final long FIELD_TYPE_INT64 = 12884901888L; // 0x300000000L
     field public static final long FIELD_TYPE_MASK = 1095216660480L; // 0xff00000000L
     field public static final long FIELD_TYPE_MESSAGE = 47244640256L; // 0xb00000000L
+    field protected static final java.lang.String[] FIELD_TYPE_NAMES;
     field public static final long FIELD_TYPE_SFIXED32 = 64424509440L; // 0xf00000000L
     field public static final long FIELD_TYPE_SFIXED64 = 68719476736L; // 0x1000000000L
     field public static final int FIELD_TYPE_SHIFT = 32; // 0x20
@@ -1444,7 +1483,6 @@
     field public static final long FIELD_TYPE_UINT32 = 55834574848L; // 0xd00000000L
     field public static final long FIELD_TYPE_UINT64 = 17179869184L; // 0x400000000L
     field public static final long FIELD_TYPE_UNKNOWN = 0L; // 0x0L
-    field public static final java.lang.String TAG = "ProtoOutputStream";
     field public static final int WIRE_TYPE_END_GROUP = 4; // 0x4
     field public static final int WIRE_TYPE_FIXED32 = 5; // 0x5
     field public static final int WIRE_TYPE_FIXED64 = 1; // 0x1
@@ -1454,8 +1492,8 @@
     field public static final int WIRE_TYPE_VARINT = 0; // 0x0
   }
 
-  public class ProtoParseException extends java.lang.RuntimeException {
-    ctor public ProtoParseException(java.lang.String);
+  public class WireTypeMismatchException extends android.util.proto.ProtoParseException {
+    ctor public WireTypeMismatchException(java.lang.String);
   }
 
 }
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index d117f39..2c07431 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -91,7 +91,7 @@
         ActivityForegroundStateChanged activity_foreground_state_changed = 42;
         IsolatedUidChanged isolated_uid_changed = 43;
         PacketWakeupOccurred packet_wakeup_occurred = 44;
-        // 45 is available
+        WallClockTimeShifted wall_clock_time_shifted = 45;
         AnomalyDetected anomaly_detected = 46;
         AppBreadcrumbReported app_breadcrumb_reported = 47;
         AppStartOccurred app_start_occurred = 48;
@@ -1479,6 +1479,18 @@
 }
 
 /**
+ * Logs the wall-clock time when a significant wall-clock time shift occurs.
+ * For example, this could be due to the user manually changing the time.
+ *
+ * Logged from:
+ *   frameworks/base/services/core/java/com/android/server/AlarmManagerService.java
+ */
+message WallClockTimeShifted {
+    // New wall-clock time in milliseconds, according to System.currentTimeMillis().
+    optional int64 wall_clock_timestamp_millis = 1;
+}
+
+/**
  * Logs when statsd detects an anomaly.
  *
  * Logged from:
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.cpp b/cmds/statsd/src/metrics/EventMetricProducer.cpp
index eec90fc..afd8ec2 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/EventMetricProducer.cpp
@@ -49,7 +49,6 @@
 // for EventMetricData
 const int FIELD_ID_ELAPSED_TIMESTAMP_NANOS = 1;
 const int FIELD_ID_ATOMS = 2;
-const int FIELD_ID_WALL_CLOCK_TIMESTAMP_NANOS = 3;
 
 EventMetricProducer::EventMetricProducer(const ConfigKey& key, const EventMetric& metric,
                                          const int conditionIndex,
@@ -146,13 +145,9 @@
     if (truncateTimestamp) {
         mProto->write(FIELD_TYPE_INT64 | FIELD_ID_ELAPSED_TIMESTAMP_NANOS,
             (long long)truncateTimestampNsToFiveMinutes(event.GetElapsedTimestampNs()));
-        mProto->write(FIELD_TYPE_INT64 | FIELD_ID_WALL_CLOCK_TIMESTAMP_NANOS,
-            (long long)truncateTimestampNsToFiveMinutes(getWallClockNs()));
     } else {
         mProto->write(FIELD_TYPE_INT64 | FIELD_ID_ELAPSED_TIMESTAMP_NANOS,
             (long long)event.GetElapsedTimestampNs());
-        mProto->write(FIELD_TYPE_INT64 | FIELD_ID_WALL_CLOCK_TIMESTAMP_NANOS,
-            (long long)getWallClockNs());
     }
 
     uint64_t eventToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_ATOMS);
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index bcfcd7a..02b9773 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -63,7 +63,6 @@
 // for GaugeBucketInfo
 const int FIELD_ID_ATOM = 3;
 const int FIELD_ID_ELAPSED_ATOM_TIMESTAMP = 4;
-const int FIELD_ID_WALL_CLOCK_ATOM_TIMESTAMP = 5;
 const int FIELD_ID_BUCKET_NUM = 6;
 const int FIELD_ID_START_BUCKET_ELAPSED_MILLIS = 7;
 const int FIELD_ID_END_BUCKET_ELAPSED_MILLIS = 8;
@@ -286,16 +285,9 @@
                     const int64_t elapsedTimestampNs =  truncateTimestamp ?
                         truncateTimestampNsToFiveMinutes(atom.mElapsedTimestamps) :
                             atom.mElapsedTimestamps;
-                    const int64_t wallClockNs = truncateTimestamp ?
-                        truncateTimestampNsToFiveMinutes(atom.mWallClockTimestampNs) :
-                            atom.mWallClockTimestampNs;
                     protoOutput->write(
                         FIELD_TYPE_INT64 | FIELD_COUNT_REPEATED | FIELD_ID_ELAPSED_ATOM_TIMESTAMP,
                         (long long)elapsedTimestampNs);
-                    protoOutput->write(
-                        FIELD_TYPE_INT64 | FIELD_COUNT_REPEATED |
-                            FIELD_ID_WALL_CLOCK_ATOM_TIMESTAMP,
-                        (long long)wallClockNs);
                 }
             }
             protoOutput->end(bucketInfoToken);
@@ -450,7 +442,7 @@
     if ((*mCurrentSlicedBucket)[eventKey].size() >= mGaugeAtomsPerDimensionLimit) {
         return;
     }
-    GaugeAtom gaugeAtom(getGaugeFields(event), eventTimeNs, getWallClockNs());
+    GaugeAtom gaugeAtom(getGaugeFields(event), eventTimeNs);
     (*mCurrentSlicedBucket)[eventKey].push_back(gaugeAtom);
     // Anomaly detection on gauge metric only works when there is one numeric
     // field specified.
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.h b/cmds/statsd/src/metrics/GaugeMetricProducer.h
index e3da5db..6379389 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.h
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.h
@@ -33,12 +33,11 @@
 namespace statsd {
 
 struct GaugeAtom {
-    GaugeAtom(std::shared_ptr<vector<FieldValue>> fields, int64_t elapsedTimeNs, int64_t wallClockNs)
-        : mFields(fields), mElapsedTimestamps(elapsedTimeNs), mWallClockTimestampNs(wallClockNs) {
+    GaugeAtom(std::shared_ptr<vector<FieldValue>> fields, int64_t elapsedTimeNs)
+        : mFields(fields), mElapsedTimestamps(elapsedTimeNs) {
     }
     std::shared_ptr<vector<FieldValue>> mFields;
     int64_t mElapsedTimestamps;
-    int64_t mWallClockTimestampNs;
 };
 
 struct GaugeBucket {
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index db7e680..ab0b23c 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -46,7 +46,7 @@
 
   optional Atom atom = 2;
 
-  optional int64 wall_clock_timestamp_nanos = 3;
+  optional int64 wall_clock_timestamp_nanos = 3 [deprecated = true];
 }
 
 message CountBucketInfo {
@@ -142,7 +142,7 @@
 
   repeated int64 elapsed_timestamp_nanos = 4;
 
-  repeated int64 wall_clock_timestamp_nanos = 5;
+  repeated int64 wall_clock_timestamp_nanos = 5 [deprecated = true];
 
   optional int64 bucket_num = 6;
 
diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
index ea6eb3f..5b6f167 100644
--- a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
+++ b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
@@ -148,7 +148,7 @@
     EXPECT_EQ(1, data.bucket_info(0).atom_size());
     EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
     EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
-    EXPECT_EQ(1, data.bucket_info(0).wall_clock_timestamp_nanos_size());
+    EXPECT_EQ(0, data.bucket_info(0).wall_clock_timestamp_nanos_size());
     EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
     EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
     EXPECT_TRUE(data.bucket_info(0).atom(0).temperature().sensor_name().empty());
@@ -271,7 +271,7 @@
     EXPECT_EQ(1, data.bucket_info(0).atom_size());
     EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
     EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
-    EXPECT_EQ(1, data.bucket_info(0).wall_clock_timestamp_nanos_size());
+    EXPECT_EQ(0, data.bucket_info(0).wall_clock_timestamp_nanos_size());
     EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
     EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
     EXPECT_TRUE(data.bucket_info(0).atom(0).temperature().sensor_name().empty());
@@ -375,7 +375,6 @@
     EXPECT_EQ(1, data.bucket_info(0).atom_size());
     EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
     EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
-    EXPECT_EQ(1, data.bucket_info(0).wall_clock_timestamp_nanos_size());
     EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
     EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
     EXPECT_TRUE(data.bucket_info(0).atom(0).temperature().sensor_name().empty());
diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
index 3de8d0d..5c1ef01 100644
--- a/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
+++ b/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
@@ -173,7 +173,7 @@
         if (sampling_type == GaugeMetric::ALL_CONDITION_CHANGES) {
             EXPECT_EQ(2, data.bucket_info(0).atom_size());
             EXPECT_EQ(2, data.bucket_info(0).elapsed_timestamp_nanos_size());
-            EXPECT_EQ(2, data.bucket_info(0).wall_clock_timestamp_nanos_size());
+            EXPECT_EQ(0, data.bucket_info(0).wall_clock_timestamp_nanos_size());
             EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
             EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
                       data.bucket_info(0).end_bucket_elapsed_nanos());
@@ -192,7 +192,6 @@
 
             EXPECT_EQ(1, data.bucket_info(1).atom_size());
             EXPECT_EQ(1, data.bucket_info(1).elapsed_timestamp_nanos_size());
-            EXPECT_EQ(1, data.bucket_info(1).wall_clock_timestamp_nanos_size());
             EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
                       data.bucket_info(1).start_bucket_elapsed_nanos());
             EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
@@ -206,7 +205,6 @@
 
             EXPECT_EQ(2, data.bucket_info(2).atom_size());
             EXPECT_EQ(2, data.bucket_info(2).elapsed_timestamp_nanos_size());
-            EXPECT_EQ(2, data.bucket_info(2).wall_clock_timestamp_nanos_size());
             EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
                       data.bucket_info(2).start_bucket_elapsed_nanos());
             EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
@@ -226,7 +224,6 @@
         } else {
             EXPECT_EQ(1, data.bucket_info(0).atom_size());
             EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
-            EXPECT_EQ(1, data.bucket_info(0).wall_clock_timestamp_nanos_size());
             EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
             EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
                       data.bucket_info(0).end_bucket_elapsed_nanos());
@@ -239,7 +236,6 @@
 
             EXPECT_EQ(1, data.bucket_info(1).atom_size());
             EXPECT_EQ(1, data.bucket_info(1).elapsed_timestamp_nanos_size());
-            EXPECT_EQ(1, data.bucket_info(1).wall_clock_timestamp_nanos_size());
             EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
                       data.bucket_info(1).start_bucket_elapsed_nanos());
             EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
@@ -253,7 +249,6 @@
 
             EXPECT_EQ(1, data.bucket_info(2).atom_size());
             EXPECT_EQ(1, data.bucket_info(2).elapsed_timestamp_nanos_size());
-            EXPECT_EQ(1, data.bucket_info(2).wall_clock_timestamp_nanos_size());
             EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
                       data.bucket_info(2).start_bucket_elapsed_nanos());
             EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
@@ -276,7 +271,6 @@
         EXPECT_EQ(1, data.bucket_info_size());
         EXPECT_EQ(1, data.bucket_info(0).atom_size());
         EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
-        EXPECT_EQ(1, data.bucket_info(0).wall_clock_timestamp_nanos_size());
         EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
                   data.bucket_info(0).start_bucket_elapsed_nanos());
         EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
diff --git a/config/boot-image-profile.txt b/config/boot-image-profile.txt
index 08b4705..b683138 100644
--- a/config/boot-image-profile.txt
+++ b/config/boot-image-profile.txt
@@ -24286,7 +24286,6 @@
 HSPLandroid/inputmethodservice/IInputMethodSessionWrapper;->getInternalInputMethodSession()Landroid/view/inputmethod/InputMethodSession;
 HSPLandroid/inputmethodservice/IInputMethodWrapper$InputMethodSessionCallbackWrapper;->sessionCreated(Landroid/view/inputmethod/InputMethodSession;)V
 HSPLandroid/inputmethodservice/IInputMethodWrapper;-><init>(Landroid/inputmethodservice/AbstractInputMethodService;Landroid/view/inputmethod/InputMethod;)V
-HSPLandroid/inputmethodservice/IInputMethodWrapper;->attachToken(Landroid/os/IBinder;)V
 HSPLandroid/inputmethodservice/IInputMethodWrapper;->bindInput(Landroid/view/inputmethod/InputBinding;)V
 HSPLandroid/inputmethodservice/IInputMethodWrapper;->createSession(Landroid/view/InputChannel;Lcom/android/internal/view/IInputSessionCallback;)V
 HSPLandroid/inputmethodservice/IInputMethodWrapper;->executeMessage(Landroid/os/Message;)V
@@ -42278,11 +42277,9 @@
 HSPLcom/android/internal/view/IInputContextCallback;->setTextAfterCursor(Ljava/lang/CharSequence;I)V
 HSPLcom/android/internal/view/IInputContextCallback;->setTextBeforeCursor(Ljava/lang/CharSequence;I)V
 HSPLcom/android/internal/view/IInputMethod$Stub$Proxy;->asBinder()Landroid/os/IBinder;
-HSPLcom/android/internal/view/IInputMethod$Stub$Proxy;->attachToken(Landroid/os/IBinder;)V
 HSPLcom/android/internal/view/IInputMethod$Stub;-><init>()V
 HSPLcom/android/internal/view/IInputMethod$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/view/IInputMethod;
 HSPLcom/android/internal/view/IInputMethod$Stub;->onTransact(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z
-HSPLcom/android/internal/view/IInputMethod;->attachToken(Landroid/os/IBinder;)V
 HSPLcom/android/internal/view/IInputMethod;->bindInput(Landroid/view/inputmethod/InputBinding;)V
 HSPLcom/android/internal/view/IInputMethod;->changeInputMethodSubtype(Landroid/view/inputmethod/InputMethodSubtype;)V
 HSPLcom/android/internal/view/IInputMethod;->createSession(Landroid/view/InputChannel;Lcom/android/internal/view/IInputSessionCallback;)V
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index f0a0e88..759443d 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -76,6 +76,7 @@
  * @attr ref android.R.styleable#AccessibilityService_notificationTimeout
  * @attr ref android.R.styleable#AccessibilityService_packageNames
  * @attr ref android.R.styleable#AccessibilityService_settingsActivity
+ * @attr ref android.R.styleable#AccessibilityService_minimumUiTimeout
  * @see AccessibilityService
  * @see android.view.accessibility.AccessibilityEvent
  * @see android.view.accessibility.AccessibilityManager
@@ -426,6 +427,13 @@
     public boolean crashed;
 
     /**
+     * The minimum timeout in milliseconds that UI controls need to remain on the screen.
+     *
+     * @see #setMinimumUiTimeoutMillis
+     */
+    private int mMinimumUiTimeout;
+
+    /**
      * The component name the accessibility service.
      */
     private ComponentName mComponentName;
@@ -529,6 +537,9 @@
             notificationTimeout = asAttributes.getInt(
                     com.android.internal.R.styleable.AccessibilityService_notificationTimeout,
                     0);
+            mMinimumUiTimeout = asAttributes.getInt(
+                    com.android.internal.R.styleable.AccessibilityService_minimumUiTimeout,
+                    0);
             flags = asAttributes.getInt(
                     com.android.internal.R.styleable.AccessibilityService_accessibilityFlags, 0);
             mSettingsActivityName = asAttributes.getString(
@@ -598,6 +609,7 @@
         packageNames = other.packageNames;
         feedbackType = other.feedbackType;
         notificationTimeout = other.notificationTimeout;
+        mMinimumUiTimeout = other.mMinimumUiTimeout;
         flags = other.flags;
     }
 
@@ -755,6 +767,29 @@
         return null;
     }
 
+    /**
+     * Set the minimum time that controls need to remain on the screen to support the user.
+     * <p>
+     *    <strong>This value can be dynamically set at runtime by
+     *    {@link AccessibilityService#setServiceInfo(AccessibilityServiceInfo)}.</strong>
+     * </p>
+     *
+     * @param timeout The timeout in milliseconds.
+     */
+    public void setMinimumUiTimeoutMillis(int timeout) {
+        mMinimumUiTimeout = timeout;
+    }
+
+    /**
+     * Get the minimum ui timeout.
+     *
+     * @see #setMinimumUiTimeoutMillis
+     * @return The timeout in milliseconds.
+     */
+    public int getMinimumUiTimeoutMillis() {
+        return mMinimumUiTimeout;
+    }
+
     /** {@hide} */
     public boolean isDirectBootAware() {
         return ((flags & FLAG_FORCE_DIRECT_BOOT_AWARE) != 0)
@@ -773,6 +808,7 @@
         parcel.writeStringArray(packageNames);
         parcel.writeInt(feedbackType);
         parcel.writeLong(notificationTimeout);
+        parcel.writeInt(mMinimumUiTimeout);
         parcel.writeInt(flags);
         parcel.writeInt(crashed ? 1 : 0);
         parcel.writeParcelable(mComponentName, flagz);
@@ -790,6 +826,7 @@
         packageNames = parcel.readStringArray();
         feedbackType = parcel.readInt();
         notificationTimeout = parcel.readLong();
+        mMinimumUiTimeout = parcel.readInt();
         flags = parcel.readInt();
         crashed = parcel.readInt() != 0;
         mComponentName = parcel.readParcelable(this.getClass().getClassLoader());
@@ -840,6 +877,8 @@
         stringBuilder.append(", ");
         stringBuilder.append("notificationTimeout: ").append(notificationTimeout);
         stringBuilder.append(", ");
+        stringBuilder.append("minimumUiTimeout: ").append(mMinimumUiTimeout);
+        stringBuilder.append(", ");
         appendFlags(stringBuilder, flags);
         stringBuilder.append(", ");
         stringBuilder.append("id: ").append(getId());
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index bf2d860..7b86646 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -2310,7 +2310,7 @@
      *
      * @param newConfig The new device configuration.
      */
-    public void onConfigurationChanged(Configuration newConfig) {
+    public void onConfigurationChanged(@NonNull Configuration newConfig) {
         if (DEBUG_LIFECYCLE) Slog.v(TAG, "onConfigurationChanged " + this + ": " + newConfig);
         mCalled = true;
 
@@ -6350,7 +6350,8 @@
      * @see android.view.Window#getLayoutInflater
      */
     @Nullable
-    public View onCreateView(String name, Context context, AttributeSet attrs) {
+    public View onCreateView(@NonNull String name, @NonNull Context context,
+            @NonNull AttributeSet attrs) {
         return null;
     }
 
@@ -6364,7 +6365,9 @@
      * @see android.view.LayoutInflater#createView
      * @see android.view.Window#getLayoutInflater
      */
-    public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
+    @Nullable
+    public View onCreateView(@Nullable View parent, @NonNull String name,
+            @NonNull Context context, @NonNull AttributeSet attrs) {
         if (!"fragment".equals(name)) {
             return onCreateView(name, context, attrs);
         }
diff --git a/core/java/android/app/Application.java b/core/java/android/app/Application.java
index 636366d..68b745d 100644
--- a/core/java/android/app/Application.java
+++ b/core/java/android/app/Application.java
@@ -127,7 +127,7 @@
     }
 
     @CallSuper
-    public void onConfigurationChanged(Configuration newConfig) {
+    public void onConfigurationChanged(@NonNull Configuration newConfig) {
         Object[] callbacks = collectComponentCallbacks();
         if (callbacks != null) {
             for (int i=0; i<callbacks.length; i++) {
diff --git a/core/java/android/content/ComponentCallbacks.java b/core/java/android/content/ComponentCallbacks.java
index b96c8d3..428545d 100644
--- a/core/java/android/content/ComponentCallbacks.java
+++ b/core/java/android/content/ComponentCallbacks.java
@@ -16,6 +16,7 @@
 
 package android.content;
 
+import android.annotation.NonNull;
 import android.content.res.Configuration;
 
 /**
@@ -44,7 +45,7 @@
      *
      * @param newConfig The new device configuration.
      */
-    void onConfigurationChanged(Configuration newConfig);
+    void onConfigurationChanged(@NonNull Configuration newConfig);
 
     /**
      * This is called when the overall system is running low on memory, and
diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java
index 1ee3c93..cb33659 100644
--- a/core/java/android/hardware/camera2/params/OutputConfiguration.java
+++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java
@@ -58,7 +58,7 @@
  * execute in parallel with any {@link Surface} initialization, such as waiting for a
  * {@link android.view.SurfaceView} to be ready as part of the UI initialization.</li>
  *
- * <li>The third and most complex usage pattern inlvolves surface sharing. Once instantiated an
+ * <li>The third and most complex usage pattern involves surface sharing. Once instantiated an
  * OutputConfiguration can be enabled for surface sharing via {@link #enableSurfaceSharing}. This
  * must be done before creating a new capture session and enables calls to
  * {@link CameraCaptureSession#updateOutputConfiguration}. An OutputConfiguration with enabled
diff --git a/core/java/android/hardware/display/BrightnessConfiguration.java b/core/java/android/hardware/display/BrightnessConfiguration.java
index 6d9ba77..7e52ca3 100644
--- a/core/java/android/hardware/display/BrightnessConfiguration.java
+++ b/core/java/android/hardware/display/BrightnessConfiguration.java
@@ -141,13 +141,6 @@
         private String mDescription;
 
         /**
-         * STOPSHIP remove when app has stopped using this.
-         * @hide
-         */
-        public Builder() {
-        }
-
-        /**
          * Constructs the builder with the control points for the brightness curve.
          *
          * Brightness curves must have strictly increasing ambient brightness values in lux and
@@ -159,24 +152,6 @@
          * @throws IllegalArgumentException if the nit levels are not monotonically increasing.
          */
         public Builder(float[] lux, float[] nits) {
-            setCurve(lux, nits);
-        }
-
-        /**
-         * Sets the control points for the brightness curve.
-         *
-         * Brightness curves must have strictly increasing ambient brightness values in lux and
-         * monotonically increasing display brightness values in nits. In addition, the initial
-         * control point must be 0 lux.
-         *
-         * @throws IllegalArgumentException if the initial control point is not at 0 lux.
-         * @throws IllegalArgumentException if the lux levels are not strictly increasing.
-         * @throws IllegalArgumentException if the nit levels are not monotonically increasing.
-         *
-         * STOPSHIP remove when app has stopped using this.
-         * @hide
-         */
-        public Builder setCurve(float[] lux, float[] nits) {
             Preconditions.checkNotNull(lux);
             Preconditions.checkNotNull(nits);
             if (lux.length == 0 || nits.length == 0) {
@@ -190,11 +165,10 @@
             }
             Preconditions.checkArrayElementsInRange(lux, 0, Float.MAX_VALUE, "lux");
             Preconditions.checkArrayElementsInRange(nits, 0, Float.MAX_VALUE, "nits");
-            checkMonotonic(lux, true/*strictly increasing*/, "lux");
+            checkMonotonic(lux, true /*strictly increasing*/, "lux");
             checkMonotonic(nits, false /*strictly increasing*/, "nits");
             mCurveLux = lux;
             mCurveNits = nits;
-            return this;
         }
 
         /**
diff --git a/core/java/android/inputmethodservice/IInputMethodWrapper.java b/core/java/android/inputmethodservice/IInputMethodWrapper.java
index 4080ee6..1030694 100644
--- a/core/java/android/inputmethodservice/IInputMethodWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java
@@ -160,11 +160,10 @@
                 args.recycle();
                 return;
             }
-
             case DO_INITIALIZE_INTERNAL: {
                 SomeArgs args = (SomeArgs) msg.obj;
                 try {
-                    inputMethod.initializeInternal((IBinder) args.arg1,
+                    inputMethod.initializeInternal((IBinder) args.arg1, msg.arg1,
                             (IInputMethodPrivilegedOperations) args.arg2);
                 } finally {
                     args.recycle();
@@ -253,9 +252,10 @@
 
     @BinderThread
     @Override
-    public void initializeInternal(IBinder token, IInputMethodPrivilegedOperations privOps) {
+    public void initializeInternal(IBinder token, int displayId,
+            IInputMethodPrivilegedOperations privOps) {
         mCaller.executeOrSendMessage(
-                mCaller.obtainMessageOO(DO_INITIALIZE_INTERNAL, token, privOps));
+                mCaller.obtainMessageIOO(DO_INITIALIZE_INTERNAL, displayId, token, privOps));
     }
 
     @BinderThread
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 2d12b86..34fa5b6 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -16,6 +16,7 @@
 
 package android.inputmethodservice;
 
+import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
@@ -461,10 +462,11 @@
          */
         @MainThread
         @Override
-        public final void initializeInternal(IBinder token,
+        public final void initializeInternal(IBinder token, int displayId,
                 IInputMethodPrivilegedOperations privilegedOperations) {
             mPrivOps.set(privilegedOperations);
             mImm.registerInputMethodPrivOps(token, mPrivOps);
+            updateInputMethodDisplay(displayId);
             attachToken(token);
         }
 
@@ -484,6 +486,22 @@
 
         /**
          * {@inheritDoc}
+         * @hide
+         */
+        @MainThread
+        @Override
+        public void updateInputMethodDisplay(int displayId) {
+            // Update display for adding IME window to the right display.
+            if (displayId != DEFAULT_DISPLAY) {
+                // TODO(b/111364446) Need to address context lifecycle issue if need to re-create
+                // for update resources & configuration correctly when show soft input
+                // in non-default display.
+                updateDisplay(displayId);
+            }
+        }
+
+        /**
+         * {@inheritDoc}
          *
          * <p>Calls {@link InputMethodService#onBindInput()} when done.</p>
          */
@@ -930,6 +948,9 @@
         // If the previous IME has occupied non-empty inset in the screen, we need to decide whether
         // we continue to use the same size of the inset or update it
         mShouldClearInsetOfPreviousIme = (mImm.getInputMethodWindowVisibleHeight() > 0);
+        // TODO(b/111364446) Need to address context lifecycle issue if need to re-create
+        // for update resources & configuration correctly when show soft input
+        // in non-default display.
         mInflater = (LayoutInflater)getSystemService(
                 Context.LAYOUT_INFLATER_SERVICE);
         mWindow = new SoftInputWindow(this, "InputMethod", mTheme, null, null, mDispatcherState,
diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index 9bcc600..40465ce 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -197,7 +197,7 @@
      *
      * <p>Example: "//www.google.com/search?q=android"
      *
-     * @return the decoded scheme-specific-part
+     * @return the encoded scheme-specific-part
      */
     public abstract String getEncodedSchemeSpecificPart();
 
diff --git a/core/java/android/os/BaseBundle.java b/core/java/android/os/BaseBundle.java
index 0fef78d..3d4c00c 100644
--- a/core/java/android/os/BaseBundle.java
+++ b/core/java/android/os/BaseBundle.java
@@ -1601,12 +1601,13 @@
     private void readFromParcelInner(Parcel parcel, int length) {
         if (length < 0) {
             throw new RuntimeException("Bad length in parcel: " + length);
-
         } else if (length == 0) {
             // Empty Bundle or end of data.
             mParcelledData = NoImagePreloadHolder.EMPTY_PARCEL;
             mParcelledByNative = false;
             return;
+        } else if (length % 4 != 0) {
+            throw new IllegalStateException("Bundle length is not aligned by 4: " + length);
         }
 
         final int magic = parcel.readInt();
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index e007398..026195e 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6508,6 +6508,25 @@
         public static final String MULTI_PRESS_TIMEOUT = "multi_press_timeout";
 
         /**
+         * Whether the user specifies a minimum ui timeout to override minimum ui timeout of
+         * accessibility service
+         *
+         * Type: int (0 for false, 1 for true)
+         * @hide
+         */
+        public static final String ACCESSIBILITY_MINIMUM_UI_TIMEOUT_ENABLED =
+                "accessibility_minimum_ui_timeout_enabled";
+
+        /**
+         * Setting that specifies ui minimum timeout in milliseconds.
+         *
+         * @see #ACCESSIBILITY_MINIMUM_UI_TIMEOUT_ENABLED
+         * @hide
+         */
+        public static final String ACCESSIBILITY_MINIMUM_UI_TIMEOUT_MS =
+                "accessibility_minimum_ui_timeout_ms";
+
+        /**
          * List of the enabled print services.
          *
          * N and beyond uses {@link #DISABLED_PRINT_SERVICES}. But this might be used in an upgrade
@@ -8195,6 +8214,8 @@
             ZEN_SETTINGS_SUGGESTION_VIEWED,
             CHARGING_SOUNDS_ENABLED,
             CHARGING_VIBRATION_ENABLED,
+            ACCESSIBILITY_MINIMUM_UI_TIMEOUT_ENABLED,
+            ACCESSIBILITY_MINIMUM_UI_TIMEOUT_MS,
         };
 
         /**
@@ -8349,6 +8370,8 @@
             VALIDATORS.put(ZEN_SETTINGS_SUGGESTION_VIEWED, BOOLEAN_VALIDATOR);
             VALIDATORS.put(CHARGING_SOUNDS_ENABLED, BOOLEAN_VALIDATOR);
             VALIDATORS.put(CHARGING_VIBRATION_ENABLED, BOOLEAN_VALIDATOR);
+            VALIDATORS.put(ACCESSIBILITY_MINIMUM_UI_TIMEOUT_ENABLED, BOOLEAN_VALIDATOR);
+            VALIDATORS.put(ACCESSIBILITY_MINIMUM_UI_TIMEOUT_MS, NON_NEGATIVE_INTEGER_VALIDATOR);
         }
 
         /**
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index b5ade2a..0476cf8 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -39,7 +39,6 @@
     private static final Map<String, String> DEFAULT_FLAGS;
     static {
         DEFAULT_FLAGS = new HashMap<>();
-        DEFAULT_FLAGS.put("settings_battery_display_app_list", "false");
         DEFAULT_FLAGS.put("settings_bluetooth_while_driving", "false");
         DEFAULT_FLAGS.put("settings_audio_switcher", "true");
         DEFAULT_FLAGS.put("settings_systemui_theme", "true");
diff --git a/core/java/android/util/proto/ProtoInputStream.java b/core/java/android/util/proto/ProtoInputStream.java
new file mode 100644
index 0000000..209451b
--- /dev/null
+++ b/core/java/android/util/proto/ProtoInputStream.java
@@ -0,0 +1,978 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util.proto;
+
+import android.annotation.TestApi;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+
+/**
+ * Class to read to a protobuf stream.
+ *
+ * Each read method takes an ID code from the protoc generated classes
+ * and return a value of the field. To read a nested object, call #start
+ * and then #end when you are done.
+ *
+ * The ID codes have type information embedded into them, so if you call
+ * the incorrect function you will get an IllegalArgumentException.
+ *
+ * nextField will return the field number of the next field, which can be
+ * matched to the protoc generated ID code and used to determine how to
+ * read the next field.
+ *
+ * It is STRONGLY RECOMMENDED to read from the ProtoInputStream with a switch
+ * statement wrapped in a while loop. Additionally, it is worth logging or
+ * storing unexpected fields or ones that do not match the expected wire type
+ *
+ * ex:
+ * void parseFromProto(ProtoInputStream stream) {
+ *     while(stream.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+ *         try {
+ *             switch (stream.getFieldNumber()) {
+ *                 case (int) DummyProto.NAME:
+ *                     mName = stream.readString(DummyProto.NAME);
+ *                     break;
+ *                 case (int) DummyProto.VALUE:
+ *                     mValue = stream.readInt(DummyProto.VALUE);
+ *                     break;
+ *                 default:
+ *                     LOG(TAG, "Unhandled field in proto!\n"
+ *                              + ProtoUtils.currentFieldToString(stream));
+ *             }
+ *         } catch (WireTypeMismatchException wtme) {
+ *             LOG(TAG, "Wire Type mismatch in proto!\n" + ProtoUtils.currentFieldToString(stream));
+ *         }
+ *     }
+ * }
+ *
+ * @hide
+ */
+@TestApi
+public final class ProtoInputStream extends ProtoStream {
+
+    public static final int NO_MORE_FIELDS = -1;
+
+    /**
+     * Our stream.  If there is one.
+     */
+    private InputStream mStream;
+
+    /**
+     * The field number of the current field. Will be equal to NO_MORE_FIELDS if end of message is
+     * reached
+     */
+    private int mFieldNumber;
+
+    /**
+     * The wire type of the current field
+     */
+    private int mWireType;
+
+    private static final byte STATE_STARTED_FIELD_READ = 1 << 0;
+    private static final byte STATE_READING_PACKED = 1 << 1;
+    private static final byte STATE_FIELD_MISS = 2 << 1;
+
+    /**
+     * Tracks some boolean states for the proto input stream
+     * bit 0: Started Field Read, true - tag has been read, ready to read field data.
+     * false - field data has been read, reading to start next field.
+     * bit 1: Reading Packed Field, true - currently reading values from a packed field
+     * false - not reading from packed field.
+     */
+    private byte mState = 0;
+
+    /**
+     * Keeps track of the currently read nested Objects, for end object sanity checking and debug
+     */
+    private ArrayList<Long> mExpectedObjectTokenStack = null;
+
+    /**
+     * Current nesting depth of start calls.
+     */
+    private int mDepth = -1;
+
+    /**
+     * Buffer for the to be read data. If mStream is not null, it will be constantly refilled from
+     * the stream.
+     */
+    private byte[] mBuffer;
+
+    private static final int DEFAULT_BUFFER_SIZE = 8192;
+
+    /**
+     * Size of the buffer if reading from a stream.
+     */
+    private final int mBufferSize;
+
+    /**
+     * The number of bytes that have been skipped or dropped from the buffer.
+     */
+    private int mDiscardedBytes = 0;
+
+    /**
+     * Current offset in the buffer
+     * mOffset + mDiscardedBytes = current offset in proto binary
+     */
+    private int mOffset = 0;
+
+    /**
+     * Note the offset of the last byte in the buffer. Usually will equal the size of the buffer.
+     * mEnd + mDiscardedBytes = the last known byte offset + 1
+     */
+    private int mEnd = 0;
+
+    /**
+     * Packed repeated fields are not read in one go. mPackedEnd keeps track of where the packed
+     * field ends in the proto binary if current field is packed.
+     */
+    private int mPackedEnd = 0;
+
+    /**
+     * Construct a ProtoInputStream on top of an InputStream to read a proto. Also specify the
+     * number of bytes the ProtoInputStream will buffer from the input stream
+     *
+     * @param stream from which the proto is read
+     */
+    public ProtoInputStream(InputStream stream, int bufferSize) {
+        mStream = stream;
+        if (bufferSize > 0) {
+            mBufferSize = bufferSize;
+        } else {
+            mBufferSize = DEFAULT_BUFFER_SIZE;
+        }
+        mBuffer = new byte[mBufferSize];
+    }
+
+    /**
+     * Construct a ProtoInputStream on top of an InputStream to read a proto
+     *
+     * @param stream from which the proto is read
+     */
+    public ProtoInputStream(InputStream stream) {
+        this(stream, DEFAULT_BUFFER_SIZE);
+    }
+
+    /**
+     * Construct a ProtoInputStream to read a proto directly from a byte array
+     *
+     * @param buffer - the byte array to be parsed
+     */
+    public ProtoInputStream(byte[] buffer) {
+        mBufferSize = buffer.length;
+        mEnd = buffer.length;
+        mBuffer = buffer;
+        mStream = null;
+    }
+
+    /**
+     * Get the field number of the current field.
+     */
+    public int getFieldNumber() {
+        return mFieldNumber;
+    }
+
+    /**
+     * Get the wire type of the current field.
+     *
+     * @return an int that matches one of the ProtoStream WIRE_TYPE_ constants
+     */
+    public int getWireType() {
+        if ((mState & STATE_READING_PACKED) == STATE_READING_PACKED) {
+            // mWireType got overwritten when STATE_READING_PACKED was set. Send length delimited
+            // constant instead
+            return WIRE_TYPE_LENGTH_DELIMITED;
+        }
+        return mWireType;
+    }
+
+    /**
+     * Get the current offset in the proto binary.
+     */
+    public int getOffset() {
+        return mOffset + mDiscardedBytes;
+    }
+
+    /**
+     * Reads the tag of the next field from the stream. If previous field value was not read, its
+     * data will be skipped over.
+     *
+     * @return the field number of the next field
+     * @throws IOException if an I/O error occurs
+     */
+    public int nextField() throws IOException {
+
+        if ((mState & STATE_FIELD_MISS) == STATE_FIELD_MISS) {
+            // Data from the last nextField was not used, reuse the info
+            mState &= ~STATE_FIELD_MISS;
+            return mFieldNumber;
+        }
+        if ((mState & STATE_STARTED_FIELD_READ) == STATE_STARTED_FIELD_READ) {
+            // Field data was not read, skip to the next field
+            skip();
+            mState &= ~STATE_STARTED_FIELD_READ;
+        }
+        if ((mState & STATE_READING_PACKED) == STATE_READING_PACKED) {
+            if (getOffset() < mPackedEnd) {
+                // In the middle of a packed field, return the same tag until last packed value
+                // has been read
+                mState |= STATE_STARTED_FIELD_READ;
+                return mFieldNumber;
+            } else if (getOffset() == mPackedEnd) {
+                // Reached the end of the packed field
+                mState &= ~STATE_READING_PACKED;
+            } else {
+                throw new ProtoParseException(
+                        "Unexpectedly reached end of packed field at offset 0x"
+                                + Integer.toHexString(mPackedEnd)
+                                + dumpDebugData());
+            }
+        }
+
+        if ((mDepth >= 0) && (getOffset() == getOffsetFromToken(
+                mExpectedObjectTokenStack.get(mDepth)))) {
+            // reached end of a embedded message
+            mFieldNumber = NO_MORE_FIELDS;
+        } else {
+            readTag();
+        }
+        return mFieldNumber;
+    }
+
+    /**
+     * Attempt to guess the next field. If there is a match, the field data will be ready to read.
+     * If there is no match, nextField will need to be called to get the field number
+     *
+     * @return true if fieldId matches the next field, false if not
+     */
+    public boolean isNextField(long fieldId) throws IOException {
+        if (nextField() == (int) fieldId) {
+            return true;
+        }
+        // Note to reuse the info from the nextField call in the next call.
+        mState |= STATE_FIELD_MISS;
+        return false;
+    }
+
+    /**
+     * Read a single double.
+     * Will throw if the current wire type is not fixed64
+     *
+     * @param fieldId - must match the current field number and field type
+     */
+    public double readDouble(long fieldId) throws IOException {
+        assertFreshData();
+        assertFieldNumber(fieldId);
+        checkPacked(fieldId);
+
+        double value;
+        switch ((int) ((fieldId & FIELD_TYPE_MASK)
+                >>> FIELD_TYPE_SHIFT)) {
+            case (int) (FIELD_TYPE_DOUBLE >>> FIELD_TYPE_SHIFT):
+                assertWireType(WIRE_TYPE_FIXED64);
+                value = Double.longBitsToDouble(readFixed64());
+                break;
+            default:
+                throw new IllegalArgumentException(
+                        "Requested field id (" + getFieldIdString(fieldId)
+                                + ") cannot be read as a double"
+                                + dumpDebugData());
+        }
+        // Successfully read the field
+        mState &= ~STATE_STARTED_FIELD_READ;
+        return value;
+    }
+
+    /**
+     * Read a single float.
+     * Will throw if the current wire type is not fixed32
+     *
+     * @param fieldId - must match the current field number and field type
+     */
+    public float readFloat(long fieldId) throws IOException {
+        assertFreshData();
+        assertFieldNumber(fieldId);
+        checkPacked(fieldId);
+
+        float value;
+        switch ((int) ((fieldId & FIELD_TYPE_MASK)
+                >>> FIELD_TYPE_SHIFT)) {
+            case (int) (FIELD_TYPE_FLOAT >>> FIELD_TYPE_SHIFT):
+                assertWireType(WIRE_TYPE_FIXED32);
+                value = Float.intBitsToFloat(readFixed32());
+                break;
+            default:
+                throw new IllegalArgumentException(
+                        "Requested field id (" + getFieldIdString(fieldId) + ") is not a float"
+                                + dumpDebugData());
+        }
+        // Successfully read the field
+        mState &= ~STATE_STARTED_FIELD_READ;
+        return value;
+    }
+
+    /**
+     * Read a single 32bit or varint proto type field as an int.
+     * Will throw if the current wire type is not varint or fixed32
+     *
+     * @param fieldId - must match the current field number and field type
+     */
+    public int readInt(long fieldId) throws IOException {
+        assertFreshData();
+        assertFieldNumber(fieldId);
+        checkPacked(fieldId);
+
+        int value;
+        switch ((int) ((fieldId & FIELD_TYPE_MASK)
+                >>> FIELD_TYPE_SHIFT)) {
+            case (int) (FIELD_TYPE_FIXED32 >>> FIELD_TYPE_SHIFT):
+            case (int) (FIELD_TYPE_SFIXED32 >>> FIELD_TYPE_SHIFT):
+                assertWireType(WIRE_TYPE_FIXED32);
+                value = readFixed32();
+                break;
+            case (int) (FIELD_TYPE_SINT32 >>> FIELD_TYPE_SHIFT):
+                assertWireType(WIRE_TYPE_VARINT);
+                value = decodeZigZag32((int) readVarint());
+                break;
+            case (int) (FIELD_TYPE_INT32 >>> FIELD_TYPE_SHIFT):
+            case (int) (FIELD_TYPE_UINT32 >>> FIELD_TYPE_SHIFT):
+            case (int) (FIELD_TYPE_ENUM >>> FIELD_TYPE_SHIFT):
+                assertWireType(WIRE_TYPE_VARINT);
+                value = (int) readVarint();
+                break;
+            default:
+                throw new IllegalArgumentException(
+                        "Requested field id (" + getFieldIdString(fieldId) + ") is not an int"
+                                + dumpDebugData());
+        }
+        // Successfully read the field
+        mState &= ~STATE_STARTED_FIELD_READ;
+        return value;
+    }
+
+    /**
+     * Read a single 64bit or varint proto type field as an long.
+     *
+     * @param fieldId - must match the current field number
+     */
+    public long readLong(long fieldId) throws IOException {
+        assertFreshData();
+        assertFieldNumber(fieldId);
+        checkPacked(fieldId);
+
+        long value;
+        switch ((int) ((fieldId & FIELD_TYPE_MASK)
+                >>> FIELD_TYPE_SHIFT)) {
+            case (int) (FIELD_TYPE_FIXED64 >>> FIELD_TYPE_SHIFT):
+            case (int) (FIELD_TYPE_SFIXED64 >>> FIELD_TYPE_SHIFT):
+                assertWireType(WIRE_TYPE_FIXED64);
+                value = readFixed64();
+                break;
+            case (int) (FIELD_TYPE_SINT64 >>> FIELD_TYPE_SHIFT):
+                assertWireType(WIRE_TYPE_VARINT);
+                value = decodeZigZag64(readVarint());
+                break;
+            case (int) (FIELD_TYPE_INT64 >>> FIELD_TYPE_SHIFT):
+            case (int) (FIELD_TYPE_UINT64 >>> FIELD_TYPE_SHIFT):
+                assertWireType(WIRE_TYPE_VARINT);
+                value = readVarint();
+                break;
+            default:
+                throw new IllegalArgumentException(
+                        "Requested field id (" + getFieldIdString(fieldId) + ") is not an long"
+                                + dumpDebugData());
+        }
+        // Successfully read the field
+        mState &= ~STATE_STARTED_FIELD_READ;
+        return value;
+    }
+
+    /**
+     * Read a single 32bit or varint proto type field as an boolean.
+     *
+     * @param fieldId - must match the current field number
+     */
+    public boolean readBoolean(long fieldId) throws IOException {
+        assertFreshData();
+        assertFieldNumber(fieldId);
+        checkPacked(fieldId);
+
+        boolean value;
+        switch ((int) ((fieldId & FIELD_TYPE_MASK)
+                >>> FIELD_TYPE_SHIFT)) {
+            case (int) (FIELD_TYPE_BOOL >>> FIELD_TYPE_SHIFT):
+                assertWireType(WIRE_TYPE_VARINT);
+                value = readVarint() != 0;
+                break;
+            default:
+                throw new IllegalArgumentException(
+                        "Requested field id (" + getFieldIdString(fieldId) + ") is not an boolean"
+                                + dumpDebugData());
+        }
+        // Successfully read the field
+        mState &= ~STATE_STARTED_FIELD_READ;
+        return value;
+    }
+
+    /**
+     * Read a string field
+     *
+     * @param fieldId - must match the current field number
+     */
+    public String readString(long fieldId) throws IOException {
+        assertFreshData();
+        assertFieldNumber(fieldId);
+
+        String value;
+        switch ((int) ((fieldId & FIELD_TYPE_MASK) >>> FIELD_TYPE_SHIFT)) {
+            case (int) (FIELD_TYPE_STRING >>> FIELD_TYPE_SHIFT):
+                assertWireType(WIRE_TYPE_LENGTH_DELIMITED);
+                int len = (int) readVarint();
+                value = readRawString(len);
+                break;
+            default:
+                throw new IllegalArgumentException(
+                        "Requested field id(" + getFieldIdString(fieldId)
+                                + ") is not an string"
+                                + dumpDebugData());
+        }
+        // Successfully read the field
+        mState &= ~STATE_STARTED_FIELD_READ;
+        return value;
+    }
+
+    /**
+     * Read a bytes field
+     *
+     * @param fieldId - must match the current field number
+     */
+    public byte[] readBytes(long fieldId) throws IOException {
+        assertFreshData();
+        assertFieldNumber(fieldId);
+
+        byte[] value;
+        switch ((int) ((fieldId & FIELD_TYPE_MASK) >>> FIELD_TYPE_SHIFT)) {
+            case (int) (FIELD_TYPE_MESSAGE >>> FIELD_TYPE_SHIFT):
+            case (int) (FIELD_TYPE_BYTES >>> FIELD_TYPE_SHIFT):
+                assertWireType(WIRE_TYPE_LENGTH_DELIMITED);
+                int len = (int) readVarint();
+                value = readRawBytes(len);
+                break;
+            default:
+                throw new IllegalArgumentException(
+                        "Requested field type (" + getFieldIdString(fieldId)
+                                + ") cannot be read as raw bytes"
+                                + dumpDebugData());
+        }
+        // Successfully read the field
+        mState &= ~STATE_STARTED_FIELD_READ;
+        return value;
+    }
+
+    /**
+     * Start the read of an embedded Object
+     *
+     * @param fieldId - must match the current field number
+     * @return a token. The token must be handed back when finished reading embedded Object
+     */
+    public long start(long fieldId) throws IOException {
+        assertFreshData();
+        assertFieldNumber(fieldId);
+        assertWireType(WIRE_TYPE_LENGTH_DELIMITED);
+
+        int messageSize = (int) readVarint();
+
+        if (mExpectedObjectTokenStack == null) {
+            mExpectedObjectTokenStack = new ArrayList<>();
+        }
+        if (++mDepth == mExpectedObjectTokenStack.size()) {
+            // Create a token to keep track of nested Object and extend the object stack
+            mExpectedObjectTokenStack.add(makeToken(0,
+                    (fieldId & FIELD_COUNT_REPEATED) == FIELD_COUNT_REPEATED, mDepth,
+                    (int) fieldId, getOffset() + messageSize));
+
+        } else {
+            // Create a token to keep track of nested Object
+            mExpectedObjectTokenStack.set(mDepth, makeToken(0,
+                    (fieldId & FIELD_COUNT_REPEATED) == FIELD_COUNT_REPEATED, mDepth,
+                    (int) fieldId, getOffset() + messageSize));
+        }
+
+        // Sanity check
+        if (mDepth > 0
+                && getOffsetFromToken(mExpectedObjectTokenStack.get(mDepth))
+                > getOffsetFromToken(mExpectedObjectTokenStack.get(mDepth - 1))) {
+            throw new ProtoParseException("Embedded Object ("
+                    + token2String(mExpectedObjectTokenStack.get(mDepth))
+                    + ") ends after of parent Objects's ("
+                    + token2String(mExpectedObjectTokenStack.get(mDepth - 1))
+                    + ") end"
+                    + dumpDebugData());
+        }
+        mState &= ~STATE_STARTED_FIELD_READ;
+        return mExpectedObjectTokenStack.get(mDepth);
+    }
+
+    /**
+     * Note the end of a nested object. Must be called to continue streaming the rest of the proto.
+     * end can be called mid object parse. The offset will be moved to the next field outside the
+     * object.
+     *
+     * @param token - token
+     */
+    public void end(long token) {
+        // Sanity check to make sure user is keeping track of their embedded messages
+        if (mExpectedObjectTokenStack.get(mDepth) != token) {
+            throw new ProtoParseException(
+                    "end token " + token + " does not match current message token "
+                            + mExpectedObjectTokenStack.get(mDepth)
+                            + dumpDebugData());
+        }
+        if (getOffsetFromToken(mExpectedObjectTokenStack.get(mDepth)) > getOffset()) {
+            // Did not read all of the message, skip to the end
+            incOffset(getOffsetFromToken(mExpectedObjectTokenStack.get(mDepth)) - getOffset());
+        }
+        mDepth--;
+        mState &= ~STATE_STARTED_FIELD_READ;
+    }
+
+    /**
+     * Read the tag at the start of the next field and collect field number and wire type.
+     * Will set mFieldNumber to NO_MORE_FIELDS if end of buffer/stream reached.
+     */
+    private void readTag() throws IOException {
+        fillBuffer();
+        if (mOffset >= mEnd) {
+            // reached end of the stream
+            mFieldNumber = NO_MORE_FIELDS;
+            return;
+        }
+        int tag = (int) readVarint();
+        mFieldNumber = tag >>> FIELD_ID_SHIFT;
+        mWireType = tag & WIRE_TYPE_MASK;
+        mState |= STATE_STARTED_FIELD_READ;
+    }
+
+    /**
+     * Decode a 32 bit ZigZag encoded signed int.
+     *
+     * @param n - int to decode
+     * @return the decoded signed int
+     */
+    public int decodeZigZag32(final int n) {
+        return (n >>> 1) ^ -(n & 1);
+    }
+
+    /**
+     * Decode a 64 bit ZigZag encoded signed long.
+     *
+     * @param n - long to decode
+     * @return the decoded signed long
+     */
+    public long decodeZigZag64(final long n) {
+        return (n >>> 1) ^ -(n & 1);
+    }
+
+    /**
+     * Read a varint from the buffer
+     *
+     * @return the varint as a long
+     */
+    private long readVarint() throws IOException {
+        long value = 0;
+        int shift = 0;
+        while (true) {
+            fillBuffer();
+            // Limit how much bookkeeping is done by checking how far away the end of the buffer is
+            // and directly accessing buffer up until the end.
+            final int fragment = mEnd - mOffset;
+            for (int i = 0; i < fragment; i++) {
+                byte b = mBuffer[(mOffset + i)];
+                value |= (b & 0x7FL) << shift;
+                if ((b & 0x80) == 0) {
+                    incOffset(i + 1);
+                    return value;
+                }
+                shift += 7;
+                if (shift > 63) {
+                    throw new ProtoParseException(
+                            "Varint is too large at offset 0x"
+                                    + Integer.toHexString(getOffset() + i)
+                                    + dumpDebugData());
+                }
+            }
+            // Hit the end of the buffer, do some incrementing and checking, then continue
+            incOffset(fragment);
+        }
+    }
+
+    /**
+     * Read a fixed 32 bit int from the buffer
+     *
+     * @return the fixed32 as a int
+     */
+    private int readFixed32() throws IOException {
+        // check for fast path, which is likely with a reasonable buffer size
+        if (mOffset + 4 <= mEnd) {
+            // don't bother filling buffer since we know the end is plenty far away
+            incOffset(4);
+            return (mBuffer[mOffset - 4] & 0xFF)
+                    | ((mBuffer[mOffset - 3] & 0xFF) << 8)
+                    | ((mBuffer[mOffset - 2] & 0xFF) << 16)
+                    | ((mBuffer[mOffset - 1] & 0xFF) << 24);
+        }
+
+        // the Fixed32 crosses the edge of a chunk, read the Fixed32 in multiple fragments.
+        // There will be two fragment reads except when the chunk size is 2 or less.
+        int value = 0;
+        int shift = 0;
+        int bytesLeft = 4;
+        while (bytesLeft > 0) {
+            fillBuffer();
+            // Find the number of bytes available until the end of the chunk or Fixed32
+            int fragment = (mEnd - mOffset) < bytesLeft ? (mEnd - mOffset) : bytesLeft;
+            incOffset(fragment);
+            bytesLeft -= fragment;
+            while (fragment > 0) {
+                value |= ((mBuffer[mOffset - fragment] & 0xFF) << shift);
+                fragment--;
+                shift += 8;
+            }
+        }
+        return value;
+    }
+
+    /**
+     * Read a fixed 64 bit long from the buffer
+     *
+     * @return the fixed64 as a long
+     */
+    private long readFixed64() throws IOException {
+        // check for fast path, which is likely with a reasonable buffer size
+        if (mOffset + 8 <= mEnd) {
+            // don't bother filling buffer since we know the end is plenty far away
+            incOffset(8);
+            return (mBuffer[mOffset - 8] & 0xFFL)
+                    | ((mBuffer[mOffset - 7] & 0xFFL) << 8)
+                    | ((mBuffer[mOffset - 6] & 0xFFL) << 16)
+                    | ((mBuffer[mOffset - 5] & 0xFFL) << 24)
+                    | ((mBuffer[mOffset - 4] & 0xFFL) << 32)
+                    | ((mBuffer[mOffset - 3] & 0xFFL) << 40)
+                    | ((mBuffer[mOffset - 2] & 0xFFL) << 48)
+                    | ((mBuffer[mOffset - 1] & 0xFFL) << 56);
+        }
+
+        // the Fixed64 crosses the edge of a chunk, read the Fixed64 in multiple fragments.
+        // There will be two fragment reads except when the chunk size is 6 or less.
+        long value = 0;
+        int shift = 0;
+        int bytesLeft = 8;
+        while (bytesLeft > 0) {
+            fillBuffer();
+            // Find the number of bytes available until the end of the chunk or Fixed64
+            int fragment = (mEnd - mOffset) < bytesLeft ? (mEnd - mOffset) : bytesLeft;
+            incOffset(fragment);
+            bytesLeft -= fragment;
+            while (fragment > 0) {
+                value |= ((mBuffer[(mOffset - fragment)] & 0xFFL) << shift);
+                fragment--;
+                shift += 8;
+            }
+        }
+        return value;
+    }
+
+    /**
+     * Read raw bytes from the buffer
+     *
+     * @param n - number of bytes to read
+     * @return a byte array with raw bytes
+     */
+    private byte[] readRawBytes(int n) throws IOException {
+        byte[] buffer = new byte[n];
+        int pos = 0;
+        while (mOffset + n - pos > mEnd) {
+            int fragment = mEnd - mOffset;
+            if (fragment > 0) {
+                System.arraycopy(mBuffer, mOffset, buffer, pos, fragment);
+                incOffset(fragment);
+                pos += fragment;
+            }
+            fillBuffer();
+            if (mOffset >= mEnd) {
+                throw new ProtoParseException(
+                        "Unexpectedly reached end of the InputStream at offset 0x"
+                                + Integer.toHexString(mEnd)
+                                + dumpDebugData());
+            }
+        }
+        System.arraycopy(mBuffer, mOffset, buffer, pos, n - pos);
+        incOffset(n - pos);
+        return buffer;
+    }
+
+    /**
+     * Read raw string from the buffer
+     *
+     * @param n - number of bytes to read
+     * @return a string
+     */
+    private String readRawString(int n) throws IOException {
+        fillBuffer();
+        if (mOffset + n <= mEnd) {
+            // fast path read. String is well within the current buffer
+            String value = StringFactory.newStringFromBytes(mBuffer, mOffset, n,
+                    StandardCharsets.UTF_8);
+            incOffset(n);
+            return value;
+        } else if (n <= mBufferSize) {
+            // String extends past buffer, but can be encapsulated in a buffer. Copy the first chunk
+            // of the string to the start of the buffer and then fill the rest of the buffer from
+            // the stream.
+            final int stringHead = mEnd - mOffset;
+            System.arraycopy(mBuffer, mOffset, mBuffer, 0, stringHead);
+            mEnd = stringHead + mStream.read(mBuffer, stringHead, n - stringHead);
+
+            mDiscardedBytes += mOffset;
+            mOffset = 0;
+
+            String value = StringFactory.newStringFromBytes(mBuffer, mOffset, n,
+                    StandardCharsets.UTF_8);
+            incOffset(n);
+            return value;
+        }
+        // Otherwise, the string is too large to use the buffer. Create the string from a
+        // separate byte array.
+        return StringFactory.newStringFromBytes(readRawBytes(n), 0, n, StandardCharsets.UTF_8);
+    }
+
+    /**
+     * Fill the buffer with a chunk from the stream if need be.
+     * Will skip chunks until mOffset is reached
+     */
+    private void fillBuffer() throws IOException {
+        if (mOffset >= mEnd && mStream != null) {
+            mOffset -= mEnd;
+            mDiscardedBytes += mEnd;
+            if (mOffset >= mBufferSize) {
+                int skipped = (int) mStream.skip((mOffset / mBufferSize) * mBufferSize);
+                mDiscardedBytes += skipped;
+                mOffset -= skipped;
+            }
+            mEnd = mStream.read(mBuffer);
+        }
+    }
+
+    /**
+     * Skips the rest of current field and moves to the start of the next field. This should only be
+     * called while state is STATE_STARTED_FIELD_READ
+     */
+    public void skip() throws IOException {
+        if ((mState & STATE_READING_PACKED) == STATE_READING_PACKED) {
+            incOffset(mPackedEnd - getOffset());
+        } else {
+            switch (mWireType) {
+                case WIRE_TYPE_VARINT:
+                    byte b;
+                    do {
+                        fillBuffer();
+                        b = mBuffer[mOffset];
+                        incOffset(1);
+                    } while ((b & 0x80) != 0);
+                    break;
+                case WIRE_TYPE_FIXED64:
+                    incOffset(8);
+                    break;
+                case WIRE_TYPE_LENGTH_DELIMITED:
+                    fillBuffer();
+                    int length = (int) readVarint();
+                    incOffset(length);
+                    break;
+                /*
+            case WIRE_TYPE_START_GROUP:
+                // Not implemented
+                break;
+            case WIRE_TYPE_END_GROUP:
+                // Not implemented
+                break;
+                */
+                case WIRE_TYPE_FIXED32:
+                    incOffset(4);
+                    break;
+                default:
+                    throw new ProtoParseException(
+                            "Unexpected wire type: " + mWireType + " at offset 0x"
+                                    + Integer.toHexString(mOffset)
+                                    + dumpDebugData());
+            }
+        }
+        mState &= ~STATE_STARTED_FIELD_READ;
+    }
+
+    /**
+     * Increment the offset and handle all the relevant bookkeeping
+     * Refilling the buffer when its end is reached will be handled elsewhere (ideally just before
+     * a read, to avoid unnecessary reads from stream)
+     *
+     * @param n - number of bytes to increment
+     */
+    private void incOffset(int n) {
+        mOffset += n;
+
+        if (mDepth >= 0 && getOffset() > getOffsetFromToken(
+                mExpectedObjectTokenStack.get(mDepth))) {
+            throw new ProtoParseException("Unexpectedly reached end of embedded object.  "
+                    + token2String(mExpectedObjectTokenStack.get(mDepth))
+                    + dumpDebugData());
+        }
+    }
+
+    /**
+     * Check the current wire type to determine if current numeric field is packed. If it is packed,
+     * set up to deal with the field
+     * This should only be called for primitive numeric field types.
+     *
+     * @param fieldId - used to determine what the packed wire type is.
+     */
+    private void checkPacked(long fieldId) throws IOException {
+        if (mWireType == WIRE_TYPE_LENGTH_DELIMITED) {
+            // Primitive Field is length delimited, must be a packed field.
+            final int length = (int) readVarint();
+            mPackedEnd = getOffset() + length;
+            mState |= STATE_READING_PACKED;
+
+            // Fake the wire type, based on the field type
+            switch ((int) ((fieldId & FIELD_TYPE_MASK)
+                    >>> FIELD_TYPE_SHIFT)) {
+                case (int) (FIELD_TYPE_FLOAT >>> FIELD_TYPE_SHIFT):
+                case (int) (FIELD_TYPE_FIXED32 >>> FIELD_TYPE_SHIFT):
+                case (int) (FIELD_TYPE_SFIXED32 >>> FIELD_TYPE_SHIFT):
+                    if (length % 4 != 0) {
+                        throw new IllegalArgumentException(
+                                "Requested field id (" + getFieldIdString(fieldId)
+                                        + ") packed length " + length
+                                        + " is not aligned for fixed32"
+                                        + dumpDebugData());
+                    }
+                    mWireType = WIRE_TYPE_FIXED32;
+                    break;
+                case (int) (FIELD_TYPE_DOUBLE >>> FIELD_TYPE_SHIFT):
+                case (int) (FIELD_TYPE_FIXED64 >>> FIELD_TYPE_SHIFT):
+                case (int) (FIELD_TYPE_SFIXED64 >>> FIELD_TYPE_SHIFT):
+                    if (length % 8 != 0) {
+                        throw new IllegalArgumentException(
+                                "Requested field id (" + getFieldIdString(fieldId)
+                                        + ") packed length " + length
+                                        + " is not aligned for fixed64"
+                                        + dumpDebugData());
+                    }
+                    mWireType = WIRE_TYPE_FIXED64;
+                    break;
+                case (int) (FIELD_TYPE_SINT32 >>> FIELD_TYPE_SHIFT):
+                case (int) (FIELD_TYPE_INT32 >>> FIELD_TYPE_SHIFT):
+                case (int) (FIELD_TYPE_UINT32 >>> FIELD_TYPE_SHIFT):
+                case (int) (FIELD_TYPE_SINT64 >>> FIELD_TYPE_SHIFT):
+                case (int) (FIELD_TYPE_INT64 >>> FIELD_TYPE_SHIFT):
+                case (int) (FIELD_TYPE_UINT64 >>> FIELD_TYPE_SHIFT):
+                case (int) (FIELD_TYPE_ENUM >>> FIELD_TYPE_SHIFT):
+                case (int) (FIELD_TYPE_BOOL >>> FIELD_TYPE_SHIFT):
+                    mWireType = WIRE_TYPE_VARINT;
+                    break;
+                default:
+                    throw new IllegalArgumentException(
+                            "Requested field id (" + getFieldIdString(fieldId)
+                                    + ") is not a packable field"
+                                    + dumpDebugData());
+            }
+        }
+    }
+
+
+    /**
+     * Check a field id constant against current field number
+     *
+     * @param fieldId - throws if fieldId does not match mFieldNumber
+     */
+    private void assertFieldNumber(long fieldId) {
+        if ((int) fieldId != mFieldNumber) {
+            throw new IllegalArgumentException("Requested field id (" + getFieldIdString(fieldId)
+                    + ") does not match current field number (0x" + Integer.toHexString(
+                    mFieldNumber)
+                    + ") at offset 0x" + Integer.toHexString(getOffset())
+                    + dumpDebugData());
+        }
+    }
+
+
+    /**
+     * Check a wire type against current wire type.
+     *
+     * @param wireType - throws if wireType does not match mWireType.
+     */
+    private void assertWireType(int wireType) {
+        if (wireType != mWireType) {
+            throw new WireTypeMismatchException(
+                    "Current wire type " + getWireTypeString(mWireType)
+                            + " does not match expected wire type " + getWireTypeString(wireType)
+                            + " at offset 0x" + Integer.toHexString(getOffset())
+                            + dumpDebugData());
+        }
+    }
+
+    /**
+     * Check if there is data ready to be read.
+     */
+    private void assertFreshData() {
+        if ((mState & STATE_STARTED_FIELD_READ) != STATE_STARTED_FIELD_READ) {
+            throw new ProtoParseException(
+                    "Attempting to read already read field at offset 0x" + Integer.toHexString(
+                            getOffset()) + dumpDebugData());
+        }
+    }
+
+    /**
+     * Dump debugging data about the buffer.
+     */
+    public String dumpDebugData() {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append("\nmFieldNumber : 0x" + Integer.toHexString(mFieldNumber));
+        sb.append("\nmWireType : 0x" + Integer.toHexString(mWireType));
+        sb.append("\nmState : 0x" + Integer.toHexString(mState));
+        sb.append("\nmDiscardedBytes : 0x" + Integer.toHexString(mDiscardedBytes));
+        sb.append("\nmOffset : 0x" + Integer.toHexString(mOffset));
+        sb.append("\nmExpectedObjectTokenStack : ");
+        if (mExpectedObjectTokenStack == null) {
+            sb.append("null");
+        } else {
+            sb.append(mExpectedObjectTokenStack);
+        }
+        sb.append("\nmDepth : 0x" + Integer.toHexString(mDepth));
+        sb.append("\nmBuffer : ");
+        if (mBuffer == null) {
+            sb.append("null");
+        } else {
+            sb.append(mBuffer);
+        }
+        sb.append("\nmBufferSize : 0x" + Integer.toHexString(mBufferSize));
+        sb.append("\nmEnd : 0x" + Integer.toHexString(mEnd));
+
+        return sb.toString();
+    }
+}
diff --git a/core/java/android/util/proto/ProtoOutputStream.java b/core/java/android/util/proto/ProtoOutputStream.java
index a94806a..a1ee61c 100644
--- a/core/java/android/util/proto/ProtoOutputStream.java
+++ b/core/java/android/util/proto/ProtoOutputStream.java
@@ -100,88 +100,12 @@
  * errors if they are not matched.
  */
 @TestApi
-public final class ProtoOutputStream {
+public final class ProtoOutputStream extends ProtoStream {
+    /**
+     * @hide
+     */
     public static final String TAG = "ProtoOutputStream";
 
-    public static final int FIELD_ID_SHIFT = 3;
-    public static final int WIRE_TYPE_MASK = (1<<FIELD_ID_SHIFT)-1;
-    public static final int FIELD_ID_MASK = ~WIRE_TYPE_MASK;
-
-    public static final int WIRE_TYPE_VARINT = 0;
-    public static final int WIRE_TYPE_FIXED64 = 1;
-    public static final int WIRE_TYPE_LENGTH_DELIMITED = 2;
-    public static final int WIRE_TYPE_START_GROUP = 3;
-    public static final int WIRE_TYPE_END_GROUP = 4;
-    public static final int WIRE_TYPE_FIXED32 = 5;
-
-    /**
-     * Position of the field type in a (long) fieldId.
-     */
-    public static final int FIELD_TYPE_SHIFT = 32;
-
-    /**
-     * Mask for the field types stored in a fieldId.  Leaves a whole
-     * byte for future expansion, even though there are currently only 17 types.
-     */
-    public static final long FIELD_TYPE_MASK = 0x0ffL << FIELD_TYPE_SHIFT;
-
-    public static final long FIELD_TYPE_UNKNOWN = 0;
-
-    /**
-     * The types are copied from external/protobuf/src/google/protobuf/descriptor.h directly,
-     * so no extra mapping needs to be maintained in this case.
-     */
-    public static final long FIELD_TYPE_DOUBLE = 1L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_FLOAT = 2L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_INT64 = 3L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_UINT64 = 4L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_INT32 = 5L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_FIXED64 = 6L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_FIXED32 = 7L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_BOOL = 8L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_STRING = 9L << FIELD_TYPE_SHIFT;
-//  public static final long FIELD_TYPE_GROUP = 10L << FIELD_TYPE_SHIFT; // Deprecated.
-    public static final long FIELD_TYPE_MESSAGE = 11L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_BYTES = 12L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_UINT32 = 13L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_ENUM = 14L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_SFIXED32 = 15L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_SFIXED64 = 16L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_SINT32 = 17L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_SINT64 = 18L << FIELD_TYPE_SHIFT;
-
-    private static final String[] FIELD_TYPE_NAMES = new String[] {
-        "Double",
-        "Float",
-        "Int64",
-        "UInt64",
-        "Int32",
-        "Fixed64",
-        "Fixed32",
-        "Bool",
-        "String",
-        "Group",  // This field is deprecated but reserved here for indexing.
-        "Message",
-        "Bytes",
-        "UInt32",
-        "Enum",
-        "SFixed32",
-        "SFixed64",
-        "SInt32",
-        "SInt64",
-    };
-
-    //
-    // FieldId flags for whether the field is single, repeated or packed.
-    //
-    public static final int FIELD_COUNT_SHIFT = 40;
-    public static final long FIELD_COUNT_MASK = 0x0fL << FIELD_COUNT_SHIFT;
-
-    public static final long FIELD_COUNT_UNKNOWN = 0;
-    public static final long FIELD_COUNT_SINGLE = 1L << FIELD_COUNT_SHIFT;
-    public static final long FIELD_COUNT_REPEATED = 2L << FIELD_COUNT_SHIFT;
-    public static final long FIELD_COUNT_PACKED = 5L << FIELD_COUNT_SHIFT;
-
     /**
      * Our buffer.
      */
@@ -1997,94 +1921,6 @@
         }
     }
 
-    //
-    // Child objects
-    //
-
-    /**
-     * Make a token.
-     *  Bits 61-63 - tag size (So we can go backwards later if the object had not data)
-     *                - 3 bits, max value 7, max value needed 5
-     *  Bit  60    - true if the object is repeated (lets us require endObject or endRepeatedObject)
-     *  Bits 59-51 - depth (For error checking)
-     *                - 9 bits, max value 512, when checking, value is masked (if we really
-     *                  are more than 512 levels deep)
-     *  Bits 32-50 - objectId (For error checking)
-     *                - 19 bits, max value 524,288. that's a lot of objects. IDs will wrap
-     *                  because of the overflow, and only the tokens are compared.
-     *  Bits  0-31 - offset of the first size field in the buffer.
-     */
-    // VisibleForTesting
-    public static long makeToken(int tagSize, boolean repeated, int depth, int objectId,
-            int sizePos) {
-        return ((0x07L & (long)tagSize) << 61)
-                | (repeated ? (1L << 60) : 0)
-                | (0x01ffL & (long)depth) << 51
-                | (0x07ffffL & (long)objectId) << 32
-                | (0x0ffffffffL & (long)sizePos);
-    }
-
-    /**
-     * Get the encoded tag size from the token.
-     */
-    public static int getTagSizeFromToken(long token) {
-        return (int)(0x7 & (token >> 61));
-    }
-
-    /**
-     * Get whether this is a call to startObject (false) or startRepeatedObject (true).
-     */
-    public static boolean getRepeatedFromToken(long token) {
-        return (0x1 & (token >> 60)) != 0;
-    }
-
-    /**
-     * Get the nesting depth of startObject calls from the token.
-     */
-    public static int getDepthFromToken(long token) {
-        return (int)(0x01ff & (token >> 51));
-    }
-
-    /**
-     * Get the object ID from the token. The object ID is a serial number for the
-     * startObject calls that have happened on this object.  The values are truncated
-     * to 9 bits, but that is sufficient for error checking.
-     */
-    public static int getObjectIdFromToken(long token) {
-        return (int)(0x07ffff & (token >> 32));
-    }
-
-    /**
-     * Get the location of the childRawSize (the first 32 bit size field) in this object.
-     */
-    public static int getSizePosFromToken(long token) {
-        return (int)token;
-    }
-
-    /**
-     * Convert the object ID to the ordinal value -- the n-th call to startObject.
-     * The object IDs start at -1 and count backwards, so that the value is unlikely
-     * to alias with an actual size field that had been written.
-     */
-    public static int convertObjectIdToOrdinal(int objectId) {
-        return (-1 & 0x07ffff) - objectId;
-    }
-
-    /**
-     * Return a debugging string of a token.
-     */
-    public static String token2String(long token) {
-        if (token == 0L) {
-            return "Token(0)";
-        } else {
-            return "Token(val=0x" + Long.toHexString(token)
-                    + " depth=" + getDepthFromToken(token)
-                    + " object=" + convertObjectIdToOrdinal(getObjectIdFromToken(token))
-                    + " tagSize=" + getTagSizeFromToken(token)
-                    + " sizePos=" + getSizePosFromToken(token)
-                    + ')';
-        }
-    }
 
     /**
      * Start a child object.
@@ -2175,7 +2011,7 @@
         // at which to write the size.
         final int depth = getDepthFromToken(token);
         final boolean expectedRepeated = getRepeatedFromToken(token);
-        final int sizePos = getSizePosFromToken(token);
+        final int sizePos = getOffsetFromToken(token);
         final int childRawSize = mBuffer.getWritePos() - sizePos - 8;
 
         if (repeated != expectedRepeated) {
@@ -2346,56 +2182,6 @@
     }
 
     /**
-     * Get the developer-usable name of a field type.
-     */
-    private static String getFieldTypeString(long fieldType) {
-        int index = ((int)((fieldType & FIELD_TYPE_MASK) >>> FIELD_TYPE_SHIFT)) - 1;
-        if (index >= 0 && index < FIELD_TYPE_NAMES.length) {
-            return FIELD_TYPE_NAMES[index];
-        } else {
-            return null;
-        }
-    }
-
-    /**
-     * Get the developer-usable name of a field count.
-     */
-    private static String getFieldCountString(long fieldCount) {
-        if (fieldCount == FIELD_COUNT_SINGLE) {
-            return "";
-        } else if (fieldCount == FIELD_COUNT_REPEATED) {
-            return "Repeated";
-        } else if (fieldCount == FIELD_COUNT_PACKED) {
-            return "Packed";
-        } else {
-            return null;
-        }
-    }
-
-    /**
-     * Get a debug string for a fieldId.
-     */
-    private String getFieldIdString(long fieldId) {
-        final long fieldCount = fieldId & FIELD_COUNT_MASK;
-        String countString = getFieldCountString(fieldCount);
-        if (countString == null) {
-            countString = "fieldCount=" + fieldCount;
-        }
-        if (countString.length() > 0) {
-            countString += " ";
-        }
-
-        final long fieldType = fieldId & FIELD_TYPE_MASK;
-        String typeString = getFieldTypeString(fieldType);
-        if (typeString == null) {
-            typeString = "fieldType=" + fieldType;
-        }
-
-        return countString + typeString + " tag=" + ((int) fieldId)
-                + " fieldId=0x" + Long.toHexString(fieldId);
-    }
-
-    /**
      * Return how many bytes an encoded field tag will require.
      */
     private static int getTagSize(int id) {
diff --git a/core/java/android/util/proto/ProtoStream.java b/core/java/android/util/proto/ProtoStream.java
new file mode 100644
index 0000000..9e2e95a
--- /dev/null
+++ b/core/java/android/util/proto/ProtoStream.java
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util.proto;
+
+import android.annotation.TestApi;
+
+/**
+ * Abstract base class for both protobuf streams.
+ *
+ * Contains a set of useful constants and methods used by both
+ * ProtoOutputStream and ProtoInputStream
+ *
+ * @hide
+ */
+@TestApi
+public abstract class ProtoStream {
+
+    public static final int FIELD_ID_SHIFT = 3;
+    public static final int WIRE_TYPE_MASK = (1 << FIELD_ID_SHIFT) - 1;
+    public static final int FIELD_ID_MASK = ~WIRE_TYPE_MASK;
+
+    public static final int WIRE_TYPE_VARINT = 0;
+    public static final int WIRE_TYPE_FIXED64 = 1;
+    public static final int WIRE_TYPE_LENGTH_DELIMITED = 2;
+    public static final int WIRE_TYPE_START_GROUP = 3;
+    public static final int WIRE_TYPE_END_GROUP = 4;
+    public static final int WIRE_TYPE_FIXED32 = 5;
+
+    /**
+     * Position of the field type in a (long) fieldId.
+     */
+    public static final int FIELD_TYPE_SHIFT = 32;
+
+    /**
+     * Mask for the field types stored in a fieldId.  Leaves a whole
+     * byte for future expansion, even though there are currently only 17 types.
+     */
+    public static final long FIELD_TYPE_MASK = 0x0ffL << FIELD_TYPE_SHIFT;
+
+    public static final long FIELD_TYPE_UNKNOWN = 0;
+
+    /**
+     * The types are copied from external/protobuf/src/google/protobuf/descriptor.h directly,
+     * so no extra mapping needs to be maintained in this case.
+     */
+    public static final long FIELD_TYPE_DOUBLE = 1L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_FLOAT = 2L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_INT64 = 3L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_UINT64 = 4L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_INT32 = 5L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_FIXED64 = 6L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_FIXED32 = 7L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_BOOL = 8L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_STRING = 9L << FIELD_TYPE_SHIFT;
+    //  public static final long FIELD_TYPE_GROUP = 10L << FIELD_TYPE_SHIFT; // Deprecated.
+    public static final long FIELD_TYPE_MESSAGE = 11L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_BYTES = 12L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_UINT32 = 13L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_ENUM = 14L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_SFIXED32 = 15L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_SFIXED64 = 16L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_SINT32 = 17L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_SINT64 = 18L << FIELD_TYPE_SHIFT;
+
+    protected static final String[] FIELD_TYPE_NAMES = new String[]{
+            "Double",
+            "Float",
+            "Int64",
+            "UInt64",
+            "Int32",
+            "Fixed64",
+            "Fixed32",
+            "Bool",
+            "String",
+            "Group",  // This field is deprecated but reserved here for indexing.
+            "Message",
+            "Bytes",
+            "UInt32",
+            "Enum",
+            "SFixed32",
+            "SFixed64",
+            "SInt32",
+            "SInt64",
+    };
+
+    //
+    // FieldId flags for whether the field is single, repeated or packed.
+    //
+    public static final int FIELD_COUNT_SHIFT = 40;
+    public static final long FIELD_COUNT_MASK = 0x0fL << FIELD_COUNT_SHIFT;
+
+    public static final long FIELD_COUNT_UNKNOWN = 0;
+    public static final long FIELD_COUNT_SINGLE = 1L << FIELD_COUNT_SHIFT;
+    public static final long FIELD_COUNT_REPEATED = 2L << FIELD_COUNT_SHIFT;
+    public static final long FIELD_COUNT_PACKED = 5L << FIELD_COUNT_SHIFT;
+
+
+    /**
+     * Get the developer-usable name of a field type.
+     */
+    public static String getFieldTypeString(long fieldType) {
+        int index = ((int) ((fieldType & FIELD_TYPE_MASK) >>> FIELD_TYPE_SHIFT)) - 1;
+        if (index >= 0 && index < FIELD_TYPE_NAMES.length) {
+            return FIELD_TYPE_NAMES[index];
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Get the developer-usable name of a field count.
+     */
+    public static String getFieldCountString(long fieldCount) {
+        if (fieldCount == FIELD_COUNT_SINGLE) {
+            return "";
+        } else if (fieldCount == FIELD_COUNT_REPEATED) {
+            return "Repeated";
+        } else if (fieldCount == FIELD_COUNT_PACKED) {
+            return "Packed";
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Get the developer-usable name of a wire type.
+     */
+    public static String getWireTypeString(int wireType) {
+        switch (wireType) {
+            case WIRE_TYPE_VARINT:
+                return "Varint";
+            case WIRE_TYPE_FIXED64:
+                return "Fixed64";
+            case WIRE_TYPE_LENGTH_DELIMITED:
+                return "Length Delimited";
+            case WIRE_TYPE_START_GROUP:
+                return "Start Group";
+            case WIRE_TYPE_END_GROUP:
+                return "End Group";
+            case WIRE_TYPE_FIXED32:
+                return "Fixed32";
+            default:
+                return null;
+        }
+    }
+
+    /**
+     * Get a debug string for a fieldId.
+     */
+    public static String getFieldIdString(long fieldId) {
+        final long fieldCount = fieldId & FIELD_COUNT_MASK;
+        String countString = getFieldCountString(fieldCount);
+        if (countString == null) {
+            countString = "fieldCount=" + fieldCount;
+        }
+        if (countString.length() > 0) {
+            countString += " ";
+        }
+
+        final long fieldType = fieldId & FIELD_TYPE_MASK;
+        String typeString = getFieldTypeString(fieldType);
+        if (typeString == null) {
+            typeString = "fieldType=" + fieldType;
+        }
+
+        return countString + typeString + " tag=" + ((int) fieldId)
+                + " fieldId=0x" + Long.toHexString(fieldId);
+    }
+
+    /**
+     * Combine a fieldId (the field keys in the proto file) and the field flags.
+     * Mostly useful for testing because the generated code contains the fieldId
+     * constants.
+     */
+    public static long makeFieldId(int id, long fieldFlags) {
+        return fieldFlags | (((long) id) & 0x0ffffffffL);
+    }
+
+    //
+    // Child objects
+    //
+
+    /**
+     * Make a token.
+     * Bits 61-63 - tag size (So we can go backwards later if the object had not data)
+     *            - 3 bits, max value 7, max value needed 5
+     * Bit  60    - true if the object is repeated (lets us require endObject or endRepeatedObject)
+     * Bits 59-51 - depth (For error checking)
+     *            - 9 bits, max value 512, when checking, value is masked (if we really
+     *              are more than 512 levels deep)
+     * Bits 32-50 - objectId (For error checking)
+     *            - 19 bits, max value 524,288. that's a lot of objects. IDs will wrap
+     *              because of the overflow, and only the tokens are compared.
+     * Bits  0-31 - offset of interest for the object.
+     */
+    public static long makeToken(int tagSize, boolean repeated, int depth, int objectId,
+            int offset) {
+        return ((0x07L & (long) tagSize) << 61)
+                | (repeated ? (1L << 60) : 0)
+                | (0x01ffL & (long) depth) << 51
+                | (0x07ffffL & (long) objectId) << 32
+                | (0x0ffffffffL & (long) offset);
+    }
+
+    /**
+     * Get the encoded tag size from the token.
+     */
+    public static int getTagSizeFromToken(long token) {
+        return (int) (0x7 & (token >> 61));
+    }
+
+    /**
+     * Get whether this is a call to startObject (false) or startRepeatedObject (true).
+     */
+    public static boolean getRepeatedFromToken(long token) {
+        return (0x1 & (token >> 60)) != 0;
+    }
+
+    /**
+     * Get the nesting depth of startObject calls from the token.
+     */
+    public static int getDepthFromToken(long token) {
+        return (int) (0x01ff & (token >> 51));
+    }
+
+    /**
+     * Get the object ID from the token. The object ID is a serial number for the
+     * startObject calls that have happened on this object.  The values are truncated
+     * to 9 bits, but that is sufficient for error checking.
+     */
+    public static int getObjectIdFromToken(long token) {
+        return (int) (0x07ffff & (token >> 32));
+    }
+
+    /**
+     * Get the location of the offset recorded in the token.
+     */
+    public static int getOffsetFromToken(long token) {
+        return (int) token;
+    }
+
+    /**
+     * Convert the object ID to the ordinal value -- the n-th call to startObject.
+     * The object IDs start at -1 and count backwards, so that the value is unlikely
+     * to alias with an actual size field that had been written.
+     */
+    public static int convertObjectIdToOrdinal(int objectId) {
+        return (-1 & 0x07ffff) - objectId;
+    }
+
+    /**
+     * Return a debugging string of a token.
+     */
+    public static String token2String(long token) {
+        if (token == 0L) {
+            return "Token(0)";
+        } else {
+            return "Token(val=0x" + Long.toHexString(token)
+                    + " depth=" + getDepthFromToken(token)
+                    + " object=" + convertObjectIdToOrdinal(getObjectIdFromToken(token))
+                    + " tagSize=" + getTagSizeFromToken(token)
+                    + " offset=" + getOffsetFromToken(token)
+                    + ')';
+        }
+    }
+}
diff --git a/core/java/android/util/proto/ProtoUtils.java b/core/java/android/util/proto/ProtoUtils.java
index c7bbb9f..03bf590 100644
--- a/core/java/android/util/proto/ProtoUtils.java
+++ b/core/java/android/util/proto/ProtoUtils.java
@@ -19,6 +19,8 @@
 import android.util.AggStats;
 import android.util.Duration;
 
+import java.io.IOException;
+
 /**
  * This class contains a list of helper functions to write common proto in
  * //frameworks/base/core/proto/android/base directory
@@ -70,4 +72,54 @@
             }
         }
     }
+
+    /**
+     * Provide debug data about the current field as a string
+     */
+    public static String currentFieldToString(ProtoInputStream proto) throws IOException {
+        StringBuilder sb = new StringBuilder();
+
+        final int fieldNumber = proto.getFieldNumber();
+        final int wireType = proto.getWireType();
+        long fieldConstant;
+
+        sb.append("Offset : 0x" + Integer.toHexString(proto.getOffset()));
+        sb.append("\nField Number : 0x" + Integer.toHexString(proto.getFieldNumber()));
+        sb.append("\nWire Type : ");
+        switch (wireType) {
+            case ProtoStream.WIRE_TYPE_VARINT:
+                sb.append("varint");
+                fieldConstant = ProtoStream.makeFieldId(fieldNumber,
+                        ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_INT64);
+                sb.append("\nField Value : 0x" + Long.toHexString(proto.readLong(fieldConstant)));
+                break;
+            case ProtoStream.WIRE_TYPE_FIXED64:
+                sb.append("fixed64");
+                fieldConstant = ProtoStream.makeFieldId(fieldNumber,
+                        ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_FIXED64);
+                sb.append("\nField Value : 0x" + Long.toHexString(proto.readLong(fieldConstant)));
+                break;
+            case ProtoStream.WIRE_TYPE_LENGTH_DELIMITED:
+                sb.append("length delimited");
+                fieldConstant = ProtoStream.makeFieldId(fieldNumber,
+                        ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_BYTES);
+                sb.append("\nField Bytes : " + proto.readBytes(fieldConstant));
+                break;
+            case ProtoStream.WIRE_TYPE_START_GROUP:
+                sb.append("start group");
+                break;
+            case ProtoStream.WIRE_TYPE_END_GROUP:
+                sb.append("end group");
+                break;
+            case ProtoStream.WIRE_TYPE_FIXED32:
+                sb.append("fixed32");
+                fieldConstant = ProtoStream.makeFieldId(fieldNumber,
+                        ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_FIXED32);
+                sb.append("\nField Value : 0x" + Integer.toHexString(proto.readInt(fieldConstant)));
+                break;
+            default:
+                sb.append("unknown(" + proto.getWireType() + ")");
+        }
+        return sb.toString();
+    }
 }
diff --git a/core/java/android/util/proto/WireTypeMismatchException.java b/core/java/android/util/proto/WireTypeMismatchException.java
new file mode 100644
index 0000000..d90b4f8
--- /dev/null
+++ b/core/java/android/util/proto/WireTypeMismatchException.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util.proto;
+
+import android.annotation.TestApi;
+
+/**
+ * Thrown when there is an error parsing protobuf data.
+ *
+ * @hide
+ */
+@TestApi
+public class WireTypeMismatchException extends ProtoParseException {
+
+    /**
+     * Construct a WireTypeMismatchException.
+     *
+     * @param msg The message.
+     */
+    public WireTypeMismatchException(String msg) {
+        super(msg);
+    }
+}
+
diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java
index 45fa561..eb41e07 100644
--- a/core/java/android/view/AccessibilityInteractionController.java
+++ b/core/java/android/view/AccessibilityInteractionController.java
@@ -32,6 +32,7 @@
 import android.os.Parcelable;
 import android.os.Process;
 import android.os.RemoteException;
+import android.os.SystemClock;
 import android.text.style.AccessibilityClickableSpan;
 import android.text.style.ClickableSpan;
 import android.util.LongSparseArray;
@@ -702,6 +703,14 @@
                     // Handle this hidden action separately
                     succeeded = handleClickableSpanActionUiThread(
                             target, virtualDescendantId, arguments);
+                } else if (action == R.id.accessibilityActionOutsideTouch) {
+                    // trigger ACTION_OUTSIDE to notify windows
+                    final long now = SystemClock.uptimeMillis();
+                    MotionEvent event = MotionEvent.obtain(now, now, MotionEvent.ACTION_OUTSIDE,
+                            0, 0, 0);
+                    event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
+                    mViewRootImpl.dispatchInputEvent(event);
+                    succeeded = true;
                 } else {
                     AccessibilityNodeProvider provider = target.getAccessibilityNodeProvider();
                     if (provider != null) {
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index c520a99..9aab419 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -17,6 +17,7 @@
 package android.view;
 
 import android.annotation.LayoutRes;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemService;
 import android.annotation.UnsupportedAppUsage;
@@ -154,7 +155,9 @@
          * @return View Newly created view. Return null for the default
          *         behavior.
          */
-        public View onCreateView(String name, Context context, AttributeSet attrs);
+        @Nullable
+        View onCreateView(@NonNull String name, @NonNull Context context,
+                @NonNull AttributeSet attrs);
     }
 
     public interface Factory2 extends Factory {
@@ -172,7 +175,9 @@
          * @return View Newly created view. Return null for the default
          *         behavior.
          */
-        public View onCreateView(View parent, String name, Context context, AttributeSet attrs);
+        @Nullable
+        View onCreateView(@Nullable View parent, @NonNull String name,
+                @NonNull Context context, @NonNull AttributeSet attrs);
     }
 
     private static class FactoryMerger implements Factory2 {
@@ -186,13 +191,17 @@
             mF22 = f22;
         }
 
-        public View onCreateView(String name, Context context, AttributeSet attrs) {
+        @Nullable
+        public View onCreateView(@NonNull String name, @NonNull Context context,
+                @NonNull AttributeSet attrs) {
             View v = mF1.onCreateView(name, context, attrs);
             if (v != null) return v;
             return mF2.onCreateView(name, context, attrs);
         }
 
-        public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
+        @Nullable
+        public View onCreateView(@Nullable View parent, @NonNull String name,
+                @NonNull Context context, @NonNull AttributeSet attrs) {
             View v = mF12 != null ? mF12.onCreateView(parent, name, context, attrs)
                     : mF1.onCreateView(name, context, attrs);
             if (v != null) return v;
diff --git a/core/java/android/view/WindowInfo.java b/core/java/android/view/WindowInfo.java
index 7bae28a..82e9a5c 100644
--- a/core/java/android/view/WindowInfo.java
+++ b/core/java/android/view/WindowInfo.java
@@ -49,6 +49,7 @@
     public CharSequence title;
     public long accessibilityIdOfAnchor = AccessibilityNodeInfo.UNDEFINED_NODE_ID;
     public boolean inPictureInPicture;
+    public boolean hasFlagWatchOutsideTouch;
 
     private WindowInfo() {
         /* do nothing - hide constructor */
@@ -74,6 +75,7 @@
         window.title = other.title;
         window.accessibilityIdOfAnchor = other.accessibilityIdOfAnchor;
         window.inPictureInPicture = other.inPictureInPicture;
+        window.hasFlagWatchOutsideTouch = other.hasFlagWatchOutsideTouch;
 
         if (other.childTokens != null && !other.childTokens.isEmpty()) {
             if (window.childTokens == null) {
@@ -108,6 +110,7 @@
         parcel.writeCharSequence(title);
         parcel.writeLong(accessibilityIdOfAnchor);
         parcel.writeInt(inPictureInPicture ? 1 : 0);
+        parcel.writeInt(hasFlagWatchOutsideTouch ? 1 : 0);
 
         if (childTokens != null && !childTokens.isEmpty()) {
             parcel.writeInt(1);
@@ -130,6 +133,8 @@
         builder.append(", focused=").append(focused);
         builder.append(", children=").append(childTokens);
         builder.append(", accessibility anchor=").append(accessibilityIdOfAnchor);
+        builder.append(", pictureInPicture=").append(inPictureInPicture);
+        builder.append(", watchOutsideTouch=").append(hasFlagWatchOutsideTouch);
         builder.append(']');
         return builder.toString();
     }
@@ -145,6 +150,7 @@
         title = parcel.readCharSequence();
         accessibilityIdOfAnchor = parcel.readLong();
         inPictureInPicture = (parcel.readInt() == 1);
+        hasFlagWatchOutsideTouch = (parcel.readInt() == 1);
 
         final boolean hasChildren = (parcel.readInt() == 1);
         if (hasChildren) {
@@ -167,6 +173,7 @@
             childTokens.clear();
         }
         inPictureInPicture = false;
+        hasFlagWatchOutsideTouch = false;
     }
 
     public static final Parcelable.Creator<WindowInfo> CREATOR =
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index c59c491..e88682e 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -139,6 +139,8 @@
 
     int mRelevantEventTypes = AccessibilityEvent.TYPES_ALL_MASK;
 
+    int mMinimumUiTimeout;
+
     boolean mIsTouchExplorationEnabled;
 
     @UnsupportedAppUsage
@@ -320,6 +322,11 @@
         public void setRelevantEventTypes(int eventTypes) {
             mRelevantEventTypes = eventTypes;
         }
+
+        @Override
+        public void setMinimumUiTimeout(int uiTimeout) {
+            mMinimumUiTimeout = uiTimeout;
+        }
     };
 
     /**
@@ -827,6 +834,19 @@
     }
 
     /**
+     * Get the minimum timeout for changes to the UI needed by this user. Controls should remain
+     * on the screen for at least this long to give users time to react. Some users may need
+     * extra time to review the controls, or to reach them, or to activate assistive technology
+     * to activate the controls automatically.
+     *
+     * @return The minimum ui timeout for the current user in milliseconds.
+     * {@link Integer#MAX_VALUE} if timeout is infinite.
+     */
+    public int getMinimumUiTimeoutMillis() {
+        return mMinimumUiTimeout;
+    }
+
+    /**
      * Get the preparers that are registered for an accessibility ID
      *
      * @param id The ID of interest
@@ -1139,6 +1159,7 @@
             final long userStateAndRelevantEvents = service.addClient(mClient, mUserId);
             setStateLocked(IntPair.first(userStateAndRelevantEvents));
             mRelevantEventTypes = IntPair.second(userStateAndRelevantEvents);
+            mMinimumUiTimeout = service.getMinimumUiTimeout();
             mService = service;
         } catch (RemoteException re) {
             Log.e(LOG_TAG, "AccessibilityManagerService is dead", re);
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index c93e2c1..3e2ef18 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -72,4 +72,6 @@
 
     // System process only
     boolean sendFingerprintGesture(int gestureKeyCode);
+
+    int getMinimumUiTimeout();
 }
diff --git a/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl b/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl
index 9cc0315..d2ddca3 100644
--- a/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManagerClient.aidl
@@ -29,4 +29,6 @@
     void notifyServicesStateChanged();
 
     void setRelevantEventTypes(int eventTypes);
+
+    void setMinimumUiTimeout(int uiTimeout);
 }
diff --git a/core/java/android/view/inputmethod/InputMethod.java b/core/java/android/view/inputmethod/InputMethod.java
index f45507c..e1600c4 100644
--- a/core/java/android/view/inputmethod/InputMethod.java
+++ b/core/java/android/view/inputmethod/InputMethod.java
@@ -89,14 +89,17 @@
      *
      * @param token special token for the system to identify
      *              {@link InputMethodService}
+     * @param displayId The id of the display that current IME shown.
+     *                  Used for {{@link #updateInputMethodDisplay(int)}}
      * @param privilegedOperations IPC endpoint to do some privileged
      *                             operations that are allowed only to the
      *                             current IME.
      * @hide
      */
     @MainThread
-    default void initializeInternal(IBinder token,
+    default void initializeInternal(IBinder token, int displayId,
             IInputMethodPrivilegedOperations privilegedOperations) {
+        updateInputMethodDisplay(displayId);
         attachToken(token);
     }
 
@@ -115,6 +118,15 @@
     public void attachToken(IBinder token);
 
     /**
+     * Update context display according to given displayId.
+     *
+     * @param displayId The id of the display that need to update for context.
+     * @hide
+     */
+    @MainThread
+    public void updateInputMethodDisplay(int displayId);
+
+    /**
      * Bind a new application environment in to the input method, so that it
      * can later start and stop input processing.
      * Typically this method is called when this input method is enabled in an
diff --git a/core/java/android/view/inputmethod/InputMethodSubtype.java b/core/java/android/view/inputmethod/InputMethodSubtype.java
index 61a6972..a7d7a8d 100644
--- a/core/java/android/view/inputmethod/InputMethodSubtype.java
+++ b/core/java/android/view/inputmethod/InputMethodSubtype.java
@@ -28,7 +28,7 @@
 import android.text.TextUtils;
 import android.util.Slog;
 
-import com.android.internal.inputmethod.LocaleUtils;
+import com.android.internal.inputmethod.InputMethodUtils;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -384,7 +384,7 @@
             if (!TextUtils.isEmpty(mSubtypeLanguageTag)) {
                 mCachedLocaleObj = Locale.forLanguageTag(mSubtypeLanguageTag);
             } else {
-                mCachedLocaleObj = LocaleUtils.constructLocaleFromString(mSubtypeLocale);
+                mCachedLocaleObj = InputMethodUtils.constructLocaleFromString(mSubtypeLocale);
             }
             return mCachedLocaleObj;
         }
diff --git a/core/java/android/view/textservice/SpellCheckerSubtype.java b/core/java/android/view/textservice/SpellCheckerSubtype.java
index 41b70b6..026610e 100644
--- a/core/java/android/view/textservice/SpellCheckerSubtype.java
+++ b/core/java/android/view/textservice/SpellCheckerSubtype.java
@@ -25,7 +25,7 @@
 import android.text.TextUtils;
 import android.util.Slog;
 
-import com.android.internal.inputmethod.LocaleUtils;
+import com.android.internal.inputmethod.InputMethodUtils;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -228,7 +228,7 @@
         if (!TextUtils.isEmpty(mSubtypeLanguageTag)) {
             return Locale.forLanguageTag(mSubtypeLanguageTag);
         }
-        return LocaleUtils.constructLocaleFromString(mSubtypeLocale);
+        return InputMethodUtils.constructLocaleFromString(mSubtypeLocale);
     }
 
     /**
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index e9a9e8f..46b1f6e 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -51,9 +51,6 @@
 
     private static final String CHROMIUM_WEBVIEW_FACTORY_METHOD = "create";
 
-    public static final String CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY =
-            "persist.sys.webview.vmsize";
-
     private static final String LOGTAG = "WebViewFactory";
 
     private static final boolean DEBUG = false;
diff --git a/core/java/android/webkit/WebViewLibraryLoader.java b/core/java/android/webkit/WebViewLibraryLoader.java
index cabba06..5a6aeba 100644
--- a/core/java/android/webkit/WebViewLibraryLoader.java
+++ b/core/java/android/webkit/WebViewLibraryLoader.java
@@ -17,15 +17,14 @@
 package android.webkit;
 
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.app.ActivityManagerInternal;
-import android.content.pm.ApplicationInfo;
+import android.app.ActivityThread;
+import android.app.LoadedApk;
+import android.content.Context;
 import android.content.pm.PackageInfo;
 import android.os.Build;
 import android.os.Process;
 import android.os.RemoteException;
-import android.os.SystemProperties;
-import android.text.TextUtils;
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -33,11 +32,7 @@
 
 import dalvik.system.VMRuntime;
 
-import java.io.File;
-import java.io.IOException;
 import java.util.Arrays;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
 
 /**
  * @hide
@@ -50,7 +45,6 @@
             "/data/misc/shared_relro/libwebviewchromium32.relro";
     private static final String CHROMIUM_WEBVIEW_NATIVE_RELRO_64 =
             "/data/misc/shared_relro/libwebviewchromium64.relro";
-    private static final long CHROMIUM_WEBVIEW_DEFAULT_VMSIZE_BYTES = 100 * 1024 * 1024;
 
     private static final boolean DEBUG = false;
 
@@ -69,18 +63,26 @@
             boolean result = false;
             boolean is64Bit = VMRuntime.getRuntime().is64Bit();
             try {
-                if (args.length != 1 || args[0] == null) {
+                if (args.length != 2 || args[0] == null || args[1] == null) {
                     Log.e(LOGTAG, "Invalid RelroFileCreator args: " + Arrays.toString(args));
                     return;
                 }
-                Log.v(LOGTAG, "RelroFileCreator (64bit = " + is64Bit + "), lib: " + args[0]);
+                String packageName = args[0];
+                String libraryFileName = args[1];
+                Log.v(LOGTAG, "RelroFileCreator (64bit = " + is64Bit + "), package: "
+                        + packageName + " library: " + libraryFileName);
                 if (!sAddressSpaceReserved) {
                     Log.e(LOGTAG, "can't create relro file; address space not reserved");
                     return;
                 }
-                result = nativeCreateRelroFile(args[0] /* path */,
+                LoadedApk apk = ActivityThread.currentActivityThread().getPackageInfo(
+                        packageName,
+                        null,
+                        Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
+                result = nativeCreateRelroFile(libraryFileName,
                                                is64Bit ? CHROMIUM_WEBVIEW_NATIVE_RELRO_64 :
-                                                         CHROMIUM_WEBVIEW_NATIVE_RELRO_32);
+                                                         CHROMIUM_WEBVIEW_NATIVE_RELRO_32,
+                                               apk.getClassLoader());
                 if (result && DEBUG) Log.v(LOGTAG, "created relro file");
             } finally {
                 // We must do our best to always notify the update service, even if something fails.
@@ -101,7 +103,8 @@
     /**
      * Create a single relro file by invoking an isolated process that to do the actual work.
      */
-    static void createRelroFile(final boolean is64Bit, @NonNull WebViewNativeLibrary nativeLib) {
+    static void createRelroFile(final boolean is64Bit, @NonNull String packageName,
+            @NonNull String libraryFileName) {
         final String abi =
                 is64Bit ? Build.SUPPORTED_64_BIT_ABIS[0] : Build.SUPPORTED_32_BIT_ABIS[0];
 
@@ -119,13 +122,10 @@
         };
 
         try {
-            if (nativeLib == null || nativeLib.path == null) {
-                throw new IllegalArgumentException(
-                        "Native library paths to the WebView RelRo process must not be null!");
-            }
             boolean success = LocalServices.getService(ActivityManagerInternal.class)
                     .startIsolatedProcess(
-                            RelroFileCreator.class.getName(), new String[] { nativeLib.path },
+                            RelroFileCreator.class.getName(),
+                            new String[] { packageName, libraryFileName },
                             "WebViewLoader-" + abi, abi, Process.SHARED_RELRO_UID, crashHandler);
             if (!success) throw new Exception("Failed to start the relro file creator process");
         } catch (Throwable t) {
@@ -140,83 +140,50 @@
      * be called whenever we change WebView provider.
      * @return the number of relro processes started.
      */
-    static int prepareNativeLibraries(PackageInfo webviewPackageInfo)
-            throws WebViewFactory.MissingWebViewPackageException {
-        WebViewNativeLibrary nativeLib32bit =
-                getWebViewNativeLibrary(webviewPackageInfo, false /* is64bit */);
-        WebViewNativeLibrary nativeLib64bit =
-                getWebViewNativeLibrary(webviewPackageInfo, true /* is64bit */);
-        updateWebViewZygoteVmSize(nativeLib32bit, nativeLib64bit);
-
-        return createRelros(nativeLib32bit, nativeLib64bit);
+    static int prepareNativeLibraries(@NonNull PackageInfo webViewPackageInfo) {
+        // TODO(torne): new way of calculating VM size
+        // updateWebViewZygoteVmSize(nativeLib32bit, nativeLib64bit);
+        String libraryFileName = WebViewFactory.getWebViewLibrary(
+                webViewPackageInfo.applicationInfo);
+        if (libraryFileName == null) {
+            // Can't do anything with no filename, don't spawn any processes.
+            return 0;
+        }
+        return createRelros(webViewPackageInfo.packageName, libraryFileName);
     }
 
     /**
      * @return the number of relro processes started.
      */
-    private static int createRelros(@Nullable WebViewNativeLibrary nativeLib32bit,
-            @Nullable WebViewNativeLibrary nativeLib64bit) {
+    private static int createRelros(@NonNull String packageName, @NonNull String libraryFileName) {
         if (DEBUG) Log.v(LOGTAG, "creating relro files");
         int numRelros = 0;
 
         if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {
-            if (nativeLib32bit == null) {
-                Log.e(LOGTAG, "No 32-bit WebView library path, skipping relro creation.");
-            } else {
-                if (DEBUG) Log.v(LOGTAG, "Create 32 bit relro");
-                createRelroFile(false /* is64Bit */, nativeLib32bit);
-                numRelros++;
-            }
+            if (DEBUG) Log.v(LOGTAG, "Create 32 bit relro");
+            createRelroFile(false /* is64Bit */, packageName, libraryFileName);
+            numRelros++;
         }
 
         if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {
-            if (nativeLib64bit == null) {
-                Log.e(LOGTAG, "No 64-bit WebView library path, skipping relro creation.");
-            } else {
-                if (DEBUG) Log.v(LOGTAG, "Create 64 bit relro");
-                createRelroFile(true /* is64Bit */, nativeLib64bit);
-                numRelros++;
-            }
+            if (DEBUG) Log.v(LOGTAG, "Create 64 bit relro");
+            createRelroFile(true /* is64Bit */, packageName, libraryFileName);
+            numRelros++;
         }
         return numRelros;
     }
 
     /**
-     *
-     * @return the native WebView libraries in the new WebView APK.
-     */
-    private static void updateWebViewZygoteVmSize(
-            @Nullable WebViewNativeLibrary nativeLib32bit,
-            @Nullable WebViewNativeLibrary nativeLib64bit)
-            throws WebViewFactory.MissingWebViewPackageException {
-        // Find the native libraries of the new WebView package, to change the size of the
-        // memory region in the Zygote reserved for the library.
-        long newVmSize = 0L;
-
-        if (nativeLib32bit != null) newVmSize = Math.max(newVmSize, nativeLib32bit.size);
-        if (nativeLib64bit != null) newVmSize = Math.max(newVmSize, nativeLib64bit.size);
-
-        if (DEBUG) {
-            Log.v(LOGTAG, "Based on library size, need " + newVmSize
-                    + " bytes of address space.");
-        }
-        // The required memory can be larger than the file on disk (due to .bss), and an
-        // upgraded version of the library will likely be larger, so always attempt to
-        // reserve twice as much as we think to allow for the library to grow during this
-        // boot cycle.
-        newVmSize = Math.max(2 * newVmSize, CHROMIUM_WEBVIEW_DEFAULT_VMSIZE_BYTES);
-        Log.d(LOGTAG, "Setting new address space to " + newVmSize);
-        setWebViewZygoteVmSize(newVmSize);
-    }
-
-    /**
      * Reserve space for the native library to be loaded into.
      */
     static void reserveAddressSpaceInZygote() {
         System.loadLibrary("webviewchromium_loader");
-        long addressSpaceToReserve =
-                SystemProperties.getLong(WebViewFactory.CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY,
-                CHROMIUM_WEBVIEW_DEFAULT_VMSIZE_BYTES);
+        boolean is64Bit = VMRuntime.getRuntime().is64Bit();
+        // On 64-bit address space is really cheap and we can reserve 1GB which is plenty.
+        // On 32-bit it's fairly scarce and we should keep it to a realistic number that
+        // permits some future growth but doesn't hog space: we use 100MB which is more than 2x
+        // the current requirement.
+        long addressSpaceToReserve = is64Bit ? 1 * 1024 * 1024 * 1024 : 100 * 1024 * 1024;
         sAddressSpaceReserved = nativeReserveAddressSpace(addressSpaceToReserve);
 
         if (sAddressSpaceReserved) {
@@ -253,106 +220,7 @@
         return result;
     }
 
-    /**
-     * Fetch WebView's native library paths from {@param packageInfo}.
-     * @hide
-     */
-    @Nullable
-    @VisibleForTesting
-    public static WebViewNativeLibrary getWebViewNativeLibrary(PackageInfo packageInfo,
-            boolean is64bit) throws WebViewFactory.MissingWebViewPackageException {
-        ApplicationInfo ai = packageInfo.applicationInfo;
-        final String nativeLibFileName = WebViewFactory.getWebViewLibrary(ai);
-
-        String dir = getWebViewNativeLibraryDirectory(ai, is64bit /* 64bit */);
-
-        WebViewNativeLibrary lib = findNativeLibrary(ai, nativeLibFileName,
-                is64bit ? Build.SUPPORTED_64_BIT_ABIS : Build.SUPPORTED_32_BIT_ABIS, dir);
-
-        if (DEBUG) {
-            Log.v(LOGTAG, String.format("Native %d-bit lib: %s", is64bit ? 64 : 32, lib.path));
-        }
-        return lib;
-    }
-
-    /**
-     * @return the directory of the native WebView library with bitness {@param is64bit}.
-     * @hide
-     */
-    @VisibleForTesting
-    public static String getWebViewNativeLibraryDirectory(ApplicationInfo ai, boolean is64bit) {
-        // Primary arch has the same bitness as the library we are looking for.
-        if (is64bit == VMRuntime.is64BitAbi(ai.primaryCpuAbi)) return ai.nativeLibraryDir;
-
-        // Secondary arch has the same bitness as the library we are looking for.
-        if (!TextUtils.isEmpty(ai.secondaryCpuAbi)) {
-            return ai.secondaryNativeLibraryDir;
-        }
-
-        return "";
-    }
-
-    /**
-     * @return an object describing a native WebView library given the directory path of that
-     * library, or null if the library couldn't be found.
-     */
-    @Nullable
-    private static WebViewNativeLibrary findNativeLibrary(ApplicationInfo ai,
-            String nativeLibFileName, String[] abiList, String libDirectory)
-            throws WebViewFactory.MissingWebViewPackageException {
-        if (TextUtils.isEmpty(libDirectory)) return null;
-        String libPath = libDirectory + "/" + nativeLibFileName;
-        File f = new File(libPath);
-        if (f.exists()) {
-            return new WebViewNativeLibrary(libPath, f.length());
-        } else {
-            return getLoadFromApkPath(ai.sourceDir, abiList, nativeLibFileName);
-        }
-    }
-
-    /**
-     * @hide
-     */
-    @VisibleForTesting
-    public static class WebViewNativeLibrary {
-        public final String path;
-        public final long size;
-
-        WebViewNativeLibrary(String path, long size) {
-            this.path = path;
-            this.size = size;
-        }
-    }
-
-    private static WebViewNativeLibrary getLoadFromApkPath(String apkPath,
-                                                           String[] abiList,
-                                                           String nativeLibFileName)
-            throws WebViewFactory.MissingWebViewPackageException {
-        // Search the APK for a native library conforming to a listed ABI.
-        try (ZipFile z = new ZipFile(apkPath)) {
-            for (String abi : abiList) {
-                final String entry = "lib/" + abi + "/" + nativeLibFileName;
-                ZipEntry e = z.getEntry(entry);
-                if (e != null && e.getMethod() == ZipEntry.STORED) {
-                    // Return a path formatted for dlopen() load from APK.
-                    return new WebViewNativeLibrary(apkPath + "!/" + entry, e.getSize());
-                }
-            }
-        } catch (IOException e) {
-            throw new WebViewFactory.MissingWebViewPackageException(e);
-        }
-        return null;
-    }
-
-    /**
-     * Sets the size of the memory area in which to store the relro section.
-     */
-    private static void setWebViewZygoteVmSize(long vmSize) {
-        SystemProperties.set(WebViewFactory.CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY,
-                Long.toString(vmSize));
-    }
-
     static native boolean nativeReserveAddressSpace(long addressSpaceToReserve);
-    static native boolean nativeCreateRelroFile(String lib, String relro);
+    static native boolean nativeCreateRelroFile(String lib, String relro, ClassLoader clazzLoader);
     static native int nativeLoadWithRelroFile(String lib, String relro, ClassLoader clazzLoader);
 }
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 0645a16..d913273 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -313,6 +313,7 @@
  * @attr ref android.R.styleable#TextView_fallbackLineSpacing
  * @attr ref android.R.styleable#TextView_letterSpacing
  * @attr ref android.R.styleable#TextView_fontFeatureSettings
+ * @attr ref android.R.styleable#TextView_fontVariationSettings
  * @attr ref android.R.styleable#TextView_breakStrategy
  * @attr ref android.R.styleable#TextView_hyphenationFrequency
  * @attr ref android.R.styleable#TextView_autoSizeTextType
@@ -4382,6 +4383,8 @@
      *
      * @see #getFontVariationSettings()
      * @see FontVariationAxis
+     *
+     * @attr ref android.R.styleable#TextView_fontVariationSettings
      */
     public boolean setFontVariationSettings(@Nullable String fontVariationSettings) {
         final String existingSettings = mTextPaint.getFontVariationSettings();
diff --git a/core/java/com/android/internal/colorextraction/types/Tonal.java b/core/java/com/android/internal/colorextraction/types/Tonal.java
index 7b25a06..3fd88db 100644
--- a/core/java/com/android/internal/colorextraction/types/Tonal.java
+++ b/core/java/com/android/internal/colorextraction/types/Tonal.java
@@ -51,10 +51,8 @@
 
     private static final boolean DEBUG = true;
 
-    public static final int THRESHOLD_COLOR_LIGHT = 0xffe0e0e0;
     public static final int MAIN_COLOR_LIGHT = 0xffe0e0e0;
-    public static final int THRESHOLD_COLOR_DARK = 0xff212121;
-    public static final int MAIN_COLOR_DARK = 0xff000000;
+    public static final int MAIN_COLOR_DARK = 0xff212121;
 
     private final TonalPalette mGreyPalette;
     private final ArrayList<TonalPalette> mTonalPalettes;
@@ -197,12 +195,12 @@
         // light fallback or darker than our dark fallback.
         ColorUtils.colorToHSL(mainColor, mTmpHSL);
         final float mainLuminosity = mTmpHSL[2];
-        ColorUtils.colorToHSL(THRESHOLD_COLOR_LIGHT, mTmpHSL);
+        ColorUtils.colorToHSL(MAIN_COLOR_LIGHT, mTmpHSL);
         final float lightLuminosity = mTmpHSL[2];
         if (mainLuminosity > lightLuminosity) {
             return false;
         }
-        ColorUtils.colorToHSL(THRESHOLD_COLOR_DARK, mTmpHSL);
+        ColorUtils.colorToHSL(MAIN_COLOR_DARK, mTmpHSL);
         final float darkLuminosity = mTmpHSL[2];
         if (mainLuminosity < darkLuminosity) {
             return false;
diff --git a/core/java/com/android/internal/inputmethod/InputMethodUtils.java b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
index 1410ff9..1e5b5c8 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodUtils.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
@@ -334,6 +334,32 @@
         return getDefaultEnabledImes(context, imis, false /* onlyMinimum */);
     }
 
+    public static Locale constructLocaleFromString(String localeStr) {
+        if (TextUtils.isEmpty(localeStr)) {
+            return null;
+        }
+        // TODO: Use {@link Locale#toLanguageTag()} and {@link Locale#forLanguageTag(languageTag)}.
+        String[] localeParams = localeStr.split("_", 3);
+        if (localeParams.length >= 1 && "tl".equals(localeParams[0])) {
+             // Convert a locale whose language is "tl" to one whose language is "fil".
+             // For example, "tl_PH" will get converted to "fil_PH".
+             // Versions of Android earlier than Lollipop did not support three letter language
+             // codes, and used "tl" (Tagalog) as the language string for "fil" (Filipino).
+             // On Lollipop and above, the current three letter version must be used.
+             localeParams[0] = "fil";
+        }
+        // The length of localeStr is guaranteed to always return a 1 <= value <= 3
+        // because localeStr is not empty.
+        if (localeParams.length == 1) {
+            return new Locale(localeParams[0]);
+        } else if (localeParams.length == 2) {
+            return new Locale(localeParams[0], localeParams[1]);
+        } else if (localeParams.length == 3) {
+            return new Locale(localeParams[0], localeParams[1], localeParams[2]);
+        }
+        return null;
+    }
+
     public static boolean containsSubtypeOf(final InputMethodInfo imi,
             @Nullable final Locale locale, final boolean checkCountry, final String mode) {
         if (locale == null) {
@@ -1294,7 +1320,133 @@
         }
     }
 
+    // For spell checker service manager.
+    // TODO: Should we have TextServicesUtils.java?
+    private static final Locale LOCALE_EN_US = new Locale("en", "US");
+    private static final Locale LOCALE_EN_GB = new Locale("en", "GB");
+
+    /**
+     * Returns a list of {@link Locale} in the order of appropriateness for the default spell
+     * checker service.
+     *
+     * <p>If the system language is English, and the region is also explicitly specified in the
+     * system locale, the following fallback order will be applied.</p>
+     * <ul>
+     * <li>(system-locale-language, system-locale-region, system-locale-variant) (if exists)</li>
+     * <li>(system-locale-language, system-locale-region)</li>
+     * <li>("en", "US")</li>
+     * <li>("en", "GB")</li>
+     * <li>("en")</li>
+     * </ul>
+     *
+     * <p>If the system language is English, but no region is specified in the system locale,
+     * the following fallback order will be applied.</p>
+     * <ul>
+     * <li>("en")</li>
+     * <li>("en", "US")</li>
+     * <li>("en", "GB")</li>
+     * </ul>
+     *
+     * <p>If the system language is not English, the following fallback order will be applied.</p>
+     * <ul>
+     * <li>(system-locale-language, system-locale-region, system-locale-variant) (if exists)</li>
+     * <li>(system-locale-language, system-locale-region) (if exists)</li>
+     * <li>(system-locale-language) (if exists)</li>
+     * <li>("en", "US")</li>
+     * <li>("en", "GB")</li>
+     * <li>("en")</li>
+     * </ul>
+     *
+     * @param systemLocale the current system locale to be taken into consideration.
+     * @return a list of {@link Locale}. The first one is considered to be most appropriate.
+     */
     @VisibleForTesting
+    public static ArrayList<Locale> getSuitableLocalesForSpellChecker(
+            @Nullable final Locale systemLocale) {
+        final Locale systemLocaleLanguageCountryVariant;
+        final Locale systemLocaleLanguageCountry;
+        final Locale systemLocaleLanguage;
+        if (systemLocale != null) {
+            final String language = systemLocale.getLanguage();
+            final boolean hasLanguage = !TextUtils.isEmpty(language);
+            final String country = systemLocale.getCountry();
+            final boolean hasCountry = !TextUtils.isEmpty(country);
+            final String variant = systemLocale.getVariant();
+            final boolean hasVariant = !TextUtils.isEmpty(variant);
+            if (hasLanguage && hasCountry && hasVariant) {
+                systemLocaleLanguageCountryVariant = new Locale(language, country, variant);
+            } else {
+                systemLocaleLanguageCountryVariant = null;
+            }
+            if (hasLanguage && hasCountry) {
+                systemLocaleLanguageCountry = new Locale(language, country);
+            } else {
+                systemLocaleLanguageCountry = null;
+            }
+            if (hasLanguage) {
+                systemLocaleLanguage = new Locale(language);
+            } else {
+                systemLocaleLanguage = null;
+            }
+        } else {
+            systemLocaleLanguageCountryVariant = null;
+            systemLocaleLanguageCountry = null;
+            systemLocaleLanguage = null;
+        }
+
+        final ArrayList<Locale> locales = new ArrayList<>();
+        if (systemLocaleLanguageCountryVariant != null) {
+            locales.add(systemLocaleLanguageCountryVariant);
+        }
+
+        if (Locale.ENGLISH.equals(systemLocaleLanguage)) {
+            if (systemLocaleLanguageCountry != null) {
+                // If the system language is English, and the region is also explicitly specified,
+                // following fallback order will be applied.
+                // - systemLocaleLanguageCountry [if systemLocaleLanguageCountry is non-null]
+                // - en_US [if systemLocaleLanguageCountry is non-null and not en_US]
+                // - en_GB [if systemLocaleLanguageCountry is non-null and not en_GB]
+                // - en
+                if (systemLocaleLanguageCountry != null) {
+                    locales.add(systemLocaleLanguageCountry);
+                }
+                if (!LOCALE_EN_US.equals(systemLocaleLanguageCountry)) {
+                    locales.add(LOCALE_EN_US);
+                }
+                if (!LOCALE_EN_GB.equals(systemLocaleLanguageCountry)) {
+                    locales.add(LOCALE_EN_GB);
+                }
+                locales.add(Locale.ENGLISH);
+            } else {
+                // If the system language is English, but no region is specified, following
+                // fallback order will be applied.
+                // - en
+                // - en_US
+                // - en_GB
+                locales.add(Locale.ENGLISH);
+                locales.add(LOCALE_EN_US);
+                locales.add(LOCALE_EN_GB);
+            }
+        } else {
+            // If the system language is not English, the fallback order will be
+            // - systemLocaleLanguageCountry  [if non-null]
+            // - systemLocaleLanguage  [if non-null]
+            // - en_US
+            // - en_GB
+            // - en
+            if (systemLocaleLanguageCountry != null) {
+                locales.add(systemLocaleLanguageCountry);
+            }
+            if (systemLocaleLanguage != null) {
+                locales.add(systemLocaleLanguage);
+            }
+            locales.add(LOCALE_EN_US);
+            locales.add(LOCALE_EN_GB);
+            locales.add(Locale.ENGLISH);
+        }
+        return locales;
+    }
+
     public static boolean isSoftInputModeStateVisibleAllowed(
             int targetSdkVersion, int controlFlags) {
         if (targetSdkVersion < Build.VERSION_CODES.P) {
@@ -1309,4 +1461,5 @@
         }
         return true;
     }
+
 }
diff --git a/core/java/com/android/internal/inputmethod/LocaleUtils.java b/core/java/com/android/internal/inputmethod/LocaleUtils.java
index f7360eb..eeb3854 100644
--- a/core/java/com/android/internal/inputmethod/LocaleUtils.java
+++ b/core/java/com/android/internal/inputmethod/LocaleUtils.java
@@ -16,6 +16,8 @@
 
 package com.android.internal.inputmethod;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -23,8 +25,6 @@
 import android.os.LocaleList;
 import android.text.TextUtils;
 
-import com.android.internal.annotations.VisibleForTesting;
-
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -208,151 +208,4 @@
             dest.add(sources.get(entry.mIndex));
         }
     }
-
-    public static Locale constructLocaleFromString(String localeStr) {
-        if (TextUtils.isEmpty(localeStr)) {
-            return null;
-        }
-        // TODO: Use {@link Locale#toLanguageTag()} and {@link Locale#forLanguageTag(languageTag)}.
-        String[] localeParams = localeStr.split("_", 3);
-        if (localeParams.length >= 1 && "tl".equals(localeParams[0])) {
-            // Convert a locale whose language is "tl" to one whose language is "fil".
-            // For example, "tl_PH" will get converted to "fil_PH".
-            // Versions of Android earlier than Lollipop did not support three letter language
-            // codes, and used "tl" (Tagalog) as the language string for "fil" (Filipino).
-            // On Lollipop and above, the current three letter version must be used.
-            localeParams[0] = "fil";
-        }
-        // The length of localeStr is guaranteed to always return a 1 <= value <= 3
-        // because localeStr is not empty.
-        if (localeParams.length == 1) {
-            return new Locale(localeParams[0]);
-        } else if (localeParams.length == 2) {
-            return new Locale(localeParams[0], localeParams[1]);
-        } else if (localeParams.length == 3) {
-            return new Locale(localeParams[0], localeParams[1], localeParams[2]);
-        }
-        return null;
-    }
-
-    /**
-     * Returns a list of {@link Locale} in the order of appropriateness for the default spell
-     * checker service.
-     *
-     * <p>If the system language is English, and the region is also explicitly specified in the
-     * system locale, the following fallback order will be applied.</p>
-     * <ul>
-     * <li>(system-locale-language, system-locale-region, system-locale-variant) (if exists)</li>
-     * <li>(system-locale-language, system-locale-region)</li>
-     * <li>("en", "US")</li>
-     * <li>("en", "GB")</li>
-     * <li>("en")</li>
-     * </ul>
-     *
-     * <p>If the system language is English, but no region is specified in the system locale,
-     * the following fallback order will be applied.</p>
-     * <ul>
-     * <li>("en")</li>
-     * <li>("en", "US")</li>
-     * <li>("en", "GB")</li>
-     * </ul>
-     *
-     * <p>If the system language is not English, the following fallback order will be applied.</p>
-     * <ul>
-     * <li>(system-locale-language, system-locale-region, system-locale-variant) (if exists)</li>
-     * <li>(system-locale-language, system-locale-region) (if exists)</li>
-     * <li>(system-locale-language) (if exists)</li>
-     * <li>("en", "US")</li>
-     * <li>("en", "GB")</li>
-     * <li>("en")</li>
-     * </ul>
-     *
-     * @param systemLocale the current system locale to be taken into consideration.
-     * @return a list of {@link Locale}. The first one is considered to be most appropriate.
-     */
-    public static ArrayList<Locale> getSuitableLocalesForSpellChecker(
-            @Nullable final Locale systemLocale) {
-        final Locale systemLocaleLanguageCountryVariant;
-        final Locale systemLocaleLanguageCountry;
-        final Locale systemLocaleLanguage;
-        if (systemLocale != null) {
-            final String language = systemLocale.getLanguage();
-            final boolean hasLanguage = !TextUtils.isEmpty(language);
-            final String country = systemLocale.getCountry();
-            final boolean hasCountry = !TextUtils.isEmpty(country);
-            final String variant = systemLocale.getVariant();
-            final boolean hasVariant = !TextUtils.isEmpty(variant);
-            if (hasLanguage && hasCountry && hasVariant) {
-                systemLocaleLanguageCountryVariant = new Locale(language, country, variant);
-            } else {
-                systemLocaleLanguageCountryVariant = null;
-            }
-            if (hasLanguage && hasCountry) {
-                systemLocaleLanguageCountry = new Locale(language, country);
-            } else {
-                systemLocaleLanguageCountry = null;
-            }
-            if (hasLanguage) {
-                systemLocaleLanguage = new Locale(language);
-            } else {
-                systemLocaleLanguage = null;
-            }
-        } else {
-            systemLocaleLanguageCountryVariant = null;
-            systemLocaleLanguageCountry = null;
-            systemLocaleLanguage = null;
-        }
-
-        final ArrayList<Locale> locales = new ArrayList<>();
-        if (systemLocaleLanguageCountryVariant != null) {
-            locales.add(systemLocaleLanguageCountryVariant);
-        }
-
-        if (Locale.ENGLISH.equals(systemLocaleLanguage)) {
-            if (systemLocaleLanguageCountry != null) {
-                // If the system language is English, and the region is also explicitly specified,
-                // following fallback order will be applied.
-                // - systemLocaleLanguageCountry [if systemLocaleLanguageCountry is non-null]
-                // - en_US [if systemLocaleLanguageCountry is non-null and not en_US]
-                // - en_GB [if systemLocaleLanguageCountry is non-null and not en_GB]
-                // - en
-                if (systemLocaleLanguageCountry != null) {
-                    locales.add(systemLocaleLanguageCountry);
-                }
-                if (!Locale.US.equals(systemLocaleLanguageCountry)) {
-                    locales.add(Locale.US);
-                }
-                if (!Locale.UK.equals(systemLocaleLanguageCountry)) {
-                    locales.add(Locale.UK);
-                }
-                locales.add(Locale.ENGLISH);
-            } else {
-                // If the system language is English, but no region is specified, following
-                // fallback order will be applied.
-                // - en
-                // - en_US
-                // - en_GB
-                locales.add(Locale.ENGLISH);
-                locales.add(Locale.US);
-                locales.add(Locale.UK);
-            }
-        } else {
-            // If the system language is not English, the fallback order will be
-            // - systemLocaleLanguageCountry  [if non-null]
-            // - systemLocaleLanguage  [if non-null]
-            // - en_US
-            // - en_GB
-            // - en
-            if (systemLocaleLanguageCountry != null) {
-                locales.add(systemLocaleLanguageCountry);
-            }
-            if (systemLocaleLanguage != null) {
-                locales.add(systemLocaleLanguage);
-            }
-            locales.add(Locale.US);
-            locales.add(Locale.UK);
-            locales.add(Locale.ENGLISH);
-        }
-        return locales;
-    }
 }
diff --git a/core/java/com/android/internal/util/ContrastColorUtil.java b/core/java/com/android/internal/util/ContrastColorUtil.java
index 16ca4fc..1038199 100644
--- a/core/java/com/android/internal/util/ContrastColorUtil.java
+++ b/core/java/com/android/internal/util/ContrastColorUtil.java
@@ -455,7 +455,7 @@
      * Resolves {@param color} to an actual color if it is {@link Notification#COLOR_DEFAULT}
      */
     public static int resolveColor(Context context, int color, boolean defaultBackgroundIsDark) {
-        if (color == Notification.COLOR_DEFAULT) {
+        if (color == Notification.COLOR_DEFAULT || defaultBackgroundIsDark) {
             int res = defaultBackgroundIsDark
                     ? com.android.internal.R.color.notification_default_color_dark
                     : com.android.internal.R.color.notification_default_color_light;
diff --git a/core/java/com/android/internal/util/OWNERS b/core/java/com/android/internal/util/OWNERS
index 21d750c..e65d114 100644
--- a/core/java/com/android/internal/util/OWNERS
+++ b/core/java/com/android/internal/util/OWNERS
@@ -1,24 +1,4 @@
-per-file AsyncChannel*=lorenzo@google.com
-per-file AsyncChannel*=satk@google.com
-per-file AsyncChannel*=silberst@google.com
-per-file BitUtils*=ek@google.com
-per-file BitUtils*=lorenzo@google.com
-per-file BitUtils*=satk@google.com
-per-file MessageUtils*=ek@google.com
-per-file MessageUtils*=lorenzo@google.com
-per-file MessageUtils*=satk@google.com
-per-file Protocol*=ek@google.com
-per-file Protocol*=lorenzo@google.com
-per-file Protocol*=quiche@google.com
-per-file Protocol*=satk@google.com
-per-file Protocol*=silberst@google.com
-per-file RingBuffer*=ek@google.com
-per-file RingBuffer*=lorenzo@google.com
-per-file RingBuffer*=satk@google.com
-per-file State*=ek@google.com
-per-file State*=lorenzo@google.com
-per-file State*=quiche@google.com
-per-file State*=silberst@google.com
-per-file TokenBucket*=ek@google.com
-per-file TokenBucket*=lorenzo@google.com
-per-file TokenBucket*=satk@google.com
+per-file AsyncChannel* = lorenzo@google.com, satk@google.com, etancohen@google.com
+per-file BitUtils*, MessageUtils*, Protocol*, RingBuffer*, TokenBucket* = jchalard@google.com, lorenzo@google.com, satk@google.com
+per-file Protocol* = etancohen@google.com, lorenzo@google.com
+per-file State* = jchalard@google.com, lorenzo@google.com, satk@google.com
diff --git a/core/java/com/android/internal/view/IInputMethod.aidl b/core/java/com/android/internal/view/IInputMethod.aidl
index b6a654a..97d5a65 100644
--- a/core/java/com/android/internal/view/IInputMethod.aidl
+++ b/core/java/com/android/internal/view/IInputMethod.aidl
@@ -33,7 +33,7 @@
  * {@hide}
  */
 oneway interface IInputMethod {
-    void initializeInternal(IBinder token, IInputMethodPrivilegedOperations privOps);
+    void initializeInternal(IBinder token, int displayId, IInputMethodPrivilegedOperations privOps);
 
     void bindInput(in InputBinding binding);
 
diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto
index 6e661e1..3ead633 100644
--- a/core/proto/android/providers/settings/secure.proto
+++ b/core/proto/android/providers/settings/secure.proto
@@ -72,6 +72,9 @@
         // List of the accessibility services to which the user has granted
         // permission to put the device into touch exploration mode.
         optional SettingProto touch_exploration_granted_accessibility_services = 31;
+        optional SettingProto minimum_ui_timeout_enabled = 32 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto minimum_ui_timeout_ms = 33 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
     }
     optional Accessibility accessibility = 2;
 
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 6932be3..e153082 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -284,7 +284,7 @@
     <string name="permgrouprequest_sms" msgid="7168124215838204719">"Permettre à &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; d\'envoyer et d\'afficher des SMS ?"</string>
     <string name="permgrouplab_storage" msgid="1971118770546336966">"Stockage"</string>
     <string name="permgroupdesc_storage" msgid="637758554581589203">"accéder à des photos, à des contenus multimédias et à des fichiers sur votre appareil"</string>
-    <string name="permgrouprequest_storage" msgid="7885942926944299560">"Permettre à &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; d\'accéder aux photos, contenus multimédias et fichiers sur votre appareil ?"</string>
+    <string name="permgrouprequest_storage" msgid="7885942926944299560">"Autoriser &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; à accéder aux photos, contenus multimédias et fichiers sur votre appareil ?"</string>
     <string name="permgrouplab_microphone" msgid="171539900250043464">"Microphone"</string>
     <string name="permgroupdesc_microphone" msgid="4988812113943554584">"enregistrer des fichiers audio"</string>
     <string name="permgrouprequest_microphone" msgid="9167492350681916038">"Permettre à &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; d\'enregistrer des contenus audio ?"</string>
@@ -1340,7 +1340,7 @@
     <string name="ext_media_unmountable_notification_message" msgid="4193858924381066522">"Appuyez sur la notification pour résoudre le problème"</string>
     <string name="ext_media_unmountable_notification_message" product="tv" msgid="3941179940297874950">"La <xliff:g id="NAME">%s</xliff:g> est corrompue. Sélectionnez cette option pour résoudre le problème."</string>
     <string name="ext_media_unsupported_notification_title" msgid="3797642322958803257">"<xliff:g id="NAME">%s</xliff:g> non compatible"</string>
-    <string name="ext_media_unsupported_notification_message" msgid="6121601473787888589">"Cet appareil n\'est pas compatible avec la mémoire de stockage \"<xliff:g id="NAME">%s</xliff:g>\". Appuyez ici pour le configurer dans un format accepté."</string>
+    <string name="ext_media_unsupported_notification_message" msgid="6121601473787888589">"Cet appareil n\'est pas compatible avec le support \"<xliff:g id="NAME">%s</xliff:g>\". Appuyez ici pour le configurer dans un format accepté."</string>
     <string name="ext_media_unsupported_notification_message" product="tv" msgid="3725436899820390906">"Cet appareil n\'est pas compatible avec cette <xliff:g id="NAME">%s</xliff:g>. Sélectionnez cette option pour la configurer dans un format accepté."</string>
     <string name="ext_media_badremoval_notification_title" msgid="3206248947375505416">"Retrait inattendu de mémoire \"<xliff:g id="NAME">%s</xliff:g>\""</string>
     <string name="ext_media_badremoval_notification_message" msgid="8556885808951260574">"Éjectez le périphérique externe avant de le retirer pour éviter toute perte de contenu"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index d4b800a..6afe603 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1895,10 +1895,10 @@
     <string name="autofill_save_title_with_type" msgid="8637809388029313305">"<xliff:g id="TYPE">%1$s</xliff:g> को &lt;b&gt;<xliff:g id="LABEL">%2$s</xliff:g>&lt;/b&gt; में सेव करें?"</string>
     <string name="autofill_save_title_with_2types" msgid="5214035651838265325">"<xliff:g id="TYPE_0">%1$s</xliff:g> और <xliff:g id="TYPE_1">%2$s</xliff:g> को &lt;b&gt;<xliff:g id="LABEL">%3$s</xliff:g>&lt;/b&gt; में सेव करें?"</string>
     <string name="autofill_save_title_with_3types" msgid="6943161834231458441">"<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> और <xliff:g id="TYPE_2">%3$s</xliff:g> को &lt;b&gt;<xliff:g id="LABEL">%4$s</xliff:g>&lt;/b&gt; में सेव करें?"</string>
-    <string name="autofill_update_title" msgid="4879673117448810818">"&lt;b&gt;<xliff:g id="LABEL">%1$s</xliff:g>&lt;/b&gt;? में अपडेट करें?"</string>
-    <string name="autofill_update_title_with_type" msgid="339733442087186755">"<xliff:g id="TYPE">%1$s</xliff:g> को to &lt;b&gt;<xliff:g id="LABEL">%2$s</xliff:g>&lt;/b&gt; में अपडेट करें?"</string>
+    <string name="autofill_update_title" msgid="4879673117448810818">"&lt;b&gt;<xliff:g id="LABEL">%1$s</xliff:g>&lt;/b&gt; में अपडेट करें?"</string>
+    <string name="autofill_update_title_with_type" msgid="339733442087186755">"<xliff:g id="TYPE">%1$s</xliff:g> को &lt;b&gt;<xliff:g id="LABEL">%2$s</xliff:g>&lt;/b&gt; में अपडेट करें?"</string>
     <string name="autofill_update_title_with_2types" msgid="6321714204167424745">"<xliff:g id="TYPE_0">%1$s</xliff:g> और <xliff:g id="TYPE_1">%2$s</xliff:g> को &lt;b&gt;<xliff:g id="LABEL">%3$s</xliff:g>&lt;/b&gt; में अपडेट करें?"</string>
-    <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> और <xliff:g id="TYPE_2">%3$s</xliff:g> को &lt;b&gt;<xliff:g id="LABEL">%4$s</xliff:g>&lt;/b&gt; में अपडेट करें."</string>
+    <string name="autofill_update_title_with_3types" msgid="5866735124066629287">"<xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> और <xliff:g id="TYPE_2">%3$s</xliff:g> को &lt;b&gt;<xliff:g id="LABEL">%4$s</xliff:g>&lt;/b&gt; में अपडेट करें?"</string>
     <string name="autofill_save_yes" msgid="6398026094049005921">"सेव करें"</string>
     <string name="autofill_save_no" msgid="2625132258725581787">"नहीं, धन्यवाद"</string>
     <string name="autofill_update_yes" msgid="310358413273276958">"अपडेट करें"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 8b3f287..6a5f287 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -514,7 +514,7 @@
     <string name="permdesc_imagesWrite" msgid="7073662756617474375">"Թույլ է տալիս հավելվածին փոփոխել ձեր լուսանկարների հավաքածուն:"</string>
     <string name="permlab_mediaLocation" msgid="8675148183726247864">"ճանաչել տեղադրության մասին տվյալները մեդիա բովանդակության հավաքածուից"</string>
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"Թույլ է տալիս հավելվածին ճանաչել տեղադրության մասին տվյալները ձեր մեդիա բովանդակության հավաքածուից:"</string>
-    <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Կենսաչափական սարք չի գտնվել"</string>
+    <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Կենսաչափական սարքը հասանելի չէ"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Մատնահետքը հայտնաբերվել է մասամբ: Փորձեք նորից:"</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Չհաջողվեց մշակել մատնահետքը: Նորից փորձեք:"</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Մատնահետքերի սենսորն աղտոտված է: Մաքրեք այն և փորձեք նորից:"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 4cada60..4915111 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -284,7 +284,7 @@
     <string name="permgrouprequest_sms" msgid="7168124215838204719">"SMS メッセージの送信と表示を &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; に許可しますか?"</string>
     <string name="permgrouplab_storage" msgid="1971118770546336966">"ストレージ"</string>
     <string name="permgroupdesc_storage" msgid="637758554581589203">"端末内の写真、メディア、ファイルへのアクセス"</string>
-    <string name="permgrouprequest_storage" msgid="7885942926944299560">"端末内の写真、メディア、ファイルへのアクセスを &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; に許可しますか?"</string>
+    <string name="permgrouprequest_storage" msgid="7885942926944299560">"端末内の写真、メディア、ファイルへのアクセスを「&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;」に許可しますか?"</string>
     <string name="permgrouplab_microphone" msgid="171539900250043464">"マイク"</string>
     <string name="permgroupdesc_microphone" msgid="4988812113943554584">"音声の録音"</string>
     <string name="permgrouprequest_microphone" msgid="9167492350681916038">"音声の録音を &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; に許可しますか?"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index dca94ff..e228d35 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -284,7 +284,7 @@
     <string name="permgrouprequest_sms" msgid="7168124215838204719">"ಎಸ್‌ಎಂಎಸ್‌ ಸಂದೇಶಗಳನ್ನು ಕಳುಹಿಸಲು ಮತ್ತು ವೀಕ್ಷಿಸಲು &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ಗೆ ಅನುಮತಿಸಬೇಕೇ?"</string>
     <string name="permgrouplab_storage" msgid="1971118770546336966">"ಸಂಗ್ರಹಣೆ"</string>
     <string name="permgroupdesc_storage" msgid="637758554581589203">"ಸಾಧನದಲ್ಲಿ ಫೋಟೋಗಳು, ಮಾಧ್ಯಮ ಮತ್ತು ಫೈಲ್‌ಗಳನ್ನು ಪ್ರವೇಶಿಸಲು"</string>
-    <string name="permgrouprequest_storage" msgid="7885942926944299560">"ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿ ಫೋಟೋಗಳು, ಮಾಧ್ಯಮ ಮತ್ತು ಫೈಲ್‌ಗಳನ್ನು ಪ್ರವೇಶಿಸಲು &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ಗೆ ಅನುಮತಿಸಬೇಕೇ?"</string>
+    <string name="permgrouprequest_storage" msgid="7885942926944299560">"ಸಾಧನದಲ್ಲಿ ಫೋಟೋಗಳು, ಮಾಧ್ಯಮ, ಫೈಲ್‌ಗಳನ್ನು ಪ್ರವೇಶಿಸಲು &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ಗೆ ಅನುಮತಿಸಬೇಕೇ?"</string>
     <string name="permgrouplab_microphone" msgid="171539900250043464">"ಮೈಕ್ರೋಫೋನ್‌"</string>
     <string name="permgroupdesc_microphone" msgid="4988812113943554584">"ಆಡಿಯೊ ರೆಕಾರ್ಡ್ ಮಾಡಿ"</string>
     <string name="permgrouprequest_microphone" msgid="9167492350681916038">"ಆಡಿಯೋ ರೆಕಾರ್ಡ್‌ ಮಾಡಲು &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ಗೆ ಅನುಮತಿಸಬೇಕೇ?"</string>
diff --git a/core/res/res/values-night/colors.xml b/core/res/res/values-night/colors.xml
index 351f8ea..6bbd258 100644
--- a/core/res/res/values-night/colors.xml
+++ b/core/res/res/values-night/colors.xml
@@ -27,5 +27,5 @@
     <color name="notification_default_color_dark">#ddffffff</color>
 
     <!-- The background color of a notification card. -->
-    <color name="notification_material_background_color">@*android:color/material_grey_900</color>
+    <color name="notification_material_background_color">@color/black</color>
 </resources>
\ No newline at end of file
diff --git a/core/res/res/values-night/themes_device_defaults.xml b/core/res/res/values-night/themes_device_defaults.xml
index 5e3675a..c8d4d05 100644
--- a/core/res/res/values-night/themes_device_defaults.xml
+++ b/core/res/res/values-night/themes_device_defaults.xml
@@ -51,4 +51,7 @@
           -->
     <!-- DeviceDefault theme for a window that should look like the Settings app.  -->
     <style name="Theme.DeviceDefault.Settings" parent="Theme.DeviceDefault"/>
+
+    <!-- Theme for the dialog shown when an app crashes or ANRs. -->
+    <style name="Theme.DeviceDefault.Dialog.AppError" parent="Theme.DeviceDefault.Dialog.Alert" />
 </resources>
diff --git a/core/res/res/values-night/values.xml b/core/res/res/values-night/values.xml
index 4eb2ff3..45cf0f0 100644
--- a/core/res/res/values-night/values.xml
+++ b/core/res/res/values-night/values.xml
@@ -26,7 +26,7 @@
         <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
 
         <!-- QS panel background -->
-        <item name="colorBackgroundFloating">@color/material_grey_900</item>
+        <item name="colorBackgroundFloating">@color/black</item>
 
         <!-- volume background -->
         <item name="panelColorBackground">@color/material_grey_800</item>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index e31f161..c14bce4 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -290,7 +290,7 @@
     <string name="permgrouprequest_sms" msgid="7168124215838204719">"Разрешить приложению &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; отправлять и просматривать SMS?"</string>
     <string name="permgrouplab_storage" msgid="1971118770546336966">"Хранилище"</string>
     <string name="permgroupdesc_storage" msgid="637758554581589203">"доступ к фото, мультимедиа и файлам на вашем устройстве"</string>
-    <string name="permgrouprequest_storage" msgid="7885942926944299560">"Разрешить приложению &lt;b&gt;\"<xliff:g id="APP_NAME">%1$s</xliff:g>\"&lt;/b&gt; доступ к фото, мультимедиа и файлам на устройстве?"</string>
+    <string name="permgrouprequest_storage" msgid="7885942926944299560">"Разрешить приложению &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ к фото, мультимедиа и файлам на устройстве?"</string>
     <string name="permgrouplab_microphone" msgid="171539900250043464">"Микрофон"</string>
     <string name="permgroupdesc_microphone" msgid="4988812113943554584">"записывать аудио"</string>
     <string name="permgrouprequest_microphone" msgid="9167492350681916038">"Разрешить приложению &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; записывать аудио?"</string>
@@ -305,7 +305,7 @@
     <string name="permgrouprequest_phone" msgid="9166979577750581037">"Разрешить приложению &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; совершать звонки и управлять ими?"</string>
     <string name="permgrouplab_sensors" msgid="416037179223226722">"Нательные датчики"</string>
     <string name="permgroupdesc_sensors" msgid="7147968539346634043">"доступ к данным датчиков о состоянии организма"</string>
-    <string name="permgrouprequest_sensors" msgid="6349806962814556786">"Разрешить приложению &lt;b&gt;\"<xliff:g id="APP_NAME">%1$s</xliff:g>\"&lt;/b&gt; доступ к данным датчиков о состоянии организма?"</string>
+    <string name="permgrouprequest_sensors" msgid="6349806962814556786">"Разрешить приложению &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ к данным датчиков о состоянии организма?"</string>
     <string name="permgrouplab_aural" msgid="965607064083134896">"Музыка"</string>
     <string name="permgroupdesc_aural" msgid="4870189506255958055">"доступ к музыке"</string>
     <string name="permgrouprequest_aural" msgid="6787926123071735620">"Разрешить приложению &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; доступ к музыке?"</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index 8b89a97..0f353f2 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -514,8 +514,7 @@
     <string name="permdesc_imagesWrite" msgid="7073662756617474375">"ඔබගේ ඡායාරූප එකතුව වෙනස් කිරීමට යෙදුමට ඉඩ දෙයි."</string>
     <string name="permlab_mediaLocation" msgid="8675148183726247864">"ඔබගේ මාධ්‍ය එකතුවෙන් ස්ථාන කියවන්න"</string>
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"ඔබගේ මාධ්‍ය එකතුවෙන් ස්ථාන කියවීමට යෙදුමට ඉඩ දෙයි."</string>
-    <!-- no translation found for biometric_error_hw_unavailable (645781226537551036) -->
-    <skip />
+    <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"ජීවමිතික දෘඪාංග ලබා ගත නොහැකිය"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"ඇඟිලි සලකුණ අඩ වශයෙන් අනාවරණය කර ගැනිණි. කරුණාකර නැවත උත්සාහ කරන්න."</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"ඇඟිලි සලකුණ පිරිසැකසීමට නොහැකි විය. කරුණාකර නැවත උත්සාහ කරන්න."</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"ඇඟිලි සලකුණු සංවේදකය අපිරිසිදුයි. කරුණාකර පිරිසිදු කර නැවත උත්සාහ කරන්න."</string>
@@ -523,8 +522,7 @@
     <string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"ඇඟිල්ල වඩා සෙමෙන් ගෙන යන ලදි. කරුණාකර නැවත උත්සාහ කරන්න."</string>
   <string-array name="fingerprint_acquired_vendor">
   </string-array>
-    <!-- no translation found for biometric_not_recognized (5770511773560736082) -->
-    <skip />
+    <string name="biometric_not_recognized" msgid="5770511773560736082">"හඳුනා නොගන්නා ලදී"</string>
     <string name="fingerprint_authenticated" msgid="5309333983002526448">"ඇඟිලි සලකුණ සත්‍යාපනය කරන ලදී"</string>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"ඇඟිලි සලකුණු දෘඪාංගය ලද නොහැකිය."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"ඇඟිලි සලකුණ ගබඩා කළ නොහැක. දැනට පවතින ඇඟිලි සලකුණක් ඉවත් කරන්න."</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index b175f75..35592a6 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -284,7 +284,7 @@
     <string name="permgrouprequest_sms" msgid="7168124215838204719">"மெசேஜ்களை அனுப்பவும், பார்க்கவும் &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ஆப்ஸை அனுமதிக்கவா?"</string>
     <string name="permgrouplab_storage" msgid="1971118770546336966">"சேமிப்பிடம்"</string>
     <string name="permgroupdesc_storage" msgid="637758554581589203">"உங்கள் சாதனத்தில் உள்ள படங்கள், மீடியா மற்றும் கோப்புகளை அணுக வேண்டும்"</string>
-    <string name="permgrouprequest_storage" msgid="7885942926944299560">"உங்கள் சாதனத்திலுள்ள படங்கள், மீடியா, ஃபைல்கள் ஆகியவற்றை அணுகுவதற்கு &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; பயன்பாட்டை அனுமதிக்கவா?"</string>
+    <string name="permgrouprequest_storage" msgid="7885942926944299560">"உங்கள் சாதனத்திலுள்ள படங்கள், மீடியா, ஃபைல்கள் ஆகியவற்றை அணுகுவதற்கு &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ஆப்ஸை அனுமதிக்கவா?"</string>
     <string name="permgrouplab_microphone" msgid="171539900250043464">"மைக்ரோஃபோன்"</string>
     <string name="permgroupdesc_microphone" msgid="4988812113943554584">"ஒலிப் பதிவு செய்யலாம்"</string>
     <string name="permgrouprequest_microphone" msgid="9167492350681916038">"ஆடியோவைப் பதிவு செய்ய &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; பயன்பாட்டை அனுமதிக்கவா?"</string>
diff --git a/core/res/res/values-television/themes.xml b/core/res/res/values-television/themes.xml
index 377982a..0712cbc 100644
--- a/core/res/res/values-television/themes.xml
+++ b/core/res/res/values-television/themes.xml
@@ -15,7 +15,7 @@
 -->
 <resources>
     <style name="Theme.Dialog.Alert" parent="Theme.Leanback.Light.Dialog.Alert" />
-    <style name="Theme.Dialog.AppError" parent="Theme.Leanback.Dialog.AppError" />
+    <style name="Theme.DeviceDefault.Dialog.AppError" parent="Theme.Leanback.Dialog.AppError" />
     <style name="Theme.Holo.Dialog.Alert" parent="Theme.Leanback.Dialog.Alert" />
     <style name="Theme.Holo.Light.Dialog.Alert" parent="Theme.Leanback.Light.Dialog.Alert" />
     <style name="Theme.Material.Dialog.Alert" parent="Theme.Leanback.Dialog.Alert" />
diff --git a/core/res/res/values-watch/themes.xml b/core/res/res/values-watch/themes.xml
index 04df180..1be47ba 100644
--- a/core/res/res/values-watch/themes.xml
+++ b/core/res/res/values-watch/themes.xml
@@ -15,7 +15,7 @@
 -->
 <resources>
     <!-- Theme for the dialog shown when an app crashes or ANRs. Override to make it dark. -->
-    <style name="Theme.Dialog.AppError" parent="Theme.DeviceDefault.Dialog.Alert">
+    <style name="Theme.DeviceDefault.Dialog.AppError" parent="Theme.DeviceDefault.Dialog.Alert">
         <item name="windowContentTransitions">false</item>
         <item name="windowActivityTransitions">false</item>
         <item name="windowCloseOnTouchOutside">false</item>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 0b04e08..966a5a5 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -272,9 +272,9 @@
     <string name="permgrouprequest_contacts" msgid="6032805601881764300">"允许&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;访问您的通讯录吗?"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"位置信息"</string>
     <string name="permgroupdesc_location" msgid="1346617465127855033">"获取此设备的位置信息"</string>
-    <string name="permgrouprequest_location" msgid="3788275734953323491">"允许&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;获取此设备的位置信息吗?"</string>
+    <string name="permgrouprequest_location" msgid="3788275734953323491">"要允许“<xliff:g id="APP_NAME">%1$s</xliff:g>”获取此设备的位置信息吗?"</string>
     <string name="permgrouprequestdetail_location" msgid="1113400215566814664">"只有当您使用该应用时,该应用才有权获取位置信息。"</string>
-    <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"一律允许&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;获取此设备的位置信息吗?"</string>
+    <string name="permgroupbackgroundrequest_location" msgid="8461841153030844390">"一律允许“<xliff:g id="APP_NAME">%1$s</xliff:g>”获取此设备的位置信息吗?"</string>
     <string name="permgroupbackgroundrequestdetail_location" msgid="1715668276378108654">"即使您并未使用该应用,该应用也将始终有权获取位置信息。"</string>
     <string name="permgrouplab_calendar" msgid="5863508437783683902">"日历"</string>
     <string name="permgroupdesc_calendar" msgid="3889615280211184106">"访问您的日历"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index bd4ea2a..bd36ed6 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -514,7 +514,7 @@
     <string name="permdesc_imagesWrite" msgid="7073662756617474375">"允許應用程式修改你的相片收藏。"</string>
     <string name="permlab_mediaLocation" msgid="8675148183726247864">"讀取你的媒體收藏的位置資訊"</string>
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"允許應用程式讀取你的媒體收藏的位置資訊。"</string>
-    <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"找不到生物特徵辨識硬體"</string>
+    <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"無法使用生物特徵辨識硬體"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"僅偵測到部分指紋,請再試一次。"</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"無法處理指紋,請再試一次。"</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"指紋感應器有髒汙。請清潔感應器,然後再試一次。"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 3fed8a3..2de2b9e 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3573,6 +3573,11 @@
              {@link android.accessibilityservice.AccessibilityService#setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo)
              android.accessibilityservice.AccessibilityService.setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo)}. -->
         <attr name="notificationTimeout" format="integer" />
+        <!-- The minimum timeout in milliseconds that UI controls need to remain on the screen.
+             This setting can be changed at runtime by calling
+             {@link android.accessibilityservice.AccessibilityService#setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo)
+             android.accessibilityservice.AccessibilityService.setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo)}. -->
+        <attr name="minimumUiTimeout" format="integer" />
         <!-- Additional flags as specified in
              {@link android.accessibilityservice.AccessibilityServiceInfo}.
              This setting can be changed at runtime by calling
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index bf7e068..8bca211 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -172,4 +172,7 @@
 
     <!-- Accessibility action identifier for {@link android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_HIDE_TOOLTIP}. -->
     <item type="id" name="accessibilityActionHideTooltip" />
+
+  <!-- Accessibility action to notify a window there is an outside touch. -->
+  <item type="id" name="accessibilityActionOutsideTouch" />
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index fa31dce..c751af3 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2914,6 +2914,7 @@
     <public-group type="attr" first-id="0x0101058d">
         <!-- @hide For use by platform and tools only. Developers should not specify this value. -->
         <public name="usesNonSdkApi" />
+        <public name="minimumUiTimeout" />
     </public-group>
 
     <public-group type="style" first-id="0x010302e2">
diff --git a/core/res/res/values/styles_permission_controller.xml b/core/res/res/values/styles_permission_controller.xml
index 339f9c7..e6e0de3 100644
--- a/core/res/res/values/styles_permission_controller.xml
+++ b/core/res/res/values/styles_permission_controller.xml
@@ -15,8 +15,8 @@
   limitations under the License.
   -->
 
-<!-- styles for the permission grant dialog. -->
 <resources>
+    <!-- styles for the permission grant dialog. -->
     <style name="PermissionGrantDialog">
         <item name="background">?attr/windowBackground</item>
         <item name="elevation">?attr/windowElevation</item>
@@ -95,4 +95,37 @@
         <item name="layout_marginEnd">16dp</item>
         <item name="layout_marginBottom">4dp</item>
     </style>
+
+    <!-- styles for the permission review screen. -->
+    <style name="PermissionReviewDescription">
+        <item name="layout_marginTop">20dp</item>
+        <item name="layout_marginStart">24dp</item>
+        <item name="layout_marginBottom">16dp</item>
+        <item name="layout_marginEnd">24dp</item>
+    </style>
+
+    <style name="PermissionReviewTitleIcon">
+        <item name="layout_marginTop">4dp</item>
+        <item name="layout_width">36dp</item>
+        <item name="layout_height">36dp</item>
+        <item name="scaleType">fitCenter</item>
+    </style>
+
+    <style name="PermissionReviewTitleMessage"
+           parent="@style/TextAppearance.DeviceDefault">
+        <item name="paddingStart">22dp</item>
+        <item name="textSize">20sp</item>
+        <item name="textColor">?attr/textColorPrimary</item>
+    </style>
+
+    <style name="PermissionReviewSettings">
+        <item name="layout_marginStart">8dp</item>
+        <item name="layout_marginEnd">8dp</item>
+    </style>
+
+    <style name="PermissionReviewButtonBar">
+        <item name="layout_marginStart">24dp</item>
+        <item name="layout_marginEnd">16dp</item>
+        <item name="layout_marginBottom">4dp</item>
+    </style>
 </resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 92cca72..7b6e064 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -218,6 +218,7 @@
   <java-symbol type="id" name="selection_end_handle" />
   <java-symbol type="id" name="insertion_handle" />
   <java-symbol type="id" name="accessibilityActionClickOnClickableSpan" />
+  <java-symbol type="id" name="accessibilityActionOutsideTouch" />
   <java-symbol type="id" name="camera" />
   <java-symbol type="id" name="mic" />
   <java-symbol type="id" name="overlay" />
@@ -2099,7 +2100,7 @@
   <java-symbol type="string" name="vpn_lockdown_error" />
   <java-symbol type="string" name="vpn_lockdown_config" />
   <java-symbol type="string" name="wallpaper_binding_label" />
-  <java-symbol type="style" name="Theme.Dialog.AppError" />
+  <java-symbol type="style" name="Theme.DeviceDefault.Dialog.AppError" />
   <java-symbol type="style" name="Theme.Leanback.Dialog.Alert" />
   <java-symbol type="style" name="Theme.Toast" />
   <java-symbol type="xml" name="storage_list" />
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 3937af5..a7530ce 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -869,13 +869,6 @@
     <!-- System themes -->
     <eat-comment />
 
-    <!-- Theme for the dialog shown when an app crashes or ANRs. -->
-    <style name="Theme.Dialog.AppError" parent="Theme.DeviceDefault.Light.Dialog.Alert">
-        <item name="windowContentTransitions">false</item>
-        <item name="windowActivityTransitions">false</item>
-        <item name="windowCloseOnTouchOutside">false</item>
-    </style>
-
     <!-- Special theme for the recent apps dialog, to allow customization
          with overlays. -->
     <style name="Theme.Dialog.RecentApplications" parent="Theme.DeviceDefault.Light.Dialog">
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index 14e5082..92096ab 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -719,6 +719,13 @@
         <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
     </style>
 
+    <!-- Theme for the dialog shown when an app crashes or ANRs. -->
+    <style name="Theme.DeviceDefault.Dialog.AppError" parent="Theme.DeviceDefault.Light.Dialog.Alert">
+        <item name="windowContentTransitions">false</item>
+        <item name="windowActivityTransitions">false</item>
+        <item name="windowCloseOnTouchOutside">false</item>
+    </style>
+
     <style name="Theme.DeviceDefault.SearchBar" parent="Theme.Material.SearchBar">
         <!-- Color palette -->
         <item name="colorPrimary">@color/primary_device_default_dark</item>
diff --git a/core/res/res/values/themes_permission_controller.xml b/core/res/res/values/themes_permission_controller.xml
index 3bc93cd..369cee3 100644
--- a/core/res/res/values/themes_permission_controller.xml
+++ b/core/res/res/values/themes_permission_controller.xml
@@ -15,8 +15,8 @@
   limitations under the License.
   -->
 
-<!-- themes for the permission grant dialog. -->
 <resources>
+    <!-- themes for the permission grant dialog. -->
     <style name="Theme.DeviceDefault.PermissionGrantApp"
            parent="@style/Theme.DeviceDefault.Light.Panel">
         <item name="windowIsFloating">false</item>
@@ -32,4 +32,13 @@
         <item name="checkboxStyle">@style/PermissionGrantCheckbox</item>
         <item name="buttonBarStyle">@style/PermissionGrantButtonBar</item>
     </style>
+
+    <!-- themes for the permission review dialog. -->
+    <style name="Theme.DeviceDefault.PermissionReviewApp"
+           parent="@style/Theme.DeviceDefault.Settings">
+        <item name="windowActionBar">false</item>
+        <item name="windowNoTitle">true</item>
+        <item name="titleTextStyle">@style/PermissionReviewTitleMessage</item>
+        <item name="buttonBarStyle">@style/PermissionReviewButtonBar</item>
+    </style>
 </resources>
diff --git a/core/tests/coretests/src/android/hardware/display/BrightnessConfigurationTest.java b/core/tests/coretests/src/android/hardware/display/BrightnessConfigurationTest.java
index 5ef30a8..dcc51e1 100644
--- a/core/tests/coretests/src/android/hardware/display/BrightnessConfigurationTest.java
+++ b/core/tests/coretests/src/android/hardware/display/BrightnessConfigurationTest.java
@@ -48,8 +48,8 @@
 
     @Test
     public void testSetCurveIsUnmodified() {
-        BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder();
-        builder.setCurve(LUX_LEVELS, NITS_LEVELS);
+        BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder(
+                LUX_LEVELS, NITS_LEVELS);
         BrightnessConfiguration config = builder.build();
         Pair<float[], float[]> curve = config.getCurve();
         assertArrayEquals(LUX_LEVELS, curve.first, "lux");
@@ -58,45 +58,33 @@
 
     @Test(expected = IllegalArgumentException.class)
     public void testCurveMustHaveZeroLuxPoint() {
-        BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder();
         float[] lux = Arrays.copyOf(LUX_LEVELS, LUX_LEVELS.length);
         lux[0] = 1f;
-        builder.setCurve(lux, NITS_LEVELS);
-    }
-
-    @Test(expected = IllegalStateException.class)
-    public void testCurveMustBeSet() {
-        BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder();
-        builder.build();
+        new BrightnessConfiguration.Builder(lux, NITS_LEVELS);
     }
 
     @Test(expected = NullPointerException.class)
     public void testCurveMustNotHaveNullArrays() {
-        BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder();
-        builder.setCurve(null, null);
+        new BrightnessConfiguration.Builder(null, null);
     }
 
     @Test(expected = IllegalArgumentException.class)
     public void testCurveMustNotHaveEmptyArrays() {
-        BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder();
-        builder.setCurve(new float[0], new float[0]);
+        new BrightnessConfiguration.Builder(new float[0], new float[0]);
     }
 
     @Test
     public void testCurveMustNotHaveArraysOfDifferentLengths() {
         assertThrows(IllegalArgumentException.class, () -> {
-            BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder();
             float[] lux = Arrays.copyOf(LUX_LEVELS, LUX_LEVELS.length + 1);
             lux[lux.length - 1] = lux[lux.length - 2] + 1;
-            boolean exceptionThrown = false;
-            builder.setCurve(lux, NITS_LEVELS);
+            new BrightnessConfiguration.Builder(lux, NITS_LEVELS);
         });
 
         assertThrows(IllegalArgumentException.class, () -> {
-            BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder();
             float[] nits = Arrays.copyOf(NITS_LEVELS, NITS_LEVELS.length + 1);
             nits[nits.length - 1] = nits[nits.length - 2] + 1;
-            builder.setCurve(LUX_LEVELS, nits);
+            new BrightnessConfiguration.Builder(LUX_LEVELS, nits);
         });
     }
 
@@ -105,23 +93,21 @@
         assertThrows(IllegalArgumentException.class, () -> {
             float[] lux = Arrays.copyOf(LUX_LEVELS, LUX_LEVELS.length);
             lux[lux.length - 1] = Float.NaN;
-            BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder();
-            builder.setCurve(lux, NITS_LEVELS);
+            new BrightnessConfiguration.Builder(lux, NITS_LEVELS);
         });
 
         assertThrows(IllegalArgumentException.class, () -> {
             float[] nits = Arrays.copyOf(NITS_LEVELS, NITS_LEVELS.length);
             nits[nits.length - 1] = Float.NaN;
-            BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder();
-            builder.setCurve(LUX_LEVELS, nits);
+            new BrightnessConfiguration.Builder(LUX_LEVELS, nits);
         });
     }
 
 
     @Test
     public void testParceledConfigIsEquivalent() {
-        BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder();
-        builder.setCurve(LUX_LEVELS, NITS_LEVELS);
+        BrightnessConfiguration.Builder builder =
+                new BrightnessConfiguration.Builder(LUX_LEVELS, NITS_LEVELS);
         BrightnessConfiguration config = builder.build();
         Parcel p = Parcel.obtain();
         p.writeParcelable(config, 0 /*flags*/);
@@ -133,12 +119,11 @@
 
     @Test
     public void testEquals() {
-        BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder();
-        builder.setCurve(LUX_LEVELS, NITS_LEVELS);
+        BrightnessConfiguration.Builder builder =
+                new BrightnessConfiguration.Builder(LUX_LEVELS, NITS_LEVELS);
         BrightnessConfiguration baseConfig = builder.build();
 
-        builder = new BrightnessConfiguration.Builder();
-        builder.setCurve(LUX_LEVELS, NITS_LEVELS);
+        builder = new BrightnessConfiguration.Builder(LUX_LEVELS, NITS_LEVELS);
         BrightnessConfiguration identicalConfig = builder.build();
         assertEquals(baseConfig, identicalConfig);
         assertEquals("hashCodes must be equal for identical configs",
@@ -146,15 +131,13 @@
 
         float[] lux = Arrays.copyOf(LUX_LEVELS, LUX_LEVELS.length);
         lux[lux.length - 1] = lux[lux.length - 1] * 2;
-        builder = new BrightnessConfiguration.Builder();
-        builder.setCurve(lux, NITS_LEVELS);
+        builder = new BrightnessConfiguration.Builder(lux, NITS_LEVELS);
         BrightnessConfiguration luxDifferConfig = builder.build();
         assertNotEquals(baseConfig, luxDifferConfig);
 
         float[] nits = Arrays.copyOf(NITS_LEVELS, NITS_LEVELS.length);
         nits[nits.length - 1] = nits[nits.length - 1] * 2;
-        builder = new BrightnessConfiguration.Builder();
-        builder.setCurve(LUX_LEVELS, nits);
+        builder = new BrightnessConfiguration.Builder(LUX_LEVELS, nits);
         BrightnessConfiguration nitsDifferConfig = builder.build();
         assertNotEquals(baseConfig, nitsDifferConfig);
     }
diff --git a/core/tests/coretests/src/android/os/SetPersistentVrThreadTest.java b/core/tests/coretests/src/android/os/SetPersistentVrThreadTest.java
index 920988b..9e44554 100644
--- a/core/tests/coretests/src/android/os/SetPersistentVrThreadTest.java
+++ b/core/tests/coretests/src/android/os/SetPersistentVrThreadTest.java
@@ -24,7 +24,6 @@
 import android.provider.Settings;
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Log;
 
 /**
  * Tests ActivityManager#setPersistentVrThread and ActivityManager#setVrThread's
@@ -76,9 +75,11 @@
     }
 
     private void setPersistentVrModeEnabled(boolean enable) throws Throwable {
-        mVrManager.setPersistentVrModeEnabled(enable);
-        // Allow the system time to send out callbacks for persistent VR mode.
-        Thread.sleep(200);
+        if (mVrManager != null) {
+            mVrManager.setPersistentVrModeEnabled(enable);
+            // Allow the system time to send out callbacks for persistent VR mode.
+            Thread.sleep(200);
+        }
     }
 
     @SmallTest
diff --git a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java b/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java
index f731a4a..3064afa 100644
--- a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java
+++ b/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java
@@ -71,11 +71,15 @@
     private static final Locale LOCALE_FR = new Locale("fr");
     private static final Locale LOCALE_FR_CA = new Locale("fr", "CA");
     private static final Locale LOCALE_HI = new Locale("hi");
+    private static final Locale LOCALE_JA = new Locale("ja");
     private static final Locale LOCALE_JA_JP = new Locale("ja", "JP");
     private static final Locale LOCALE_ZH_CN = new Locale("zh", "CN");
     private static final Locale LOCALE_ZH_TW = new Locale("zh", "TW");
     private static final Locale LOCALE_IN = new Locale("in");
     private static final Locale LOCALE_ID = new Locale("id");
+    private static final Locale LOCALE_TH = new Locale("ht");
+    private static final Locale LOCALE_TH_TH = new Locale("ht", "TH");
+    private static final Locale LOCALE_TH_TH_TH = new Locale("ht", "TH", "TH");
     private static final String SUBTYPE_MODE_KEYBOARD = "keyboard";
     private static final String SUBTYPE_MODE_VOICE = "voice";
     private static final String SUBTYPE_MODE_HANDWRITING = "handwriting";
@@ -1083,6 +1087,122 @@
     }
 
     @Test
+    public void testGetSuitableLocalesForSpellChecker() throws Exception {
+        {
+            final ArrayList<Locale> locales =
+                    InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_EN_US);
+            assertEquals(3, locales.size());
+            assertEquals(LOCALE_EN_US, locales.get(0));
+            assertEquals(LOCALE_EN_GB, locales.get(1));
+            assertEquals(LOCALE_EN, locales.get(2));
+        }
+
+        {
+            final ArrayList<Locale> locales =
+                    InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_EN_GB);
+            assertEquals(3, locales.size());
+            assertEquals(LOCALE_EN_GB, locales.get(0));
+            assertEquals(LOCALE_EN_US, locales.get(1));
+            assertEquals(LOCALE_EN, locales.get(2));
+        }
+
+        {
+            final ArrayList<Locale> locales =
+                    InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_EN);
+            assertEquals(3, locales.size());
+            assertEquals(LOCALE_EN, locales.get(0));
+            assertEquals(LOCALE_EN_US, locales.get(1));
+            assertEquals(LOCALE_EN_GB, locales.get(2));
+        }
+
+        {
+            final ArrayList<Locale> locales =
+                    InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_EN_IN);
+            assertEquals(4, locales.size());
+            assertEquals(LOCALE_EN_IN, locales.get(0));
+            assertEquals(LOCALE_EN_US, locales.get(1));
+            assertEquals(LOCALE_EN_GB, locales.get(2));
+            assertEquals(LOCALE_EN, locales.get(3));
+        }
+
+        {
+            final ArrayList<Locale> locales =
+                    InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_JA_JP);
+            assertEquals(5, locales.size());
+            assertEquals(LOCALE_JA_JP, locales.get(0));
+            assertEquals(LOCALE_JA, locales.get(1));
+            assertEquals(LOCALE_EN_US, locales.get(2));
+            assertEquals(LOCALE_EN_GB, locales.get(3));
+            assertEquals(Locale.ENGLISH, locales.get(4));
+        }
+
+        // Test 3-letter language code.
+        {
+            final ArrayList<Locale> locales =
+                    InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_FIL_PH);
+            assertEquals(5, locales.size());
+            assertEquals(LOCALE_FIL_PH, locales.get(0));
+            assertEquals(LOCALE_FIL, locales.get(1));
+            assertEquals(LOCALE_EN_US, locales.get(2));
+            assertEquals(LOCALE_EN_GB, locales.get(3));
+            assertEquals(Locale.ENGLISH, locales.get(4));
+        }
+
+        // Test variant.
+        {
+            final ArrayList<Locale> locales =
+                    InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_TH_TH_TH);
+            assertEquals(6, locales.size());
+            assertEquals(LOCALE_TH_TH_TH, locales.get(0));
+            assertEquals(LOCALE_TH_TH, locales.get(1));
+            assertEquals(LOCALE_TH, locales.get(2));
+            assertEquals(LOCALE_EN_US, locales.get(3));
+            assertEquals(LOCALE_EN_GB, locales.get(4));
+            assertEquals(Locale.ENGLISH, locales.get(5));
+        }
+
+        // Test Locale extension.
+        {
+            final Locale localeWithoutVariant = LOCALE_JA_JP;
+            final Locale localeWithVariant = new Locale.Builder()
+                    .setLocale(LOCALE_JA_JP)
+                    .setExtension('x', "android")
+                    .build();
+            assertFalse(localeWithoutVariant.equals(localeWithVariant));
+
+            final ArrayList<Locale> locales =
+                    InputMethodUtils.getSuitableLocalesForSpellChecker(localeWithVariant);
+            assertEquals(5, locales.size());
+            assertEquals(LOCALE_JA_JP, locales.get(0));
+            assertEquals(LOCALE_JA, locales.get(1));
+            assertEquals(LOCALE_EN_US, locales.get(2));
+            assertEquals(LOCALE_EN_GB, locales.get(3));
+            assertEquals(Locale.ENGLISH, locales.get(4));
+        }
+    }
+
+    @Test
+    public void testConstructLocaleFromString() throws Exception {
+        assertEquals(new Locale("en"), InputMethodUtils.constructLocaleFromString("en"));
+        assertEquals(new Locale("en", "US"), InputMethodUtils.constructLocaleFromString("en_US"));
+        assertEquals(new Locale("en", "US", "POSIX"),
+                InputMethodUtils.constructLocaleFromString("en_US_POSIX"));
+
+        // Special rewrite rule for "tl" for versions of Android earlier than Lollipop that did not
+        // support three letter language codes, and used "tl" (Tagalog) as the language string for
+        // "fil" (Filipino).
+        assertEquals(new Locale("fil"), InputMethodUtils.constructLocaleFromString("tl"));
+        assertEquals(new Locale("fil", "PH"), InputMethodUtils.constructLocaleFromString("tl_PH"));
+        assertEquals(new Locale("fil", "PH", "POSIX"),
+                InputMethodUtils.constructLocaleFromString("tl_PH_POSIX"));
+
+        // So far rejecting an invalid/unexpected locale string is out of the scope of this method.
+        assertEquals(new Locale("a"), InputMethodUtils.constructLocaleFromString("a"));
+        assertEquals(new Locale("a b c"), InputMethodUtils.constructLocaleFromString("a b c"));
+        assertEquals(new Locale("en-US"), InputMethodUtils.constructLocaleFromString("en-US"));
+    }
+
+    @Test
     public void testIsSoftInputModeStateVisibleAllowed() {
         // On pre-P devices, SOFT_INPUT_STATE_VISIBLE/SOFT_INPUT_STATE_ALWAYS_VISIBLE are always
         // allowed, regardless of the focused view state.
diff --git a/core/tests/coretests/src/com/android/internal/inputmethod/LocaleUtilsTest.java b/core/tests/coretests/src/com/android/internal/inputmethod/LocaleUtilsTest.java
index 7d0e646..549511a 100644
--- a/core/tests/coretests/src/com/android/internal/inputmethod/LocaleUtilsTest.java
+++ b/core/tests/coretests/src/com/android/internal/inputmethod/LocaleUtilsTest.java
@@ -17,7 +17,6 @@
 package com.android.internal.inputmethod;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
 
 import android.os.LocaleList;
 import android.support.test.filters.SmallTest;
@@ -35,18 +34,6 @@
 
     private static final LocaleUtils.LocaleExtractor<Locale> sIdentityMapper = source -> source;
 
-    private static final Locale LOCALE_EN = new Locale("en");
-    private static final Locale LOCALE_EN_US = new Locale("en", "US");
-    private static final Locale LOCALE_EN_GB = new Locale("en", "GB");
-    private static final Locale LOCALE_EN_IN = new Locale("en", "IN");
-    private static final Locale LOCALE_FIL = new Locale("fil");
-    private static final Locale LOCALE_FIL_PH = new Locale("fil", "PH");
-    private static final Locale LOCALE_JA = new Locale("ja");
-    private static final Locale LOCALE_JA_JP = new Locale("ja", "JP");
-    private static final Locale LOCALE_TH = new Locale("ht");
-    private static final Locale LOCALE_TH_TH = new Locale("ht", "TH");
-    private static final Locale LOCALE_TH_TH_TH = new Locale("ht", "TH", "TH");
-
     @Test
     public void testFilterByLanguageEmptyLanguageList() throws Exception {
         final ArrayList<Locale> availableLocales = new ArrayList<>();
@@ -398,120 +385,4 @@
             assertEquals(availableLocales.get(3), dest.get(0));
         }
     }
-
-    @Test
-    public void testGetSuitableLocalesForSpellChecker() throws Exception {
-        {
-            final ArrayList<Locale> locales =
-                    LocaleUtils.getSuitableLocalesForSpellChecker(LOCALE_EN_US);
-            assertEquals(3, locales.size());
-            assertEquals(LOCALE_EN_US, locales.get(0));
-            assertEquals(LOCALE_EN_GB, locales.get(1));
-            assertEquals(LOCALE_EN, locales.get(2));
-        }
-
-        {
-            final ArrayList<Locale> locales =
-                    LocaleUtils.getSuitableLocalesForSpellChecker(LOCALE_EN_GB);
-            assertEquals(3, locales.size());
-            assertEquals(LOCALE_EN_GB, locales.get(0));
-            assertEquals(LOCALE_EN_US, locales.get(1));
-            assertEquals(LOCALE_EN, locales.get(2));
-        }
-
-        {
-            final ArrayList<Locale> locales =
-                    LocaleUtils.getSuitableLocalesForSpellChecker(LOCALE_EN);
-            assertEquals(3, locales.size());
-            assertEquals(LOCALE_EN, locales.get(0));
-            assertEquals(LOCALE_EN_US, locales.get(1));
-            assertEquals(LOCALE_EN_GB, locales.get(2));
-        }
-
-        {
-            final ArrayList<Locale> locales =
-                    LocaleUtils.getSuitableLocalesForSpellChecker(LOCALE_EN_IN);
-            assertEquals(4, locales.size());
-            assertEquals(LOCALE_EN_IN, locales.get(0));
-            assertEquals(LOCALE_EN_US, locales.get(1));
-            assertEquals(LOCALE_EN_GB, locales.get(2));
-            assertEquals(LOCALE_EN, locales.get(3));
-        }
-
-        {
-            final ArrayList<Locale> locales =
-                    LocaleUtils.getSuitableLocalesForSpellChecker(LOCALE_JA_JP);
-            assertEquals(5, locales.size());
-            assertEquals(LOCALE_JA_JP, locales.get(0));
-            assertEquals(LOCALE_JA, locales.get(1));
-            assertEquals(LOCALE_EN_US, locales.get(2));
-            assertEquals(LOCALE_EN_GB, locales.get(3));
-            assertEquals(Locale.ENGLISH, locales.get(4));
-        }
-
-        // Test 3-letter language code.
-        {
-            final ArrayList<Locale> locales =
-                    LocaleUtils.getSuitableLocalesForSpellChecker(LOCALE_FIL_PH);
-            assertEquals(5, locales.size());
-            assertEquals(LOCALE_FIL_PH, locales.get(0));
-            assertEquals(LOCALE_FIL, locales.get(1));
-            assertEquals(LOCALE_EN_US, locales.get(2));
-            assertEquals(LOCALE_EN_GB, locales.get(3));
-            assertEquals(Locale.ENGLISH, locales.get(4));
-        }
-
-        // Test variant.
-        {
-            final ArrayList<Locale> locales =
-                    LocaleUtils.getSuitableLocalesForSpellChecker(LOCALE_TH_TH_TH);
-            assertEquals(6, locales.size());
-            assertEquals(LOCALE_TH_TH_TH, locales.get(0));
-            assertEquals(LOCALE_TH_TH, locales.get(1));
-            assertEquals(LOCALE_TH, locales.get(2));
-            assertEquals(LOCALE_EN_US, locales.get(3));
-            assertEquals(LOCALE_EN_GB, locales.get(4));
-            assertEquals(Locale.ENGLISH, locales.get(5));
-        }
-
-        // Test Locale extension.
-        {
-            final Locale localeWithoutVariant = LOCALE_JA_JP;
-            final Locale localeWithVariant = new Locale.Builder()
-                    .setLocale(LOCALE_JA_JP)
-                    .setExtension('x', "android")
-                    .build();
-            assertFalse(localeWithoutVariant.equals(localeWithVariant));
-
-            final ArrayList<Locale> locales =
-                    LocaleUtils.getSuitableLocalesForSpellChecker(localeWithVariant);
-            assertEquals(5, locales.size());
-            assertEquals(LOCALE_JA_JP, locales.get(0));
-            assertEquals(LOCALE_JA, locales.get(1));
-            assertEquals(LOCALE_EN_US, locales.get(2));
-            assertEquals(LOCALE_EN_GB, locales.get(3));
-            assertEquals(Locale.ENGLISH, locales.get(4));
-        }
-    }
-
-    @Test
-    public void testConstructLocaleFromString() throws Exception {
-        assertEquals(new Locale("en"), LocaleUtils.constructLocaleFromString("en"));
-        assertEquals(new Locale("en", "US"), LocaleUtils.constructLocaleFromString("en_US"));
-        assertEquals(new Locale("en", "US", "POSIX"),
-                LocaleUtils.constructLocaleFromString("en_US_POSIX"));
-
-        // Special rewrite rule for "tl" for versions of Android earlier than Lollipop that did not
-        // support three letter language codes, and used "tl" (Tagalog) as the language string for
-        // "fil" (Filipino).
-        assertEquals(new Locale("fil"), LocaleUtils.constructLocaleFromString("tl"));
-        assertEquals(new Locale("fil", "PH"), LocaleUtils.constructLocaleFromString("tl_PH"));
-        assertEquals(new Locale("fil", "PH", "POSIX"),
-                LocaleUtils.constructLocaleFromString("tl_PH_POSIX"));
-
-        // So far rejecting an invalid/unexpected locale string is out of the scope of this method.
-        assertEquals(new Locale("a"), LocaleUtils.constructLocaleFromString("a"));
-        assertEquals(new Locale("a b c"), LocaleUtils.constructLocaleFromString("a b c"));
-        assertEquals(new Locale("en-US"), LocaleUtils.constructLocaleFromString("en-US"));
-    }
 }
diff --git a/core/tests/webkit/Android.mk b/core/tests/webkit/Android.mk
deleted file mode 100644
index 45f6957..0000000
--- a/core/tests/webkit/Android.mk
+++ /dev/null
@@ -1,45 +0,0 @@
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# We only want this apk build for tests.
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-
-
-# Include all test java files.
-LOCAL_SRC_FILES := \
-	$(call all-java-files-under, unit_tests_src)
-
-LOCAL_JAVA_LIBRARIES := android.test.runner
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-	android-support-test
-
-LOCAL_PACKAGE_NAME := WebViewLoadingTests
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_CERTIFICATE := platform
-
-LOCAL_COMPATIBILITY_SUITE := device-tests
-
-LOCAL_REQUIRED_MODULES := \
-	WebViewLoadingOnDiskTestApk \
-	WebViewLoadingFromApkTestApk
-
-include $(BUILD_PACKAGE)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/core/tests/webkit/AndroidManifest.xml b/core/tests/webkit/AndroidManifest.xml
deleted file mode 100644
index 42accdf..0000000
--- a/core/tests/webkit/AndroidManifest.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="com.android.webkit.tests"
-          android:sharedUserId="android.uid.system">
-
-    <application>
-        <uses-library android:name="android.test.runner" />
-    </application>
-
-    <instrumentation
-            android:name="android.support.test.runner.AndroidJUnitRunner"
-            android:targetPackage="com.android.webkit.tests"
-            android:label="Frameworks WebView Loader Tests" />
-
-</manifest>
diff --git a/core/tests/webkit/AndroidTest.xml b/core/tests/webkit/AndroidTest.xml
deleted file mode 100644
index 4c50b7d..0000000
--- a/core/tests/webkit/AndroidTest.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<configuration description="Runs Frameworks WebView Loading Tests.">
-    <option name="test-suite-tag" value="apct" />
-    <option name="test-suite-tag" value="apct-instrumentation" />
-    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
-        <option name="test-file-name" value="WebViewLoadingTests.apk" />
-        <option name="test-file-name" value="WebViewLoadingOnDiskTestApk.apk" />
-        <option name="test-file-name" value="WebViewLoadingFromApkTestApk.apk" />
-        <option name="cleanup-apks" value="true" />
-        <option name="alt-dir" value="out" />
-    </target_preparer>
-
-    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
-        <option name="package" value="com.android.webkit.tests" />
-    </test>
-</configuration>
diff --git a/core/tests/webkit/OWNERS b/core/tests/webkit/OWNERS
deleted file mode 100644
index 00e540a..0000000
--- a/core/tests/webkit/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-changwan@google.com
-tobiasjs@google.com
-torne@google.com
diff --git a/core/tests/webkit/apk_with_native_libs/Android.mk b/core/tests/webkit/apk_with_native_libs/Android.mk
deleted file mode 100644
index e18a7e0..0000000
--- a/core/tests/webkit/apk_with_native_libs/Android.mk
+++ /dev/null
@@ -1,71 +0,0 @@
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-MY_PATH := $(LOCAL_PATH)
-
-# Set shared variables
-MY_MODULE_TAGS := optional
-MY_JNI_SHARED_LIBRARIES := libwebviewtest_jni
-MY_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-MY_SRC_FILES := $(call all-java-files-under, src)
-MY_CFLAGS := -Wall -Werror
-MY_SDK_VERSION := system_current
-MY_PROGUARD_ENABLED := disabled
-MY_MULTILIB := both
-
-# Recurse down the file tree.
-include $(call all-subdir-makefiles)
-
-
-
-# Builds an apk containing native libraries that will be unzipped on the device.
-include $(CLEAR_VARS)
-
-LOCAL_PATH := $(MY_PATH)
-LOCAL_PACKAGE_NAME := WebViewLoadingOnDiskTestApk
-LOCAL_MANIFEST_FILE := ondisk/AndroidManifest.xml
-
-LOCAL_MODULE_TAGS := $(MY_MODULE_TAGS)
-LOCAL_JNI_SHARED_LIBRARIES := $(MY_JNI_SHARED_LIBRARIES)
-LOCAL_MODULE_PATH := $(MY_MODULE_PATH)
-LOCAL_SRC_FILES := $(MY_SRC_FILES)
-LOCAL_CFLAGS := $(MY_CFLAGS)
-LOCAL_SDK_VERSION := $(MY_SDK_VERSION)
-LOCAL_PROGUARD_ENABLED := $(MY_PROGUARD_ENABLED)
-LOCAL_MULTILIB := $(MY_MULTILIB)
-LOCAL_COMPATIBILITY_SUITE := device-tests
-
-include $(BUILD_PACKAGE)
-
-
-# Builds an apk containing uncompressed native libraries that have to be
-# accessed through the APK itself on the device.
-include $(CLEAR_VARS)
-
-LOCAL_PATH := $(MY_PATH)
-LOCAL_PACKAGE_NAME := WebViewLoadingFromApkTestApk
-LOCAL_MANIFEST_FILE := inapk/AndroidManifest.xml
-
-LOCAL_MODULE_TAGS := $(MY_MODULE_TAGS)
-LOCAL_JNI_SHARED_LIBRARIES := $(MY_JNI_SHARED_LIBRARIES)
-LOCAL_MODULE_PATH := $(MY_MODULE_PATH)
-LOCAL_SRC_FILES := $(MY_SRC_FILES)
-LOCAL_CFLAGS := $(MY_CFLAGS)
-LOCAL_SDK_VERSION := $(MY_SDK_VERSION)
-LOCAL_PROGUARD_ENABLED := $(MY_PROGUARD_ENABLED)
-LOCAL_MULTILIB := $(MY_MULTILIB)
-LOCAL_COMPATIBILITY_SUITE := device-tests
-
-include $(BUILD_PACKAGE)
diff --git a/core/tests/webkit/apk_with_native_libs/inapk/AndroidManifest.xml b/core/tests/webkit/apk_with_native_libs/inapk/AndroidManifest.xml
deleted file mode 100644
index 868b238..0000000
--- a/core/tests/webkit/apk_with_native_libs/inapk/AndroidManifest.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.webviewloading_test_from_apk"
-    android:versionCode="1"
-    android:versionName="0.0.0.1">
-
-    <application android:label="WebView Loading Test APK"
-      android:multiArch="true"
-      android:extractNativeLibs="false">
-        <meta-data android:name="com.android.webview.WebViewLibrary"
-            android:value="libwebviewtest_jni.so" />
-    </application>
-</manifest>
diff --git a/core/tests/webkit/apk_with_native_libs/jni/Android.mk b/core/tests/webkit/apk_with_native_libs/jni/Android.mk
deleted file mode 100644
index fd5b5eb..0000000
--- a/core/tests/webkit/apk_with_native_libs/jni/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-#
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libwebviewtest_jni
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := WebViewTestJniOnLoad.cpp
-
-LOCAL_C_INCLUDES := $(JNI_H_INCLUDE)
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_MULTILIB := both
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/core/tests/webkit/apk_with_native_libs/jni/WebViewTestJniOnLoad.cpp b/core/tests/webkit/apk_with_native_libs/jni/WebViewTestJniOnLoad.cpp
deleted file mode 100644
index 0ced4ee..0000000
--- a/core/tests/webkit/apk_with_native_libs/jni/WebViewTestJniOnLoad.cpp
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <jni.h>
-
-jint JNI_OnLoad(JavaVM * /*vm*/, void * /*reserved*/) {
-    return JNI_VERSION_1_4;
-}
diff --git a/core/tests/webkit/apk_with_native_libs/ondisk/AndroidManifest.xml b/core/tests/webkit/apk_with_native_libs/ondisk/AndroidManifest.xml
deleted file mode 100644
index ffffeb8..0000000
--- a/core/tests/webkit/apk_with_native_libs/ondisk/AndroidManifest.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.webviewloading_test_on_disk"
-    android:versionCode="1"
-    android:versionName="0.0.0.1">
-
-    <application android:label="WebView Loading Test APK"
-      android:multiArch="true">
-        <meta-data android:name="com.android.webview.WebViewLibrary"
-            android:value="libwebviewtest_jni.so" />
-    </application>
-</manifest>
diff --git a/core/tests/webkit/apk_with_native_libs/src/com/google/android/xts/webview_list/WebViewLoadingTestClass.java b/core/tests/webkit/apk_with_native_libs/src/com/google/android/xts/webview_list/WebViewLoadingTestClass.java
deleted file mode 100644
index 0efa4b4..0000000
--- a/core/tests/webkit/apk_with_native_libs/src/com/google/android/xts/webview_list/WebViewLoadingTestClass.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-package com.android.webview.chromium;
-
-/**
- * An empty class for testing purposes.
- */
-public class WebViewLoadingTestClass {
-}
diff --git a/core/tests/webkit/unit_tests_src/com/android/webkit/WebViewLibraryLoaderTest.java b/core/tests/webkit/unit_tests_src/com/android/webkit/WebViewLibraryLoaderTest.java
deleted file mode 100644
index e2f2d37..0000000
--- a/core/tests/webkit/unit_tests_src/com/android/webkit/WebViewLibraryLoaderTest.java
+++ /dev/null
@@ -1,329 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.webkit;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.os.Build;
-import android.os.Bundle;
-import android.util.Log;
-
-import android.support.test.filters.MediumTest;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.test.InstrumentationRegistry;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Unit tests for {@link WebViewLibraryLoader}.
- * Use the following command to run these tests:
- * make WebViewLoadingTests \
- * && adb install -r -d \
- * ${ANDROID_PRODUCT_OUT}/data/app/WebViewLoadingTests/WebViewLoadingTests.apk \
- * && adb shell am instrument -e class 'android.webkit.WebViewLibraryLoaderTest' -w \
- * 'com.android.webkit.tests/android.support.test.runner.AndroidJUnitRunner'
- */
-@RunWith(AndroidJUnit4.class)
-public final class WebViewLibraryLoaderTest {
-    private static final String WEBVIEW_LIBS_ON_DISK_TEST_APK =
-            "com.android.webviewloading_test_on_disk";
-    private static final String WEBVIEW_LIBS_IN_APK_TEST_APK =
-            "com.android.webviewloading_test_from_apk";
-    private static final String WEBVIEW_LOADING_TEST_NATIVE_LIB = "libwebviewtest_jni.so";
-
-    private PackageInfo webviewOnDiskPackageInfo;
-    private PackageInfo webviewFromApkPackageInfo;
-
-    @Before public void setUp() throws PackageManager.NameNotFoundException {
-        PackageManager pm = InstrumentationRegistry.getContext().getPackageManager();
-        webviewOnDiskPackageInfo =
-                pm.getPackageInfo(WEBVIEW_LIBS_ON_DISK_TEST_APK, PackageManager.GET_META_DATA);
-        webviewFromApkPackageInfo =
-                pm.getPackageInfo(WEBVIEW_LIBS_IN_APK_TEST_APK, PackageManager.GET_META_DATA);
-    }
-
-    private static boolean is64BitDevice() {
-        return Build.SUPPORTED_64_BIT_ABIS.length > 0;
-    }
-
-    // We test the getWebViewNativeLibraryDirectory method here because it handled several different
-    // cases/combinations and it seems unnecessary to create one test-apk for each such combination
-    // and arch.
-
-    /**
-     * Ensure we fetch the correct native library directories in the multi-arch case where
-     * the primary ABI is 64-bit.
-     */
-    @SmallTest
-    @Test public void testGetWebViewLibDirMultiArchPrimary64bit() {
-        final String nativeLib = "nativeLib";
-        final String secondaryNativeLib = "secondaryNativeLib";
-        PackageInfo packageInfo = new PackageInfo();
-        ApplicationInfo ai = new ApplicationInfoBuilder().
-                // See VMRuntime.ABI_TO_INSTRUCTION_SET_MAP
-                setPrimaryCpuAbi("arm64-v8a").
-                setNativeLibraryDir(nativeLib).
-                setSecondaryCpuAbi("armeabi").
-                setSecondaryNativeLibraryDir(secondaryNativeLib).
-                create();
-        packageInfo.applicationInfo = ai;
-        String actual32Lib =
-                WebViewLibraryLoader.getWebViewNativeLibraryDirectory(ai, false /* is64bit */);
-        String actual64Lib =
-                WebViewLibraryLoader.getWebViewNativeLibraryDirectory(ai, true /* is64bit */);
-        assertEquals(nativeLib, actual64Lib);
-        assertEquals(secondaryNativeLib, actual32Lib);
-    }
-
-    /**
-     * Ensure we fetch the correct native library directory in the 64-bit single-arch case.
-     */
-    @SmallTest
-    @Test public void testGetWebViewLibDirSingleArch64bit() {
-        final String nativeLib = "nativeLib";
-        PackageInfo packageInfo = new PackageInfo();
-        ApplicationInfo ai = new ApplicationInfoBuilder().
-                // See VMRuntime.ABI_TO_INSTRUCTION_SET_MAP
-                setPrimaryCpuAbi("arm64-v8a").
-                setNativeLibraryDir(nativeLib).
-                create();
-        packageInfo.applicationInfo = ai;
-        String actual64Lib =
-                WebViewLibraryLoader.getWebViewNativeLibraryDirectory(ai, true /* is64bit */);
-        assertEquals(nativeLib, actual64Lib);
-    }
-
-    /**
-     * Ensure we fetch the correct native library directory in the 32-bit single-arch case.
-     */
-    @SmallTest
-    @Test public void testGetWebViewLibDirSingleArch32bit() {
-        final String nativeLib = "nativeLib";
-        PackageInfo packageInfo = new PackageInfo();
-        ApplicationInfo ai = new ApplicationInfoBuilder().
-                // See VMRuntime.ABI_TO_INSTRUCTION_SET_MAP
-                setPrimaryCpuAbi("armeabi-v7a").
-                setNativeLibraryDir(nativeLib).
-                create();
-        packageInfo.applicationInfo = ai;
-        String actual32Lib =
-                WebViewLibraryLoader.getWebViewNativeLibraryDirectory(ai, false /* is64bit */);
-        assertEquals(nativeLib, actual32Lib);
-    }
-
-    /**
-     * Ensure we fetch the correct 32-bit library path from an APK with 32-bit and 64-bit
-     * libraries unzipped onto disk.
-     */
-    @MediumTest
-    @Test public void testGetWebViewLibraryPathOnDisk32Bit()
-            throws WebViewFactory.MissingWebViewPackageException {
-        WebViewLibraryLoader.WebViewNativeLibrary actualNativeLib =
-                WebViewLibraryLoader.getWebViewNativeLibrary(
-                        webviewOnDiskPackageInfo, false /* is64bit */);
-        String expectedLibaryDirectory = is64BitDevice() ?
-                webviewOnDiskPackageInfo.applicationInfo.secondaryNativeLibraryDir :
-                webviewOnDiskPackageInfo.applicationInfo.nativeLibraryDir;
-        String lib32Path = expectedLibaryDirectory + "/" + WEBVIEW_LOADING_TEST_NATIVE_LIB;
-        assertEquals("Fetched incorrect 32-bit path from WebView library.",
-                lib32Path, actualNativeLib.path);
-    }
-
-    /**
-     * Ensure we fetch the correct 64-bit library path from an APK with 32-bit and 64-bit
-     * libraries unzipped onto disk.
-     */
-    @MediumTest
-    @Test public void testGetWebViewLibraryPathOnDisk64Bit()
-            throws WebViewFactory.MissingWebViewPackageException {
-        // A 32-bit device will not unpack 64-bit libraries.
-        if (!is64BitDevice()) return;
-
-        WebViewLibraryLoader.WebViewNativeLibrary actualNativeLib =
-                WebViewLibraryLoader.getWebViewNativeLibrary(
-                        webviewOnDiskPackageInfo, true /* is64bit */);
-        String lib64Path = webviewOnDiskPackageInfo.applicationInfo.nativeLibraryDir
-                + "/" + WEBVIEW_LOADING_TEST_NATIVE_LIB;
-        assertEquals("Fetched incorrect 64-bit path from WebView library.",
-                lib64Path, actualNativeLib.path);
-    }
-
-    /**
-     * Check the size of the 32-bit library fetched from an APK with both 32-bit and 64-bit
-     * libraries unzipped onto disk.
-     */
-    @MediumTest
-    @Test public void testGetWebView32BitLibrarySizeOnDiskIsNonZero()
-            throws WebViewFactory.MissingWebViewPackageException {
-        WebViewLibraryLoader.WebViewNativeLibrary actual32BitNativeLib =
-                WebViewLibraryLoader.getWebViewNativeLibrary(
-                        webviewOnDiskPackageInfo, false /* is64bit */);
-        assertTrue(actual32BitNativeLib.size > 0);
-    }
-
-    /**
-     * Check the size of the 64-bit library fetched from an APK with both 32-bit and 64-bit
-     * libraries unzipped onto disk.
-     */
-    @MediumTest
-    @Test public void testGetWebView64BitLibrarySizeOnDiskIsNonZero()
-            throws WebViewFactory.MissingWebViewPackageException {
-        // A 32-bit device will not unpack 64-bit libraries.
-        if (!is64BitDevice()) return;
-        WebViewLibraryLoader.WebViewNativeLibrary actual64BitNativeLib =
-                WebViewLibraryLoader.getWebViewNativeLibrary(
-                        webviewOnDiskPackageInfo, true /* is64bit */);
-        assertTrue(actual64BitNativeLib.size > 0);
-    }
-
-    /**
-     * Ensure we fetch the correct 32-bit library path from an APK with both 32-bit and 64-bit
-     * libraries stored uncompressed in the APK.
-     */
-    @MediumTest
-    @Test public void testGetWebView32BitLibraryPathFromApk()
-            throws WebViewFactory.MissingWebViewPackageException, IOException {
-        WebViewLibraryLoader.WebViewNativeLibrary actualNativeLib =
-                WebViewLibraryLoader.getWebViewNativeLibrary(
-                        webviewFromApkPackageInfo, false /* is64bit */);
-        // The device might have ignored the app's request to not extract native libs, so first
-        // check whether the library paths match those of extracted libraries.
-        String expectedLibaryDirectory = is64BitDevice() ?
-                webviewFromApkPackageInfo.applicationInfo.secondaryNativeLibraryDir :
-                webviewFromApkPackageInfo.applicationInfo.nativeLibraryDir;
-        String lib32Path = expectedLibaryDirectory + "/" + WEBVIEW_LOADING_TEST_NATIVE_LIB;
-        if (lib32Path.equals(actualNativeLib.path)) {
-            // If the libraries were extracted to disk, ensure that they're actually there.
-            assertTrue("The given WebView library doesn't exist.",
-                    new File(actualNativeLib.path).exists());
-        } else { // The libraries were not extracted to disk.
-            assertIsValidZipEntryPath(actualNativeLib.path,
-                    webviewFromApkPackageInfo.applicationInfo.sourceDir);
-        }
-    }
-
-    /**
-     * Ensure we fetch the correct 32-bit library path from an APK with both 32-bit and 64-bit
-     * libraries stored uncompressed in the APK.
-     */
-    @MediumTest
-    @Test public void testGetWebView64BitLibraryPathFromApk()
-            throws WebViewFactory.MissingWebViewPackageException, IOException {
-        // A 32-bit device will not unpack 64-bit libraries.
-        if (!is64BitDevice()) return;
-
-        WebViewLibraryLoader.WebViewNativeLibrary actualNativeLib =
-                WebViewLibraryLoader.getWebViewNativeLibrary(
-                        webviewFromApkPackageInfo, true /* is64bit */);
-        assertIsValidZipEntryPath(actualNativeLib.path,
-                webviewFromApkPackageInfo.applicationInfo.sourceDir);
-    }
-
-    private static void assertIsValidZipEntryPath(String path, String zipFilePath)
-            throws IOException {
-        assertTrue("The path to a zip entry must start with the path to the zip file itself."
-            + "Expected zip path: " + zipFilePath + ", actual zip entry: " + path,
-            path.startsWith(zipFilePath + "!/"));
-        String[] pathSplit = path.split("!/");
-        assertEquals("A zip file path should have two parts, the zip path, and the zip entry path.",
-                2, pathSplit.length);
-        ZipFile zipFile = new ZipFile(pathSplit[0]);
-        assertNotNull("Path doesn't point to a valid zip entry: " + path,
-                zipFile.getEntry(pathSplit[1]));
-    }
-
-
-    /**
-     * Check the size of the 32-bit library fetched from an APK with both 32-bit and 64-bit
-     * libraries stored uncompressed in the APK.
-     */
-    @MediumTest
-    @Test public void testGetWebView32BitLibrarySizeFromApkIsNonZero()
-            throws WebViewFactory.MissingWebViewPackageException {
-        WebViewLibraryLoader.WebViewNativeLibrary actual32BitNativeLib =
-                WebViewLibraryLoader.getWebViewNativeLibrary(
-                        webviewFromApkPackageInfo, false /* is64bit */);
-        assertTrue(actual32BitNativeLib.size > 0);
-    }
-
-    /**
-     * Check the size of the 64-bit library fetched from an APK with both 32-bit and 64-bit
-     * libraries stored uncompressed in the APK.
-     */
-    @MediumTest
-    @Test public void testGetWebView64BitLibrarySizeFromApkIsNonZero()
-            throws WebViewFactory.MissingWebViewPackageException {
-        // A 32-bit device will not unpack 64-bit libraries.
-        if (!is64BitDevice()) return;
-
-        WebViewLibraryLoader.WebViewNativeLibrary actual64BitNativeLib =
-                WebViewLibraryLoader.getWebViewNativeLibrary(
-                        webviewFromApkPackageInfo, true /* is64bit */);
-        assertTrue(actual64BitNativeLib.size > 0);
-    }
-
-    private static class ApplicationInfoBuilder {
-        ApplicationInfo ai;
-
-        public ApplicationInfoBuilder setPrimaryCpuAbi(String primaryCpuAbi) {
-            ai.primaryCpuAbi = primaryCpuAbi;
-            return this;
-        }
-
-        public ApplicationInfoBuilder setSecondaryCpuAbi(String secondaryCpuAbi) {
-            ai.secondaryCpuAbi = secondaryCpuAbi;
-            return this;
-        }
-
-        public ApplicationInfoBuilder setNativeLibraryDir(String nativeLibraryDir) {
-            ai.nativeLibraryDir = nativeLibraryDir;
-            return this;
-        }
-
-        public ApplicationInfoBuilder setSecondaryNativeLibraryDir(
-                String secondaryNativeLibraryDir) {
-            ai.secondaryNativeLibraryDir = secondaryNativeLibraryDir;
-            return this;
-        }
-
-        public ApplicationInfoBuilder setMetaData(Bundle metaData) {
-            ai.metaData = metaData;
-            return this;
-        }
-
-        public ApplicationInfoBuilder() {
-            ai = new android.content.pm.ApplicationInfo();
-        }
-
-        public ApplicationInfo create() {
-            return ai;
-        }
-    }
-}
diff --git a/libs/androidfw/include/androidfw/ByteBucketArray.h b/libs/androidfw/include/androidfw/ByteBucketArray.h
index d84a207..949c9445 100644
--- a/libs/androidfw/include/androidfw/ByteBucketArray.h
+++ b/libs/androidfw/include/androidfw/ByteBucketArray.h
@@ -60,7 +60,7 @@
   }
 
   T& editItemAt(size_t index) {
-    CHECK(index < size()) << "ByteBucketArray.getOrCreate(index=" << index
+    CHECK(index < size()) << "ByteBucketArray.editItemAt(index=" << index
                           << ") with size=" << size();
 
     uint8_t bucket_index = static_cast<uint8_t>(index) >> 4;
diff --git a/media/jni/android_media_MediaPlayer2.cpp b/media/jni/android_media_MediaPlayer2.cpp
index a2bf549..d4c84b5 100644
--- a/media/jni/android_media_MediaPlayer2.cpp
+++ b/media/jni/android_media_MediaPlayer2.cpp
@@ -1014,7 +1014,11 @@
     PlayerMessage response;
     request.ParseFromArray(pData, pDataLen);
 
-    media_player->invoke(request, &response);
+    process_media_player_call( env, thiz, media_player->invoke(request, &response),
+            "java.lang.RuntimeException", NULL );
+    if (env->ExceptionCheck()) {
+        return NULL;
+    }
 
     int size = response.ByteSize();
     jbyte* temp = new jbyte[size];
diff --git a/native/webview/loader/loader.cpp b/native/webview/loader/loader.cpp
index adb371d..fee2a25 100644
--- a/native/webview/loader/loader.cpp
+++ b/native/webview/loader/loader.cpp
@@ -64,7 +64,8 @@
   return JNI_TRUE;
 }
 
-jboolean DoCreateRelroFile(const char* lib, const char* relro) {
+jboolean DoCreateRelroFile(JNIEnv* env, const char* lib, const char* relro,
+                           jobject clazzLoader) {
   // Try to unlink the old file, since if this is being called, the old one is
   // obsolete.
   if (unlink(relro) != 0 && errno != ENOENT) {
@@ -82,11 +83,19 @@
     ALOGE("Failed to create temporary file %s: %s", relro_tmp, strerror(errno));
     return JNI_FALSE;
   }
+  android_namespace_t* ns =
+      android::FindNamespaceByClassLoader(env, clazzLoader);
+  if (ns == NULL) {
+    ALOGE("Failed to find classloader namespace");
+    return JNI_FALSE;
+  }
   android_dlextinfo extinfo;
-  extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS | ANDROID_DLEXT_WRITE_RELRO;
+  extinfo.flags = ANDROID_DLEXT_RESERVED_ADDRESS | ANDROID_DLEXT_WRITE_RELRO |
+                  ANDROID_DLEXT_USE_NAMESPACE;
   extinfo.reserved_addr = gReservedAddress;
   extinfo.reserved_size = gReservedSize;
   extinfo.relro_fd = tmp_fd;
+  extinfo.library_namespace = ns;
   void* handle = android_dlopen_ext(lib, RTLD_NOW, &extinfo);
   int close_result = close(tmp_fd);
   if (handle == NULL) {
@@ -143,13 +152,14 @@
   return DoReserveAddressSpace(size);
 }
 
-jboolean CreateRelroFile(JNIEnv* env, jclass, jstring lib, jstring relro) {
+jboolean CreateRelroFile(JNIEnv* env, jclass, jstring lib, jstring relro,
+                         jobject clazzLoader) {
   jboolean ret = JNI_FALSE;
   const char* lib_utf8 = env->GetStringUTFChars(lib, NULL);
   if (lib_utf8 != NULL) {
     const char* relro_utf8 = env->GetStringUTFChars(relro, NULL);
     if (relro_utf8 != NULL) {
-      ret = DoCreateRelroFile(lib_utf8, relro_utf8);
+      ret = DoCreateRelroFile(env, lib_utf8, relro_utf8, clazzLoader);
       env->ReleaseStringUTFChars(relro, relro_utf8);
     }
     env->ReleaseStringUTFChars(lib, lib_utf8);
@@ -179,7 +189,7 @@
   { "nativeReserveAddressSpace", "(J)Z",
       reinterpret_cast<void*>(ReserveAddressSpace) },
   { "nativeCreateRelroFile",
-      "(Ljava/lang/String;Ljava/lang/String;)Z",
+      "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/ClassLoader;)Z",
       reinterpret_cast<void*>(CreateRelroFile) },
   { "nativeLoadWithRelroFile",
       "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/ClassLoader;)I",
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/hvac/AnimatedTemperatureView.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/hvac/AnimatedTemperatureView.java
index 6473f0d..0467bff 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/hvac/AnimatedTemperatureView.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/hvac/AnimatedTemperatureView.java
@@ -177,7 +177,7 @@
                             }
                         }
                         textView.getViewTreeObserver().removeOnPreDrawListener(this);
-                        return false;
+                        return true;
                     }
                 });
         textView.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
diff --git a/packages/CarrierDefaultApp/Android.mk b/packages/CarrierDefaultApp/Android.mk
index 5068b3b..df88afd 100644
--- a/packages/CarrierDefaultApp/Android.mk
+++ b/packages/CarrierDefaultApp/Android.mk
@@ -9,8 +9,6 @@
 LOCAL_PRIVATE_PLATFORM_APIS := true
 LOCAL_CERTIFICATE := platform
 
-LOCAL_STATIC_JAVA_LIBRARIES := services.net
-
 include $(BUILD_PACKAGE)
 
 # This finds and builds the test apk as well, so a single make does both.
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
index b1933373..4f67350 100644
--- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
@@ -32,7 +32,6 @@
 import android.net.Proxy;
 import android.net.TrafficStats;
 import android.net.Uri;
-import android.net.dns.ResolvUtil;
 import android.net.http.SslError;
 import android.os.Bundle;
 import android.telephony.CarrierConfigManager;
@@ -159,9 +158,9 @@
 
     private void setNetwork(Network network) {
         if (network != null) {
+            network = network.getPrivateDnsBypassingCopy();
             mCm.bindProcessToNetwork(network);
-            mCm.setProcessDefaultNetworkForHostResolution(
-                    ResolvUtil.getNetworkWithUseLocalNameserversFlag(network));
+            mCm.setProcessDefaultNetworkForHostResolution(network);
         }
         mNetwork = network;
     }
@@ -242,7 +241,6 @@
     private void testForCaptivePortal() {
         mTestingThread = new Thread(new Runnable() {
             public void run() {
-                final Network network = ResolvUtil.makeNetworkWithPrivateDnsBypass(mNetwork);
                 // Give time for captive portal to open.
                 try {
                     Thread.sleep(1000);
@@ -253,7 +251,7 @@
                 int httpResponseCode = 500;
                 int oldTag = TrafficStats.getAndSetThreadStatsTag(TrafficStats.TAG_SYSTEM_PROBE);
                 try {
-                    urlConnection = (HttpURLConnection) network.openConnection(
+                    urlConnection = (HttpURLConnection) mNetwork.openConnection(
                             new URL(mCm.getCaptivePortalServerUrl()));
                     urlConnection.setInstanceFollowRedirects(false);
                     urlConnection.setConnectTimeout(SOCKET_TIMEOUT_MS);
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index ab2892f..d29bd65 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -135,7 +135,7 @@
     <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"테더링"</string>
     <string name="tether_settings_title_all" msgid="8356136101061143841">"테더링 및 휴대용 핫스팟"</string>
     <string name="managed_user_title" msgid="8109605045406748842">"모든 직장 앱"</string>
-    <string name="user_guest" msgid="8475274842845401871">"손님"</string>
+    <string name="user_guest" msgid="8475274842845401871">"게스트"</string>
     <string name="unknown" msgid="1592123443519355854">"알 수 없음"</string>
     <string name="running_process_item_user_label" msgid="3129887865552025943">"사용자: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
     <string name="launch_defaults_some" msgid="313159469856372621">"일부 기본값이 설정됨"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 649900b..b9f7323 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -78,12 +78,6 @@
 
     private final static String MESSAGE_REJECTION_COUNT_PREFS_NAME = "bluetooth_message_reject";
 
-    /**
-     * When we connect to multiple profiles, we only want to display a single
-     * error even if they all fail. This tracks that state.
-     */
-    private boolean mIsConnectingErrorPossible;
-
     public long getHiSyncId() {
         return mHiSyncId;
     }
@@ -230,9 +224,6 @@
             return;
         }
 
-        // Reset the only-show-one-error-dialog tracking variable
-        mIsConnectingErrorPossible = true;
-
         int preferredProfiles = 0;
         for (LocalBluetoothProfile profile : mProfiles) {
             if (connectAllProfiles ? profile.isConnectable() : profile.isAutoConnectable()) {
@@ -253,8 +244,6 @@
         if (!ensurePaired()) {
             return;
         }
-        // Reset the only-show-one-error-dialog tracking variable
-        mIsConnectingErrorPossible = true;
 
         for (LocalBluetoothProfile profile : mProfiles) {
             if (profile.isAutoConnectable()) {
@@ -271,8 +260,6 @@
      */
     public void connectProfile(LocalBluetoothProfile profile) {
         mConnectAttempted = SystemClock.elapsedRealtime();
-        // Reset the only-show-one-error-dialog tracking variable
-        mIsConnectingErrorPossible = true;
         connectInt(profile);
         // Refresh the UI based on profile.connect() call
         refresh();
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index c6ea480..bd21b83 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1617,6 +1617,12 @@
         dumpSetting(s, p,
                 Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
                 SecureSettingsProto.Accessibility.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES);
+        dumpSetting(s, p,
+                Settings.Secure.ACCESSIBILITY_MINIMUM_UI_TIMEOUT_ENABLED,
+                SecureSettingsProto.Accessibility.MINIMUM_UI_TIMEOUT_ENABLED);
+        dumpSetting(s, p,
+                Settings.Secure.ACCESSIBILITY_MINIMUM_UI_TIMEOUT_MS,
+                SecureSettingsProto.Accessibility.MINIMUM_UI_TIMEOUT_MS);
         p.end(accessibilityToken);
 
         dumpSetting(s, p,
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 4fc190d..ec35b3d 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -16,6 +16,8 @@
 
 package com.android.shell;
 
+import static android.content.pm.PackageManager.FEATURE_LEANBACK;
+import static android.content.pm.PackageManager.FEATURE_TELEVISION;
 import static android.os.Process.THREAD_PRIORITY_BACKGROUND;
 
 import static com.android.shell.BugreportPrefs.STATE_HIDE;
@@ -235,6 +237,7 @@
     private static final Bundle sNotificationBundle = new Bundle();
 
     private boolean mIsWatch;
+    private boolean mIsTv;
 
     private int mLastProgressPercent;
 
@@ -255,6 +258,9 @@
         final Configuration conf = mContext.getResources().getConfiguration();
         mIsWatch = (conf.uiMode & Configuration.UI_MODE_TYPE_MASK) ==
                 Configuration.UI_MODE_TYPE_WATCH;
+        PackageManager packageManager = getPackageManager();
+        mIsTv = packageManager.hasSystemFeature(FEATURE_LEANBACK)
+                || packageManager.hasSystemFeature(FEATURE_TELEVISION);
         NotificationManager nm = NotificationManager.from(mContext);
         nm.createNotificationChannel(
                 new NotificationChannel(NOTIFICATION_CHANNEL_ID,
@@ -500,8 +506,8 @@
                 .setProgress(info.max, info.progress, false)
                 .setOngoing(true);
 
-        // Wear bugreport doesn't need the bug info dialog, screenshot and cancel action.
-        if (!mIsWatch) {
+        // Wear and ATV bugreport doesn't need the bug info dialog, screenshot and cancel action.
+        if (!(mIsWatch || mIsTv)) {
             final Action cancelAction = new Action.Builder(null, mContext.getString(
                     com.android.internal.R.string.cancel), newCancelIntent(mContext, info)).build();
             final Intent infoIntent = new Intent(mContext, BugreportProgressService.class);
diff --git a/packages/SystemUI/res/values-night/colors.xml b/packages/SystemUI/res/values-night/colors.xml
index 45d2185..2c5120d 100644
--- a/packages/SystemUI/res/values-night/colors.xml
+++ b/packages/SystemUI/res/values-night/colors.xml
@@ -25,10 +25,10 @@
     <color name="notification_legacy_background_color">@*android:color/notification_material_background_color</color>
 
     <!-- The color of the material notification background when dimmed -->
-    <color name="notification_material_background_dimmed_color">#aa212121</color>
+    <color name="notification_material_background_dimmed_color">#aa000000</color>
 
     <!-- The color of the dividing line between grouped notifications while . -->
-    <color name="notification_divider_color">#000</color>
+    <color name="notification_divider_color">#212121</color>
 
     <!-- The background color of the notification shade -->
     <color name="notification_shade_background_color">#181818</color>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 67db68d..216ed68 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -1141,9 +1141,13 @@
     }
 
     private void updateNotificationColor() {
+        Configuration currentConfig = getResources().getConfiguration();
+        boolean nightMode = (currentConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK)
+                == Configuration.UI_MODE_NIGHT_YES;
+
         mNotificationColor = ContrastColorUtil.resolveContrastColor(mContext,
                 getStatusBarNotification().getNotification().color,
-                getBackgroundColorWithoutTint());
+                getBackgroundColorWithoutTint(), nightMode);
         mNotificationColorAmbient = ContrastColorUtil.resolveAmbientColor(mContext,
                 getStatusBarNotification().getNotification().color);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
index 2cbb78a..3744105 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
@@ -356,10 +356,11 @@
     if (supplementalIconId != 0) {
       Drawable supplementalIcon = mContext.getResources().getDrawable(supplementalIconId);
       supplementalIcon.mutate().setTint(color);
-      listItem.setSupplementalIcon(supplementalIcon, true,
-          supplementalIconOnClickListener);
+      listItem.setSupplementalIcon(supplementalIcon, true);
+      listItem.setSupplementalIconListener(supplementalIconOnClickListener);
     } else {
       listItem.setSupplementalEmptyIcon(true);
+      listItem.setSupplementalIconListener(null);
     }
 
     mVolumeLineItems.add(listItem);
diff --git a/packages/VpnDialogs/res/values-es-rUS/strings.xml b/packages/VpnDialogs/res/values-es-rUS/strings.xml
index 3732ebc..21cfc04 100644
--- a/packages/VpnDialogs/res/values-es-rUS/strings.xml
+++ b/packages/VpnDialogs/res/values-es-rUS/strings.xml
@@ -17,7 +17,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Solicitud de conexión"</string>
-    <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> quiere configurar una conexión VPN que permite controlar el tráfico de la red. Acéptala solo si confías en la fuente. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; aparece en la parte superior de la pantalla cuando la VPN está activa."</string>
+    <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> quiere configurar una conexión VPN capaz de controlar el tráfico de la red. Acéptala solo si confías en la fuente. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; aparece en la parte superior de la pantalla cuando se activa la VPN."</string>
     <string name="legacy_title" msgid="192936250066580964">"La VPN está conectada."</string>
     <string name="session" msgid="6470628549473641030">"Sesión:"</string>
     <string name="duration" msgid="3584782459928719435">"Duración:"</string>
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index b2e06f9..9bee8db 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -21,6 +21,8 @@
 import static android.view.accessibility.AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED;
 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS;
 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS;
+import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
+import static android.view.accessibility.AccessibilityNodeInfo.ACTION_LONG_CLICK;
 import static com.android.internal.util.FunctionalUtils.ignoreRemoteException;
 import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
 import static android.accessibilityservice.AccessibilityService.SHOW_MODE_AUTO;
@@ -1689,6 +1691,24 @@
                 this, userState));
     }
 
+    private void scheduleSetAllClientsMinimumUiTimeout(UserState userState) {
+        mMainHandler.sendMessage(obtainMessage(
+                AccessibilityManagerService::sendMinimumUiTimeoutChanged,
+                this, userState.mUserClients, userState.mMinimumUiTimeout));
+    }
+
+    private void sendMinimumUiTimeoutChanged(
+            RemoteCallbackList<IAccessibilityManagerClient> userClients, int uiTimeout) {
+        notifyClientsOfServicesMinimumUiTimeoutChange(mGlobalClients, uiTimeout);
+        notifyClientsOfServicesMinimumUiTimeoutChange(userClients, uiTimeout);
+    }
+
+    private void notifyClientsOfServicesMinimumUiTimeoutChange(
+            RemoteCallbackList<IAccessibilityManagerClient> clients, int uiTimeout) {
+        clients.broadcast(ignoreRemoteException(
+                client -> client.setMinimumUiTimeout(uiTimeout)));
+    }
+
     private void updateInputFilter(UserState userState) {
         if (mUiAutomationManager.suppressingAccessibilityServicesLocked()) return;
 
@@ -1822,6 +1842,7 @@
         scheduleUpdateClientsIfNeededLocked(userState);
         updateRelevantEventsLocked(userState);
         updateAccessibilityButtonTargetsLocked(userState);
+        updateMinimumUiTimeoutLocked(userState);
     }
 
     private void updateAccessibilityFocusBehaviorLocked(UserState userState) {
@@ -1940,6 +1961,7 @@
         somethingChanged |= readAutoclickEnabledSettingLocked(userState);
         somethingChanged |= readAccessibilityShortcutSettingLocked(userState);
         somethingChanged |= readAccessibilityButtonSettingsLocked(userState);
+        somethingChanged |= readUserMinimumUiTimeoutSettingsLocked(userState);
         return somethingChanged;
     }
 
@@ -2084,6 +2106,22 @@
         return true;
     }
 
+    private boolean readUserMinimumUiTimeoutSettingsLocked(UserState userState) {
+        final boolean enabled = Settings.Secure.getIntForUser(mContext.getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_MINIMUM_UI_TIMEOUT_ENABLED, 0,
+                userState.mUserId) == 1;
+        final int timeout = Settings.Secure.getIntForUser(mContext.getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_MINIMUM_UI_TIMEOUT_MS, 0,
+                userState.mUserId);
+        if (enabled != userState.mUserMinimumUiTimeoutEnabled
+                || timeout != userState.mUserMinimumUiTimeout) {
+            userState.mUserMinimumUiTimeoutEnabled = enabled;
+            userState.mUserMinimumUiTimeout = timeout;
+            return true;
+        }
+        return false;
+    }
+
     /**
      * Check if the service that will be enabled by the shortcut is installed. If it isn't,
      * clear the value and the associated setting so a sideloaded service can't spoof the
@@ -2250,6 +2288,27 @@
         }
     }
 
+    private void updateMinimumUiTimeoutLocked(UserState userState) {
+        int newUiTimeout = 0;
+        if (userState.mUserMinimumUiTimeoutEnabled) {
+            newUiTimeout = userState.mUserMinimumUiTimeout;
+        } else {
+            final List<AccessibilityServiceConnection> services = userState.mBoundServices;
+            final int numServices = services.size();
+            for (int i = 0; i < numServices; i++) {
+                final int serviceUiTimeout = services.get(i).getServiceInfo()
+                        .getMinimumUiTimeoutMillis();
+                if (newUiTimeout < serviceUiTimeout) {
+                    newUiTimeout = serviceUiTimeout;
+                }
+            }
+        }
+        if (newUiTimeout != userState.mMinimumUiTimeout) {
+            userState.mMinimumUiTimeout = newUiTimeout;
+            scheduleSetAllClientsMinimumUiTimeout(userState);
+        }
+    }
+
     @GuardedBy("mLock")
     @Override
     public MagnificationSpec getCompatibleMagnificationSpecLocked(int windowId) {
@@ -2388,6 +2447,20 @@
         return mFingerprintGestureDispatcher.onFingerprintGesture(gestureKeyCode);
     }
 
+    /**
+     * Get the minimum timeout for changes to the UI needed by this user. Controls should remain
+     * on the screen for at least this long to give users time to react.
+     *
+     * @return The minimum timeout for the current user in milliseconds.
+     */
+    @Override
+    public int getMinimumUiTimeout() {
+        synchronized(mLock) {
+            final UserState userState = getCurrentUserStateLocked();
+            return userState.mMinimumUiTimeout;
+        }
+    }
+
     @Override
     public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
         if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, pw)) return;
@@ -2405,6 +2478,7 @@
                 pw.append(", navBarMagnificationEnabled="
                         + userState.mIsNavBarMagnificationEnabled);
                 pw.append(", autoclickEnabled=" + userState.mIsAutoclickEnabled);
+                pw.append(", minimumUiTimeout=" + userState.mMinimumUiTimeout);
                 if (mUiAutomationManager.isUiAutomationRunningLocked()) {
                     pw.append(", ");
                     mUiAutomationManager.dumpUiAutomationService(fd, pw, args);
@@ -2549,6 +2623,38 @@
         return -1;
     }
 
+    private void notifyOutsideTouchIfNeeded(int targetWindowId, int action, Bundle arguments,
+            int interactionId, IAccessibilityInteractionConnectionCallback callback, int fetchFlags,
+            int interrogatingPid, long interrogatingTid) {
+        if (action != ACTION_CLICK && action != ACTION_LONG_CLICK) {
+            return;
+        }
+
+        final List<Integer> outsideWindowsIds;
+        final List<RemoteAccessibilityConnection> connectionList = new ArrayList<>();
+        synchronized (mLock) {
+            outsideWindowsIds = mSecurityPolicy.getWatchOutsideTouchWindowId(targetWindowId);
+            for (int i = 0; i < outsideWindowsIds.size(); i++) {
+                connectionList.add(getConnectionLocked(outsideWindowsIds.get(i)));
+            }
+        }
+        for (int i = 0; i < connectionList.size(); i++) {
+            final RemoteAccessibilityConnection connection = connectionList.get(i);
+            if (connection != null) {
+                try {
+                    connection.mConnection.performAccessibilityAction(
+                            AccessibilityNodeInfo.ROOT_ITEM_ID,
+                            R.id.accessibilityActionOutsideTouch, arguments, interactionId,
+                            callback, fetchFlags, interrogatingPid, interrogatingTid);
+                } catch (RemoteException re) {
+                    if (DEBUG) {
+                        Slog.e(LOG_TAG, "Error calling performAccessibilityAction: " + re);
+                    }
+                }
+            }
+        }
+    }
+
     @Override
     public void ensureWindowsAvailableTimed() {
         synchronized (mLock) {
@@ -2628,6 +2734,8 @@
             mPowerManager.userActivity(SystemClock.uptimeMillis(),
                     PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY, 0);
 
+            notifyOutsideTouchIfNeeded(resolvedWindowId, action, arguments, interactionId, callback,
+                    fetchFlags, interrogatingPid, interrogatingTid);
             if (activityToken != null) {
                 LocalServices.getService(ActivityTaskManagerInternal.class)
                         .setFocusedActivity(activityToken);
@@ -2955,6 +3063,7 @@
         public long mAccessibilityFocusNodeId = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
 
         private boolean mTouchInteractionInProgress;
+        private boolean mHasWatchOutsideTouchWindow;
 
         private boolean canDispatchAccessibilityEventLocked(AccessibilityEvent event) {
             final int eventType = event.getEventType();
@@ -3112,6 +3221,7 @@
                 mWindowInfoById.valueAt(i).recycle();
             }
             mWindowInfoById.clear();
+            mHasWatchOutsideTouchWindow = false;
 
             mFocusedWindowId = INVALID_WINDOW_ID;
             if (!mTouchInteractionInProgress) {
@@ -3156,6 +3266,9 @@
                                 activeWindowGone = false;
                             }
                         }
+                        if (!mHasWatchOutsideTouchWindow && windowInfo.hasFlagWatchOutsideTouch) {
+                            mHasWatchOutsideTouchWindow = true;
+                        }
                         mWindows.add(window);
                         mA11yWindowInfoById.put(windowId, window);
                         mWindowInfoById.put(windowId, WindowInfo.obtain(windowInfo));
@@ -3574,6 +3687,22 @@
             return mWindowInfoById.get(windowId);
         }
 
+        private List<Integer> getWatchOutsideTouchWindowId(int targetWindowId) {
+            if (mWindowInfoById != null && mHasWatchOutsideTouchWindow) {
+                final List<Integer> outsideWindowsId = new ArrayList<>();
+                final WindowInfo targetWindow = mWindowInfoById.get(targetWindowId);
+                for (int i = 0; i < mWindowInfoById.size(); i++) {
+                    WindowInfo window = mWindowInfoById.valueAt(i);
+                    if (window.layer < targetWindow.layer
+                            && window.hasFlagWatchOutsideTouch) {
+                        outsideWindowsId.add(mWindowInfoById.keyAt(i));
+                    }
+                }
+                return outsideWindowsId;
+            }
+            return Collections.emptyList();
+        }
+
         private AccessibilityWindowInfo getPictureInPictureWindow() {
             if (mWindows != null) {
                 final int windowCount = mWindows.size();
@@ -3660,6 +3789,7 @@
         public ComponentName mServiceToEnableWithShortcut;
 
         public int mLastSentClientState = -1;
+        public int mMinimumUiTimeout = 0;
 
         private int mSoftKeyboardShowMode = 0;
 
@@ -3674,6 +3804,8 @@
         public boolean mIsPerformGesturesEnabled;
         public boolean mIsFilterKeyEventsEnabled;
         public boolean mAccessibilityFocusOnlyInActiveWindow;
+        public boolean mUserMinimumUiTimeoutEnabled;
+        public int mUserMinimumUiTimeout;
 
         public boolean mBindInstantServiceAllowed;
 
@@ -3713,6 +3845,9 @@
             // Clear event management state.
             mLastSentClientState = -1;
 
+            // clear minimum ui timeout
+            mMinimumUiTimeout = 0;
+
             // Clear state persisted in settings.
             mEnabledServices.clear();
             mTouchExplorationGrantedServices.clear();
@@ -3722,6 +3857,8 @@
             mServiceAssignedToAccessibilityButton = null;
             mIsNavBarMagnificationAssignedToAccessibilityButton = false;
             mIsAutoclickEnabled = false;
+            mUserMinimumUiTimeoutEnabled = false;
+            mUserMinimumUiTimeout = 0;
         }
 
         public void addServiceLocked(AccessibilityServiceConnection serviceConnection) {
@@ -3948,6 +4085,12 @@
         private final Uri mAccessibilityButtonComponentIdUri = Settings.Secure.getUriFor(
                 Settings.Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT);
 
+        private final Uri mUserMinimumUiTimeoutEnabledUri = Settings.Secure.getUriFor(
+                Settings.Secure.ACCESSIBILITY_MINIMUM_UI_TIMEOUT_ENABLED);
+
+        private final Uri mUserMinimumUiTimeoutUri = Settings.Secure.getUriFor(
+                Settings.Secure.ACCESSIBILITY_MINIMUM_UI_TIMEOUT_MS);
+
         public AccessibilityContentObserver(Handler handler) {
             super(handler);
         }
@@ -3982,6 +4125,10 @@
                     mAccessibilityShortcutServiceIdUri, false, this, UserHandle.USER_ALL);
             contentResolver.registerContentObserver(
                     mAccessibilityButtonComponentIdUri, false, this, UserHandle.USER_ALL);
+            contentResolver.registerContentObserver(
+                    mUserMinimumUiTimeoutEnabledUri, false, this, UserHandle.USER_ALL);
+            contentResolver.registerContentObserver(
+                    mUserMinimumUiTimeoutUri, false, this, UserHandle.USER_ALL);
         }
 
         @Override
@@ -4032,6 +4179,11 @@
                     if (readAccessibilityButtonSettingsLocked(userState)) {
                         onUserStateChangedLocked(userState);
                     }
+                } else if (mUserMinimumUiTimeoutEnabledUri.equals(uri)
+                        || mUserMinimumUiTimeoutUri.equals(uri)) {
+                    if (readUserMinimumUiTimeoutSettingsLocked(userState)) {
+                        updateMinimumUiTimeoutLocked(userState);
+                    }
                 }
             }
         }
diff --git a/services/backup/java/com/android/server/backup/encryption/chunk/ChunkHash.java b/services/backup/java/com/android/server/backup/encryption/chunk/ChunkHash.java
new file mode 100644
index 0000000..1ae598e
--- /dev/null
+++ b/services/backup/java/com/android/server/backup/encryption/chunk/ChunkHash.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.backup.encryption.chunk;
+
+import com.android.internal.util.Preconditions;
+import java.util.Arrays;
+import java.util.Base64;
+
+/**
+ * Represents the SHA-256 hash of the plaintext of a chunk, which is frequently used as a key.
+ *
+ * <p>This class is {@link Comparable} and implements {@link #equals(Object)} and {@link
+ * #hashCode()}.
+ */
+public class ChunkHash implements Comparable<ChunkHash> {
+    /** The length of the hash in bytes. The hash is a SHA-256, so this is 256 bits. */
+    public static final int HASH_LENGTH_BYTES = 256 / 8;
+
+    private static final int UNSIGNED_MASK = 0xFF;
+
+    private final byte[] mHash;
+
+    /** Constructs a new instance which wraps the given SHA-256 hash bytes. */
+    public ChunkHash(byte[] hash) {
+        Preconditions.checkArgument(hash.length == HASH_LENGTH_BYTES, "Hash must have 256 bits");
+        mHash = hash;
+    }
+
+    public byte[] getHash() {
+        return mHash;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (!(o instanceof ChunkHash)) {
+            return false;
+        }
+
+        ChunkHash chunkHash = (ChunkHash) o;
+        return Arrays.equals(mHash, chunkHash.mHash);
+    }
+
+    @Override
+    public int hashCode() {
+        return Arrays.hashCode(mHash);
+    }
+
+    @Override
+    public int compareTo(ChunkHash other) {
+        return lexicographicalCompareUnsignedBytes(getHash(), other.getHash());
+    }
+
+    @Override
+    public String toString() {
+        return Base64.getEncoder().encodeToString(mHash);
+    }
+
+    private static int lexicographicalCompareUnsignedBytes(byte[] left, byte[] right) {
+        int minLength = Math.min(left.length, right.length);
+        for (int i = 0; i < minLength; i++) {
+            int result = toInt(left[i]) - toInt(right[i]);
+            if (result != 0) {
+                return result;
+            }
+        }
+        return left.length - right.length;
+    }
+
+    private static int toInt(byte value) {
+        return value & UNSIGNED_MASK;
+    }
+}
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 499c03d..ad2f82c 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -81,6 +81,7 @@
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
 import android.util.SparseLongArray;
+import android.util.StatsLog;
 import android.util.TimeUtils;
 import android.util.proto.ProtoOutputStream;
 
@@ -3637,6 +3638,8 @@
                         if (DEBUG_BATCH) {
                             Slog.v(TAG, "Time changed notification from kernel; rebatching");
                         }
+                        // StatsLog requires currentTimeMillis(), which == nowRTC to within usecs.
+                        StatsLog.write(StatsLog.WALL_CLOCK_TIME_SHIFTED, nowRTC);
                         removeImpl(mTimeTickSender);
                         removeImpl(mDateChangeSender);
                         rebatchAllAlarms();
diff --git a/services/core/java/com/android/server/HardwarePropertiesManagerService.java b/services/core/java/com/android/server/HardwarePropertiesManagerService.java
index 4016d29..e21a3d7 100644
--- a/services/core/java/com/android/server/HardwarePropertiesManagerService.java
+++ b/services/core/java/com/android/server/HardwarePropertiesManagerService.java
@@ -26,7 +26,6 @@
 import static android.os.HardwarePropertiesManager.TEMPERATURE_THROTTLING_BELOW_VR_MIN;
 
 import android.Manifest;
-import android.app.ActivityManager;
 import android.app.AppOpsManager;
 import android.app.admin.DevicePolicyManager;
 import android.content.Context;
@@ -34,8 +33,8 @@
 import android.os.Binder;
 import android.os.CpuUsageInfo;
 import android.os.IHardwarePropertiesManager;
-import android.os.Process;
 import android.os.UserHandle;
+
 import com.android.internal.util.DumpUtils;
 import com.android.server.vr.VrManagerInternal;
 
@@ -166,11 +165,11 @@
         final VrManagerInternal vrService = LocalServices.getService(VrManagerInternal.class);
         final DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
         if (!dpm.isDeviceOwnerApp(callingPackage)
-                && !vrService.isCurrentVrListener(callingPackage, userId)
                 && mContext.checkCallingOrSelfPermission(Manifest.permission.DEVICE_POWER)
-                        != PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException("The caller is not a device owner, bound VrListenerService"
-                + ", or holding the DEVICE_POWER permission.");
+                        != PackageManager.PERMISSION_GRANTED
+                && (vrService == null || !vrService.isCurrentVrListener(callingPackage, userId))) {
+            throw new SecurityException("The caller is neither a device owner"
+                + ", nor holding the DEVICE_POWER permission, nor the current VrListener.");
         }
     }
 }
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index 01e8152..380f6a7 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -612,7 +612,7 @@
                 mSrvConfig
                         .getNetdInstance()
                         .ipSecDeleteSecurityAssociation(
-                                mResourceId,
+                                uid,
                                 mConfig.getSourceAddress(),
                                 mConfig.getDestinationAddress(),
                                 spi,
@@ -679,7 +679,7 @@
                     mSrvConfig
                             .getNetdInstance()
                             .ipSecDeleteSecurityAssociation(
-                                    mResourceId, mSourceAddress, mDestinationAddress, mSpi, 0, 0);
+                                    uid, mSourceAddress, mDestinationAddress, mSpi, 0, 0);
                 }
             } catch (ServiceSpecificException | RemoteException e) {
                 Log.e(TAG, "Failed to delete SPI reservation with ID: " + mResourceId, e);
@@ -821,13 +821,13 @@
 
                 for (int selAddrFamily : ADDRESS_FAMILIES) {
                     netd.ipSecDeleteSecurityPolicy(
-                            0,
+                            uid,
                             selAddrFamily,
                             IpSecManager.DIRECTION_OUT,
                             mOkey,
                             0xffffffff);
                     netd.ipSecDeleteSecurityPolicy(
-                            0,
+                            uid,
                             selAddrFamily,
                             IpSecManager.DIRECTION_IN,
                             mIkey,
@@ -1083,7 +1083,8 @@
         }
         checkNotNull(binder, "Null Binder passed to allocateSecurityParameterIndex");
 
-        UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
+        int callingUid = Binder.getCallingUid();
+        UserRecord userRecord = mUserResourceTracker.getUserRecord(callingUid);
         final int resourceId = mNextResourceId++;
 
         int spi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX;
@@ -1096,7 +1097,7 @@
             spi =
                     mSrvConfig
                             .getNetdInstance()
-                            .ipSecAllocateSpi(resourceId, "", destinationAddress, requestedSpi);
+                            .ipSecAllocateSpi(callingUid, "", destinationAddress, requestedSpi);
             Log.d(TAG, "Allocated SPI " + spi);
             userRecord.mSpiRecords.put(
                     resourceId,
@@ -1264,7 +1265,8 @@
         // TODO: Check that underlying network exists, and IP addresses not assigned to a different
         //       network (b/72316676).
 
-        UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
+        int callerUid = Binder.getCallingUid();
+        UserRecord userRecord = mUserResourceTracker.getUserRecord(callerUid);
         if (!userRecord.mTunnelQuotaTracker.isAvailable()) {
             return new IpSecTunnelInterfaceResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE);
         }
@@ -1285,7 +1287,7 @@
             for (int selAddrFamily : ADDRESS_FAMILIES) {
                 // Always send down correct local/remote addresses for template.
                 netd.ipSecAddSecurityPolicy(
-                        0, // Use 0 for reqId
+                        callerUid,
                         selAddrFamily,
                         IpSecManager.DIRECTION_OUT,
                         localAddr,
@@ -1294,7 +1296,7 @@
                         okey,
                         0xffffffff);
                 netd.ipSecAddSecurityPolicy(
-                        0, // Use 0 for reqId
+                        callerUid,
                         selAddrFamily,
                         IpSecManager.DIRECTION_IN,
                         remoteAddr,
@@ -1532,7 +1534,7 @@
         mSrvConfig
                 .getNetdInstance()
                 .ipSecAddSecurityAssociation(
-                        resourceId,
+                        Binder.getCallingUid(),
                         c.getMode(),
                         c.getSourceAddress(),
                         c.getDestinationAddress(),
@@ -1623,13 +1625,14 @@
     @Override
     public synchronized void applyTransportModeTransform(
             ParcelFileDescriptor socket, int direction, int resourceId) throws RemoteException {
-        UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
+        int callingUid = Binder.getCallingUid();
+        UserRecord userRecord = mUserResourceTracker.getUserRecord(callingUid);
         checkDirection(direction);
         // Get transform record; if no transform is found, will throw IllegalArgumentException
         TransformRecord info = userRecord.mTransformRecords.getResourceOrThrow(resourceId);
 
         // TODO: make this a function.
-        if (info.pid != getCallingPid() || info.uid != getCallingUid()) {
+        if (info.pid != getCallingPid() || info.uid != callingUid) {
             throw new SecurityException("Only the owner of an IpSec Transform may apply it!");
         }
 
@@ -1643,7 +1646,7 @@
                 .getNetdInstance()
                 .ipSecApplyTransportModeTransform(
                         socket.getFileDescriptor(),
-                        resourceId,
+                        callingUid,
                         direction,
                         c.getSourceAddress(),
                         c.getDestinationAddress(),
@@ -1675,7 +1678,8 @@
         enforceTunnelPermissions(callingPackage);
         checkDirection(direction);
 
-        UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
+        int callingUid = Binder.getCallingUid();
+        UserRecord userRecord = mUserResourceTracker.getUserRecord(callingUid);
 
         // Get transform record; if no transform is found, will throw IllegalArgumentException
         TransformRecord transformInfo =
@@ -1717,7 +1721,7 @@
                     mSrvConfig
                             .getNetdInstance()
                             .ipSecUpdateSecurityPolicy(
-                                    0, // Use 0 for reqId
+                                    callingUid,
                                     selAddrFamily,
                                     direction,
                                     tunnelInterfaceInfo.getLocalAddress(),
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index daf870d..1d163ee 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -1565,10 +1565,11 @@
 
             try {
                 // TODO: support quota shared across interfaces
-                mConnector.execute("bandwidth", "setiquota", iface, quotaBytes);
+                mNetdService.bandwidthSetInterfaceQuota(iface, quotaBytes);
+
                 mActiveQuotas.put(iface, quotaBytes);
-            } catch (NativeDaemonConnectorException e) {
-                throw e.rethrowAsParcelableException();
+            } catch (RemoteException | ServiceSpecificException e) {
+                throw new IllegalStateException(e);
             }
 
             synchronized (mTetheringStatsProviders) {
@@ -1599,9 +1600,9 @@
 
             try {
                 // TODO: support quota shared across interfaces
-                mConnector.execute("bandwidth", "removeiquota", iface);
-            } catch (NativeDaemonConnectorException e) {
-                throw e.rethrowAsParcelableException();
+                mNetdService.bandwidthRemoveInterfaceQuota(iface);
+            } catch (RemoteException | ServiceSpecificException e) {
+                throw new IllegalStateException(e);
             }
 
             synchronized (mTetheringStatsProviders) {
@@ -1633,10 +1634,10 @@
 
             try {
                 // TODO: support alert shared across interfaces
-                mConnector.execute("bandwidth", "setinterfacealert", iface, alertBytes);
+                mNetdService.bandwidthSetInterfaceAlert(iface, alertBytes);
                 mActiveAlerts.put(iface, alertBytes);
-            } catch (NativeDaemonConnectorException e) {
-                throw e.rethrowAsParcelableException();
+            } catch (RemoteException | ServiceSpecificException e) {
+                throw new IllegalStateException(e);
             }
         }
     }
@@ -1653,10 +1654,10 @@
 
             try {
                 // TODO: support alert shared across interfaces
-                mConnector.execute("bandwidth", "removeinterfacealert", iface);
+                mNetdService.bandwidthRemoveInterfaceAlert(iface);
                 mActiveAlerts.remove(iface);
-            } catch (NativeDaemonConnectorException e) {
-                throw e.rethrowAsParcelableException();
+            } catch (RemoteException | ServiceSpecificException e) {
+                throw new IllegalStateException(e);
             }
         }
     }
@@ -1666,18 +1667,15 @@
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
 
         try {
-            mConnector.execute("bandwidth", "setglobalalert", alertBytes);
-        } catch (NativeDaemonConnectorException e) {
-            throw e.rethrowAsParcelableException();
+            mNetdService.bandwidthSetGlobalAlert(alertBytes);
+        } catch (RemoteException | ServiceSpecificException e) {
+            throw new IllegalStateException(e);
         }
     }
 
     private void setUidOnMeteredNetworkList(int uid, boolean blacklist, boolean enable) {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
 
-        final String chain = blacklist ? "naughtyapps" : "niceapps";
-        final String suffix = enable ? "add" : "remove";
-
         synchronized (mQuotaLock) {
             boolean oldEnable;
             SparseBooleanArray quotaList;
@@ -1692,7 +1690,19 @@
 
             Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "inetd bandwidth");
             try {
-                mConnector.execute("bandwidth", suffix + chain, uid);
+                if (blacklist) {
+                    if (enable) {
+                        mNetdService.bandwidthAddNaughtyApp(uid);
+                    } else {
+                        mNetdService.bandwidthRemoveNaughtyApp(uid);
+                    }
+                } else {
+                    if (enable) {
+                        mNetdService.bandwidthAddNiceApp(uid);
+                    } else {
+                        mNetdService.bandwidthRemoveNiceApp(uid);
+                    }
+                }
                 synchronized (mRulesLock) {
                     if (enable) {
                         quotaList.put(uid, true);
@@ -1700,8 +1710,8 @@
                         quotaList.delete(uid);
                     }
                 }
-            } catch (NativeDaemonConnectorException e) {
-                throw e.rethrowAsParcelableException();
+            } catch (RemoteException | ServiceSpecificException e) {
+                throw new IllegalStateException(e);
             } finally {
                 Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
             }
diff --git a/services/core/java/com/android/server/TextServicesManagerService.java b/services/core/java/com/android/server/TextServicesManagerService.java
index 708350d..40f81b3 100644
--- a/services/core/java/com/android/server/TextServicesManagerService.java
+++ b/services/core/java/com/android/server/TextServicesManagerService.java
@@ -20,7 +20,7 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.content.PackageMonitor;
-import com.android.internal.inputmethod.LocaleUtils;
+import com.android.internal.inputmethod.InputMethodUtils;
 import com.android.internal.textservice.ISpellCheckerService;
 import com.android.internal.textservice.ISpellCheckerServiceCallback;
 import com.android.internal.textservice.ISpellCheckerSession;
@@ -461,7 +461,7 @@
         // is pre-installed or not.
         final Locale systemLocal = mContext.getResources().getConfiguration().locale;
         final ArrayList<Locale> suitableLocales =
-                LocaleUtils.getSuitableLocalesForSpellChecker(systemLocal);
+                InputMethodUtils.getSuitableLocalesForSpellChecker(systemLocal);
         if (DBG) {
             Slog.w(TAG, "findAvailSystemSpellCheckerLocked suitableLocales="
                     + Arrays.toString(suitableLocales.toArray(new Locale[suitableLocales.size()])));
@@ -475,7 +475,7 @@
                 final int subtypeCount = info.getSubtypeCount();
                 for (int subtypeIndex = 0; subtypeIndex < subtypeCount; ++subtypeIndex) {
                     final SpellCheckerSubtype subtype = info.getSubtypeAt(subtypeIndex);
-                    final Locale subtypeLocale = LocaleUtils.constructLocaleFromString(
+                    final Locale subtypeLocale = InputMethodUtils.constructLocaleFromString(
                             subtype.getLocale());
                     if (locale.equals(subtypeLocale)) {
                         // TODO: We may have more spell checkers that fall into this category.
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 2ee598f..b64e8b8 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2382,7 +2382,7 @@
                 }
             }
             int logSampleRate = Settings.Global.getInt(mContext.getContentResolver(),
-                    Settings.Global.HIDDEN_API_ACCESS_LOG_SAMPLING_RATE, -1);
+                    Settings.Global.HIDDEN_API_ACCESS_LOG_SAMPLING_RATE, 0x200);
             if (logSampleRate < 0 || logSampleRate > 0x10000) {
                 logSampleRate = -1;
             }
@@ -11941,7 +11941,9 @@
                         printed = true;
                     }
                     pw.print("    "); UserHandle.formatUid(pw, reg.uid);
-                    pw.print(" "); pw.print(reg.pkg); pw.print(":");
+                    pw.print(" "); pw.print(reg.pkg);
+                    final IUidObserver observer = mUidObservers.getRegisteredCallbackItem(i);
+                    pw.print(" "); pw.print(observer.getClass().getTypeName()); pw.print(":");
                     if ((reg.which&ActivityManager.UID_OBSERVER_IDLE) != 0) {
                         pw.print(" IDLE");
                     }
diff --git a/services/core/java/com/android/server/am/BaseErrorDialog.java b/services/core/java/com/android/server/am/BaseErrorDialog.java
index 347a357..cd4d6a3 100644
--- a/services/core/java/com/android/server/am/BaseErrorDialog.java
+++ b/services/core/java/com/android/server/am/BaseErrorDialog.java
@@ -33,7 +33,7 @@
     private boolean mConsuming = true;
 
     public BaseErrorDialog(Context context) {
-        super(context, com.android.internal.R.style.Theme_Dialog_AppError);
+        super(context, com.android.internal.R.style.Theme_DeviceDefault_Dialog_AppError);
         context.assertRuntimeOverlayThemable();
 
         getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
diff --git a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
index 1b688a6..76c191d 100644
--- a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
+++ b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
@@ -26,8 +26,8 @@
 import android.util.Slog;
 import android.util.Spline;
 
-import com.android.internal.util.Preconditions;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
 import com.android.server.display.utils.Plog;
 
 import java.io.PrintWriter;
@@ -77,8 +77,8 @@
                 Slog.w(TAG, "Screen brightness mapping does not cover whole range of available " +
                         "backlight values, autobrightness functionality may be impaired.");
             }
-            BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder();
-            builder.setCurve(luxLevels, brightnessLevelsNits);
+            BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder(
+                    luxLevels, brightnessLevelsNits);
             return new PhysicalMappingStrategy(builder.build(), nitsRange, backlightRange,
                     autoBrightnessAdjustmentMaxGamma);
         } else if (isValidMapping(luxLevels, brightnessLevelsBacklight)) {
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 49f33e0..44fb9ea 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -16,6 +16,7 @@
 package com.android.server.inputmethod;
 
 import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.INVALID_DISPLAY;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
@@ -572,6 +573,11 @@
     IBinder mCurToken;
 
     /**
+     * The displayId of current active input method.
+     */
+    int mCurTokenDisplayId = INVALID_DISPLAY;
+
+    /**
      * If non-null, this is the input method service we are currently connected
      * to.
      */
@@ -1866,7 +1872,9 @@
         mCurAttribute = attribute;
 
         // Check if the input method is changing.
-        if (mCurId != null && mCurId.equals(mCurMethodId)) {
+        final int displayId = mWindowManagerInternal.getDisplayIdForWindow(
+                mCurFocusedWindow);
+        if (mCurId != null && mCurId.equals(mCurMethodId) && displayId == mCurTokenDisplayId) {
             if (cs.curSession != null) {
                 // Fast case: if we are already connected to the input method,
                 // then just return it.
@@ -1930,14 +1938,20 @@
                 com.android.internal.R.string.input_method_binding_label);
         mCurIntent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
                 mContext, 0, new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS), 0));
+        final int displayId = mWindowManagerInternal.getDisplayIdForWindow(mCurFocusedWindow);
+        mCurTokenDisplayId = (displayId != INVALID_DISPLAY) ? displayId : DEFAULT_DISPLAY;
+
         if (bindCurrentInputMethodServiceLocked(mCurIntent, this, IME_CONNECTION_BIND_FLAGS)) {
             mLastBindTime = SystemClock.uptimeMillis();
             mHaveConnection = true;
             mCurId = info.getId();
             mCurToken = new Binder();
             try {
-                if (DEBUG) Slog.v(TAG, "Adding window token: " + mCurToken);
-                mIWindowManager.addWindowToken(mCurToken, TYPE_INPUT_METHOD, DEFAULT_DISPLAY);
+                if (DEBUG) {
+                    Slog.v(TAG, "Adding window token: " + mCurToken + " for display: "
+                            + mCurTokenDisplayId);
+                }
+                mIWindowManager.addWindowToken(mCurToken, TYPE_INPUT_METHOD, mCurTokenDisplayId);
             } catch (RemoteException e) {
             }
             return new InputBindResult(
@@ -1964,8 +1978,9 @@
                     return;
                 }
                 if (DEBUG) Slog.v(TAG, "Initiating attach with token: " + mCurToken);
-                executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
-                        MSG_INITIALIZE_IME, mCurMethod, mCurToken));
+                // Dispatch display id for InputMethodService to update context display.
+                executeOrSendMessage(mCurMethod, mCaller.obtainMessageIOO(
+                        MSG_INITIALIZE_IME, mCurTokenDisplayId, mCurMethod, mCurToken));
                 if (mCurClient != null) {
                     clearClientSessionLocked(mCurClient);
                     requestClientSessionLocked(mCurClient);
@@ -2011,15 +2026,19 @@
 
         if (mCurToken != null) {
             try {
-                if (DEBUG) Slog.v(TAG, "Removing window token: " + mCurToken);
+                if (DEBUG) {
+                    Slog.v(TAG, "Removing window token: " + mCurToken + " for display: "
+                            + mCurTokenDisplayId);
+                }
                 if ((mImeWindowVis & InputMethodService.IME_ACTIVE) != 0 && savePosition) {
                     // The current IME is shown. Hence an IME switch (transition) is happening.
                     mWindowManagerInternal.saveLastInputMethodWindowForTransition();
                 }
-                mIWindowManager.removeWindowToken(mCurToken, DEFAULT_DISPLAY);
+                mIWindowManager.removeWindowToken(mCurToken, mCurTokenDisplayId);
             } catch (RemoteException e) {
             }
             mCurToken = null;
+            mCurTokenDisplayId = INVALID_DISPLAY;
         }
 
         mCurId = null;
@@ -2785,6 +2804,15 @@
                                 // soft input window if it is shown.
                                 if (DEBUG) Slog.v(TAG, "Unspecified window will hide input");
                                 hideCurrentInputLocked(InputMethodManager.HIDE_NOT_ALWAYS, null);
+
+                                // If focused display changed, we should unbind current method
+                                // to make app window in previous display relayout after Ime
+                                // window token removed.
+                                final int newFocusDisplayId =
+                                        mWindowManagerInternal.getDisplayIdForWindow(windowToken);
+                                if (newFocusDisplayId != mCurTokenDisplayId) {
+                                    unbindCurrentMethodLocked(false);
+                                }
                             }
                         } else if (isTextEditor && doAutoShow && (softInputMode &
                                 WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
@@ -3151,7 +3179,7 @@
      */
     @Override
     public int getInputMethodWindowVisibleHeight() {
-        return mWindowManagerInternal.getInputMethodWindowVisibleHeight();
+        return mWindowManagerInternal.getInputMethodWindowVisibleHeight(mCurTokenDisplayId);
     }
 
     @BinderThread
@@ -3352,9 +3380,12 @@
             case MSG_INITIALIZE_IME:
                 args = (SomeArgs)msg.obj;
                 try {
-                    if (DEBUG) Slog.v(TAG, "Sending attach of token: " + args.arg2);
+                    if (DEBUG) {
+                        Slog.v(TAG, "Sending attach of token: " + args.arg2 + " for display: "
+                                + msg.arg1);
+                    }
                     final IBinder token = (IBinder) args.arg2;
-                    ((IInputMethod) args.arg1).initializeInternal(token,
+                    ((IInputMethod) args.arg1).initializeInternal(token, msg.arg1,
                             new InputMethodPrivilegedOperationsImpl(this, token));
                 } catch (RemoteException e) {
                 }
@@ -4516,6 +4547,7 @@
             p.println("  mCurId=" + mCurId + " mHaveConnection=" + mHaveConnection
                     + " mBoundToMethod=" + mBoundToMethod + " mVisibleBound=" + mVisibleBound);
             p.println("  mCurToken=" + mCurToken);
+            p.println("  mCurTokenDisplayId=" + mCurTokenDisplayId);
             p.println("  mCurIntent=" + mCurIntent);
             method = mCurMethod;
             p.println("  mCurMethod=" + mCurMethod);
diff --git a/services/core/java/com/android/server/net/NetworkPolicyLogger.java b/services/core/java/com/android/server/net/NetworkPolicyLogger.java
index b4bc7f5..452b699 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyLogger.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyLogger.java
@@ -46,9 +46,9 @@
     static final boolean LOGV = Log.isLoggable(TAG, Log.VERBOSE);
 
     private static final int MAX_LOG_SIZE =
-            ActivityManager.isLowRamDeviceStatic() ? 20 : 50;
+            ActivityManager.isLowRamDeviceStatic() ? 100 : 400;
     private static final int MAX_NETWORK_BLOCKED_LOG_SIZE =
-            ActivityManager.isLowRamDeviceStatic() ? 50 : 100;
+            ActivityManager.isLowRamDeviceStatic() ? 100 : 400;
 
     private static final int EVENT_TYPE_GENERIC = 0;
     private static final int EVENT_NETWORK_BLOCKED = 1;
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 76f9695..48e09d7 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -796,7 +796,7 @@
             try {
                 mActivityManager.registerUidObserver(mUidObserver,
                         ActivityManager.UID_OBSERVER_PROCSTATE|ActivityManager.UID_OBSERVER_GONE,
-                        ActivityManager.PROCESS_STATE_UNKNOWN, null);
+                        NetworkPolicyManager.FOREGROUND_THRESHOLD_STATE, "android");
                 mNetworkManager.registerObserver(mAlertObserver);
             } catch (RemoteException e) {
                 // ignored; both services live in system_server
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 340ae0a..7751f5f 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -694,7 +694,8 @@
 
             for (int userId : userIds) {
                 if (enabled) {
-                    if (isPackageOrComponentAllowed(component.toString(), userId)) {
+                    if (isPackageOrComponentAllowed(component.toString(), userId)
+                            || isPackageOrComponentAllowed(component.getPackageName(), userId)) {
                         registerServiceLocked(component, userId);
                     } else {
                         Slog.d(TAG, component + " no longer has permission to be bound");
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 593e7cd..13ff6e8 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -107,7 +107,7 @@
     }
 
     // pkg|uid => PackagePreferences
-    private final ArrayMap<String, PackagePreferences> mPackagePreferencess = new ArrayMap<>();
+    private final ArrayMap<String, PackagePreferences> mPackagePreferences = new ArrayMap<>();
     // pkg => PackagePreferences
     private final ArrayMap<String, PackagePreferences> mRestoredWithoutUids = new ArrayMap<>();
 
@@ -142,109 +142,117 @@
         if (type != XmlPullParser.START_TAG) return;
         String tag = parser.getName();
         if (!TAG_RANKING.equals(tag)) return;
-        // Clobber groups and channels with the xml, but don't delete other data that wasn't present
-        // at the time of serialization.
-        mRestoredWithoutUids.clear();
-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
-            tag = parser.getName();
-            if (type == XmlPullParser.END_TAG && TAG_RANKING.equals(tag)) {
-                return;
-            }
-            if (type == XmlPullParser.START_TAG) {
-                if (TAG_PACKAGE.equals(tag)) {
-                    int uid = XmlUtils.readIntAttribute(parser, ATT_UID, UNKNOWN_UID);
-                    String name = parser.getAttributeValue(null, ATT_NAME);
-                    if (!TextUtils.isEmpty(name)) {
-                        if (forRestore) {
-                            try {
-                                //TODO: http://b/22388012
-                                uid = mPm.getPackageUidAsUser(name,
-                                        UserHandle.USER_SYSTEM);
-                            } catch (PackageManager.NameNotFoundException e) {
-                                // noop
-                            }
-                        }
+        synchronized (mPackagePreferences) {
+            // Clobber groups and channels with the xml, but don't delete other data that wasn't present
 
-                        PackagePreferences r = getOrCreatePackagePreferences(name, uid,
-                                XmlUtils.readIntAttribute(
-                                        parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE),
-                                XmlUtils.readIntAttribute(parser, ATT_PRIORITY, DEFAULT_PRIORITY),
-                                XmlUtils.readIntAttribute(
-                                        parser, ATT_VISIBILITY, DEFAULT_VISIBILITY),
-                                XmlUtils.readBooleanAttribute(
-                                        parser, ATT_SHOW_BADGE, DEFAULT_SHOW_BADGE));
-                        r.importance = XmlUtils.readIntAttribute(
-                                parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE);
-                        r.priority = XmlUtils.readIntAttribute(
-                                parser, ATT_PRIORITY, DEFAULT_PRIORITY);
-                        r.visibility = XmlUtils.readIntAttribute(
-                                parser, ATT_VISIBILITY, DEFAULT_VISIBILITY);
-                        r.showBadge = XmlUtils.readBooleanAttribute(
-                                parser, ATT_SHOW_BADGE, DEFAULT_SHOW_BADGE);
-                        r.lockedAppFields = XmlUtils.readIntAttribute(parser,
-                                ATT_APP_USER_LOCKED_FIELDS, DEFAULT_LOCKED_APP_FIELDS);
-
-                        final int innerDepth = parser.getDepth();
-                        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                                && (type != XmlPullParser.END_TAG
-                                || parser.getDepth() > innerDepth)) {
-                            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
-                                continue;
-                            }
-
-                            String tagName = parser.getName();
-                            // Channel groups
-                            if (TAG_GROUP.equals(tagName)) {
-                                String id = parser.getAttributeValue(null, ATT_ID);
-                                CharSequence groupName = parser.getAttributeValue(null, ATT_NAME);
-                                if (!TextUtils.isEmpty(id)) {
-                                    NotificationChannelGroup group
-                                            = new NotificationChannelGroup(id, groupName);
-                                    group.populateFromXml(parser);
-                                    r.groups.put(id, group);
+            // at the time of serialization.
+            mRestoredWithoutUids.clear();
+            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
+                tag = parser.getName();
+                if (type == XmlPullParser.END_TAG && TAG_RANKING.equals(tag)) {
+                    return;
+                }
+                if (type == XmlPullParser.START_TAG) {
+                    if (TAG_PACKAGE.equals(tag)) {
+                        int uid = XmlUtils.readIntAttribute(parser, ATT_UID, UNKNOWN_UID);
+                        String name = parser.getAttributeValue(null, ATT_NAME);
+                        if (!TextUtils.isEmpty(name)) {
+                            if (forRestore) {
+                                try {
+                                    //TODO: http://b/22388012
+                                    uid = mPm.getPackageUidAsUser(name,
+                                            UserHandle.USER_SYSTEM);
+                                } catch (PackageManager.NameNotFoundException e) {
+                                    // noop
                                 }
                             }
-                            // Channels
-                            if (TAG_CHANNEL.equals(tagName)) {
-                                String id = parser.getAttributeValue(null, ATT_ID);
-                                String channelName = parser.getAttributeValue(null, ATT_NAME);
-                                int channelImportance = XmlUtils.readIntAttribute(
-                                        parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE);
-                                if (!TextUtils.isEmpty(id) && !TextUtils.isEmpty(channelName)) {
-                                    NotificationChannel channel = new NotificationChannel(id,
-                                            channelName, channelImportance);
-                                    if (forRestore) {
-                                        channel.populateFromXmlForRestore(parser, mContext);
-                                    } else {
-                                        channel.populateFromXml(parser);
+
+                            PackagePreferences r = getOrCreatePackagePreferences(name, uid,
+                                    XmlUtils.readIntAttribute(
+                                            parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE),
+                                    XmlUtils.readIntAttribute(parser, ATT_PRIORITY,
+                                            DEFAULT_PRIORITY),
+                                    XmlUtils.readIntAttribute(
+                                            parser, ATT_VISIBILITY, DEFAULT_VISIBILITY),
+                                    XmlUtils.readBooleanAttribute(
+                                            parser, ATT_SHOW_BADGE, DEFAULT_SHOW_BADGE));
+                            r.importance = XmlUtils.readIntAttribute(
+                                    parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE);
+                            r.priority = XmlUtils.readIntAttribute(
+                                    parser, ATT_PRIORITY, DEFAULT_PRIORITY);
+                            r.visibility = XmlUtils.readIntAttribute(
+                                    parser, ATT_VISIBILITY, DEFAULT_VISIBILITY);
+                            r.showBadge = XmlUtils.readBooleanAttribute(
+                                    parser, ATT_SHOW_BADGE, DEFAULT_SHOW_BADGE);
+                            r.lockedAppFields = XmlUtils.readIntAttribute(parser,
+                                    ATT_APP_USER_LOCKED_FIELDS, DEFAULT_LOCKED_APP_FIELDS);
+
+                            final int innerDepth = parser.getDepth();
+                            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                                    && (type != XmlPullParser.END_TAG
+                                    || parser.getDepth() > innerDepth)) {
+                                if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                                    continue;
+                                }
+
+                                String tagName = parser.getName();
+                                // Channel groups
+                                if (TAG_GROUP.equals(tagName)) {
+                                    String id = parser.getAttributeValue(null, ATT_ID);
+                                    CharSequence groupName = parser.getAttributeValue(null,
+                                            ATT_NAME);
+                                    if (!TextUtils.isEmpty(id)) {
+                                        NotificationChannelGroup group
+                                                = new NotificationChannelGroup(id, groupName);
+                                        group.populateFromXml(parser);
+                                        r.groups.put(id, group);
                                     }
-                                    r.channels.put(id, channel);
                                 }
-                            }
-                            // Delegate
-                            if (TAG_DELEGATE.equals(tagName)) {
-                                int delegateId =
-                                        XmlUtils.readIntAttribute(parser, ATT_UID, UNKNOWN_UID);
-                                String delegateName =
-                                        XmlUtils.readStringAttribute(parser, ATT_NAME);
-                                boolean delegateEnabled = XmlUtils.readBooleanAttribute(
-                                        parser, ATT_ENABLED, Delegate.DEFAULT_ENABLED);
-                                boolean userAllowed = XmlUtils.readBooleanAttribute(
-                                        parser, ATT_USER_ALLOWED, Delegate.DEFAULT_USER_ALLOWED);
-                                Delegate d = null;
-                                if (delegateId != UNKNOWN_UID && !TextUtils.isEmpty(delegateName)) {
-                                    d = new Delegate(
-                                            delegateName, delegateId, delegateEnabled, userAllowed);
+                                // Channels
+                                if (TAG_CHANNEL.equals(tagName)) {
+                                    String id = parser.getAttributeValue(null, ATT_ID);
+                                    String channelName = parser.getAttributeValue(null, ATT_NAME);
+                                    int channelImportance = XmlUtils.readIntAttribute(
+                                            parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE);
+                                    if (!TextUtils.isEmpty(id) && !TextUtils.isEmpty(channelName)) {
+                                        NotificationChannel channel = new NotificationChannel(id,
+                                                channelName, channelImportance);
+                                        if (forRestore) {
+                                            channel.populateFromXmlForRestore(parser, mContext);
+                                        } else {
+                                            channel.populateFromXml(parser);
+                                        }
+                                        r.channels.put(id, channel);
+                                    }
                                 }
-                                r.delegate = d;
+                                // Delegate
+                                if (TAG_DELEGATE.equals(tagName)) {
+                                    int delegateId =
+                                            XmlUtils.readIntAttribute(parser, ATT_UID, UNKNOWN_UID);
+                                    String delegateName =
+                                            XmlUtils.readStringAttribute(parser, ATT_NAME);
+                                    boolean delegateEnabled = XmlUtils.readBooleanAttribute(
+                                            parser, ATT_ENABLED, Delegate.DEFAULT_ENABLED);
+                                    boolean userAllowed = XmlUtils.readBooleanAttribute(
+                                            parser, ATT_USER_ALLOWED,
+                                            Delegate.DEFAULT_USER_ALLOWED);
+                                    Delegate d = null;
+                                    if (delegateId != UNKNOWN_UID && !TextUtils.isEmpty(
+                                            delegateName)) {
+                                        d = new Delegate(
+                                                delegateName, delegateId, delegateEnabled,
+                                                userAllowed);
+                                    }
+                                    r.delegate = d;
+                                }
+
                             }
 
-                        }
-
-                        try {
-                            deleteDefaultChannelIfNeeded(r);
-                        } catch (PackageManager.NameNotFoundException e) {
-                            Slog.e(TAG, "deleteDefaultChannelIfNeeded - Exception: " + e);
+                            try {
+                                deleteDefaultChannelIfNeeded(r);
+                            } catch (PackageManager.NameNotFoundException e) {
+                                Slog.e(TAG, "deleteDefaultChannelIfNeeded - Exception: " + e);
+                            }
                         }
                     }
                 }
@@ -255,8 +263,8 @@
 
     private PackagePreferences getPackagePreferences(String pkg, int uid) {
         final String key = packagePreferencesKey(pkg, uid);
-        synchronized (mPackagePreferencess) {
-            return mPackagePreferencess.get(key);
+        synchronized (mPackagePreferences) {
+            return mPackagePreferences.get(key);
         }
     }
 
@@ -268,10 +276,10 @@
     private PackagePreferences getOrCreatePackagePreferences(String pkg, int uid, int importance,
             int priority, int visibility, boolean showBadge) {
         final String key = packagePreferencesKey(pkg, uid);
-        synchronized (mPackagePreferencess) {
+        synchronized (mPackagePreferences) {
             PackagePreferences
                     r = (uid == UNKNOWN_UID) ? mRestoredWithoutUids.get(pkg)
-                    : mPackagePreferencess.get(key);
+                    : mPackagePreferences.get(key);
             if (r == null) {
                 r = new PackagePreferences();
                 r.pkg = pkg;
@@ -290,7 +298,7 @@
                 if (r.uid == UNKNOWN_UID) {
                     mRestoredWithoutUids.put(pkg, r);
                 } else {
-                    mPackagePreferencess.put(key, r);
+                    mPackagePreferences.put(key, r);
                 }
             }
             return r;
@@ -364,10 +372,10 @@
         out.startTag(null, TAG_RANKING);
         out.attribute(null, ATT_VERSION, Integer.toString(XML_VERSION));
 
-        synchronized (mPackagePreferencess) {
-            final int N = mPackagePreferencess.size();
+        synchronized (mPackagePreferences) {
+            final int N = mPackagePreferences.size();
             for (int i = 0; i < N; i++) {
-                final PackagePreferences r = mPackagePreferencess.valueAt(i);
+                final PackagePreferences r = mPackagePreferences.valueAt(i);
                 //TODO: http://b/22388012
                 if (forBackup && UserHandle.getUserId(r.uid) != UserHandle.USER_SYSTEM) {
                     continue;
@@ -882,10 +890,10 @@
 
     public int getBlockedAppCount(int userId) {
         int count = 0;
-        synchronized (mPackagePreferencess) {
-            final int N = mPackagePreferencess.size();
+        synchronized (mPackagePreferences) {
+            final int N = mPackagePreferences.size();
             for (int i = 0; i < N; i++) {
-                final PackagePreferences r = mPackagePreferencess.valueAt(i);
+                final PackagePreferences r = mPackagePreferences.valueAt(i);
                 if (userId == UserHandle.getUserId(r.uid)
                         && r.importance == IMPORTANCE_NONE) {
                     count++;
@@ -896,11 +904,11 @@
     }
 
     public void updateChannelsBypassingDnd() {
-        synchronized (mPackagePreferencess) {
-            final int numPackagePreferencess = mPackagePreferencess.size();
+        synchronized (mPackagePreferences) {
+            final int numPackagePreferencess = mPackagePreferences.size();
             for (int PackagePreferencesIndex = 0; PackagePreferencesIndex < numPackagePreferencess;
                     PackagePreferencesIndex++) {
-                final PackagePreferences r = mPackagePreferencess.valueAt(PackagePreferencesIndex);
+                final PackagePreferences r = mPackagePreferences.valueAt(PackagePreferencesIndex);
                 final int numChannels = r.channels.size();
 
                 for (int channelIndex = 0; channelIndex < numChannels; channelIndex++) {
@@ -1064,8 +1072,8 @@
         pw.println("per-package config:");
 
         pw.println("PackagePreferencess:");
-        synchronized (mPackagePreferencess) {
-            dumpPackagePreferencess(pw, prefix, filter, mPackagePreferencess);
+        synchronized (mPackagePreferences) {
+            dumpPackagePreferencess(pw, prefix, filter, mPackagePreferences);
         }
         pw.println("Restored without uid:");
         dumpPackagePreferencess(pw, prefix, filter, mRestoredWithoutUids);
@@ -1073,9 +1081,9 @@
 
     public void dump(ProtoOutputStream proto,
             @NonNull NotificationManagerService.DumpFilter filter) {
-        synchronized (mPackagePreferencess) {
+        synchronized (mPackagePreferences) {
             dumpPackagePreferencess(proto, RankingHelperProto.RECORDS, filter,
-                    mPackagePreferencess);
+                    mPackagePreferences);
         }
         dumpPackagePreferencess(proto, RankingHelperProto.RECORDS_RESTORED_WITHOUT_UID, filter,
                 mRestoredWithoutUids);
@@ -1160,10 +1168,10 @@
         } catch (JSONException e) {
             // pass
         }
-        synchronized (mPackagePreferencess) {
-            final int N = mPackagePreferencess.size();
+        synchronized (mPackagePreferences) {
+            final int N = mPackagePreferences.size();
             for (int i = 0; i < N; i++) {
-                final PackagePreferences r = mPackagePreferencess.valueAt(i);
+                final PackagePreferences r = mPackagePreferences.valueAt(i);
                 if (filter == null || filter.matches(r.pkg)) {
                     JSONObject PackagePreferences = new JSONObject();
                     try {
@@ -1240,11 +1248,11 @@
     }
 
     public Map<Integer, String> getPackageBans() {
-        synchronized (mPackagePreferencess) {
-            final int N = mPackagePreferencess.size();
+        synchronized (mPackagePreferences) {
+            final int N = mPackagePreferences.size();
             ArrayMap<Integer, String> packageBans = new ArrayMap<>(N);
             for (int i = 0; i < N; i++) {
-                final PackagePreferences r = mPackagePreferencess.valueAt(i);
+                final PackagePreferences r = mPackagePreferences.valueAt(i);
                 if (r.importance == IMPORTANCE_NONE) {
                     packageBans.put(r.uid, r.pkg);
                 }
@@ -1284,9 +1292,9 @@
 
     private Map<String, Integer> getPackageChannels() {
         ArrayMap<String, Integer> packageChannels = new ArrayMap<>();
-        synchronized (mPackagePreferencess) {
-            for (int i = 0; i < mPackagePreferencess.size(); i++) {
-                final PackagePreferences r = mPackagePreferencess.valueAt(i);
+        synchronized (mPackagePreferences) {
+            for (int i = 0; i < mPackagePreferences.size(); i++) {
+                final PackagePreferences r = mPackagePreferences.valueAt(i);
                 int channelCount = 0;
                 for (int j = 0; j < r.channels.size(); j++) {
                     if (!r.channels.valueAt(j).isDeleted()) {
@@ -1300,22 +1308,22 @@
     }
 
     public void onUserRemoved(int userId) {
-        synchronized (mPackagePreferencess) {
-            int N = mPackagePreferencess.size();
+        synchronized (mPackagePreferences) {
+            int N = mPackagePreferences.size();
             for (int i = N - 1; i >= 0; i--) {
-                PackagePreferences PackagePreferences = mPackagePreferencess.valueAt(i);
+                PackagePreferences PackagePreferences = mPackagePreferences.valueAt(i);
                 if (UserHandle.getUserId(PackagePreferences.uid) == userId) {
-                    mPackagePreferencess.removeAt(i);
+                    mPackagePreferences.removeAt(i);
                 }
             }
         }
     }
 
     protected void onLocaleChanged(Context context, int userId) {
-        synchronized (mPackagePreferencess) {
-            int N = mPackagePreferencess.size();
+        synchronized (mPackagePreferences) {
+            int N = mPackagePreferences.size();
             for (int i = 0; i < N; i++) {
-                PackagePreferences PackagePreferences = mPackagePreferencess.valueAt(i);
+                PackagePreferences PackagePreferences = mPackagePreferences.valueAt(i);
                 if (UserHandle.getUserId(PackagePreferences.uid) == userId) {
                     if (PackagePreferences.channels.containsKey(
                             NotificationChannel.DEFAULT_CHANNEL_ID)) {
@@ -1341,8 +1349,8 @@
             for (int i = 0; i < size; i++) {
                 final String pkg = pkgList[i];
                 final int uid = uidList[i];
-                synchronized (mPackagePreferencess) {
-                    mPackagePreferencess.remove(packagePreferencesKey(pkg, uid));
+                synchronized (mPackagePreferences) {
+                    mPackagePreferences.remove(packagePreferencesKey(pkg, uid));
                 }
                 mRestoredWithoutUids.remove(pkg);
                 updated = true;
@@ -1355,8 +1363,8 @@
                     try {
                         r.uid = mPm.getPackageUidAsUser(r.pkg, changeUserId);
                         mRestoredWithoutUids.remove(pkg);
-                        synchronized (mPackagePreferencess) {
-                            mPackagePreferencess.put(packagePreferencesKey(r.pkg, r.uid), r);
+                        synchronized (mPackagePreferences) {
+                            mPackagePreferences.put(packagePreferencesKey(r.pkg, r.uid), r);
                         }
                         updated = true;
                     } catch (PackageManager.NameNotFoundException e) {
@@ -1365,11 +1373,13 @@
                 }
                 // Package upgrade
                 try {
-                    PackagePreferences fullPackagePreferences = getPackagePreferences(pkg,
-                            mPm.getPackageUidAsUser(pkg, changeUserId));
-                    if (fullPackagePreferences != null) {
-                        createDefaultChannelIfNeeded(fullPackagePreferences);
-                        deleteDefaultChannelIfNeeded(fullPackagePreferences);
+                    synchronized (mPackagePreferences) {
+                        PackagePreferences fullPackagePreferences = getPackagePreferences(pkg,
+                                mPm.getPackageUidAsUser(pkg, changeUserId));
+                        if (fullPackagePreferences != null) {
+                            createDefaultChannelIfNeeded(fullPackagePreferences);
+                            deleteDefaultChannelIfNeeded(fullPackagePreferences);
+                        }
                     }
                 } catch (PackageManager.NameNotFoundException e) {
                 }
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index c738701..f1b03d1 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -558,8 +558,8 @@
         @Override
         public boolean setEnabledExclusive(@Nullable final String packageName, final boolean enable,
                 int userId) throws RemoteException {
-            enforceChangeOverlayPackagesPermission("setEnabled");
-            userId = handleIncomingUser(userId, "setEnabled");
+            enforceChangeOverlayPackagesPermission("setEnabledExclusive");
+            userId = handleIncomingUser(userId, "setEnabledExclusive");
             if (packageName == null || !enable) {
                 return false;
             }
@@ -578,8 +578,8 @@
         @Override
         public boolean setEnabledExclusiveInCategory(@Nullable String packageName, int userId)
                 throws RemoteException {
-            enforceChangeOverlayPackagesPermission("setEnabled");
-            userId = handleIncomingUser(userId, "setEnabled");
+            enforceChangeOverlayPackagesPermission("setEnabledExclusiveInCategory");
+            userId = handleIncomingUser(userId, "setEnabledExclusiveInCategory");
             if (packageName == null) {
                 return false;
             }
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index d305032..8f2833f 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -59,6 +59,7 @@
 import android.content.pm.PackageParser.ApkLite;
 import android.content.pm.PackageParser.PackageLite;
 import android.content.pm.PackageParser.PackageParserException;
+import android.content.pm.dex.DexMetadataHelper;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.os.Binder;
@@ -99,7 +100,6 @@
 import com.android.server.pm.Installer.InstallerException;
 import com.android.server.pm.PackageInstallerService.PackageInstallObserverAdapter;
 
-import android.content.pm.dex.DexMetadataHelper;
 import libcore.io.IoUtils;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -122,7 +122,6 @@
     private static final boolean LOGD = true;
     private static final String REMOVE_SPLIT_MARKER_EXTENSION = ".removed";
 
-    private static final int MSG_EARLY_BIND = 0;
     private static final int MSG_COMMIT = 1;
     private static final int MSG_ON_PACKAGE_INSTALLED = 2;
 
@@ -168,7 +167,6 @@
     final int userId;
     final SessionParams params;
     final long createdMillis;
-    final int defaultContainerGid;
 
     /** Staging location where client data is written. */
     final File stageDir;
@@ -285,9 +283,6 @@
         @Override
         public boolean handleMessage(Message msg) {
             switch (msg.what) {
-                case MSG_EARLY_BIND:
-                    earlyBindToDefContainer();
-                    break;
                 case MSG_COMMIT:
                     synchronized (mLock) {
                         try {
@@ -323,10 +318,6 @@
         }
     };
 
-    private void earlyBindToDefContainer() {
-        mPm.earlyBindToDefContainer();
-    }
-
     /**
      * @return {@code true} iff the installing is app an device owner or affiliated profile owner.
      */
@@ -413,19 +404,6 @@
                 }
             }
         }
-
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            final int uid = mPm.getPackageUid(PackageManagerService.DEFAULT_CONTAINER_PACKAGE,
-                    PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM);
-            defaultContainerGid = UserHandle.getSharedAppGid(uid);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-        // attempt to bind to the DefContainer as early as possible
-        if ((params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0) {
-            mHandler.sendMessage(mHandler.obtainMessage(MSG_EARLY_BIND));
-        }
     }
 
     public SessionInfo generateInfo() {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index cacdccb..adf95dc 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -88,8 +88,6 @@
 import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
 import static android.os.storage.StorageManager.FLAG_STORAGE_CE;
 import static android.os.storage.StorageManager.FLAG_STORAGE_DE;
-import static android.system.OsConstants.O_CREAT;
-import static android.system.OsConstants.O_RDWR;
 
 import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE;
 import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_PARENT;
@@ -137,7 +135,6 @@
 import android.content.IntentFilter;
 import android.content.IntentSender;
 import android.content.IntentSender.SendIntentException;
-import android.content.ServiceConnection;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.AppsQueryHelper;
@@ -207,14 +204,12 @@
 import android.os.Bundle;
 import android.os.Debug;
 import android.os.Environment;
-import android.os.Environment.UserEnvironment;
 import android.os.FileUtils;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
 import android.os.Parcel;
-import android.os.ParcelFileDescriptor;
 import android.os.PatternMatcher;
 import android.os.PersistableBundle;
 import android.os.Process;
@@ -273,12 +268,10 @@
 
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
-import com.android.internal.app.IMediaContainerService;
 import com.android.internal.app.ResolverActivity;
 import com.android.internal.content.NativeLibraryHelper;
 import com.android.internal.content.PackageHelper;
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.os.IParcelFileDescriptorFactory;
 import com.android.internal.os.SomeArgs;
 import com.android.internal.os.Zygote;
 import com.android.internal.telephony.CarrierAppUtils;
@@ -551,12 +544,6 @@
 
     public static final String PLATFORM_PACKAGE_NAME = "android";
 
-    public static final String DEFAULT_CONTAINER_PACKAGE = "com.android.defcontainer";
-
-    public static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName(
-            DEFAULT_CONTAINER_PACKAGE,
-            "com.android.defcontainer.DefaultContainerService");
-
     private static final String KILL_APP_REASON_GIDS_CHANGED =
             "permission grant or revoke changed gids";
 
@@ -1238,18 +1225,9 @@
     }
     final PendingPackageBroadcasts mPendingBroadcasts = new PendingPackageBroadcasts();
 
-    // Service Connection to remote media container service to copy
-    // package uri's from external media onto secure containers
-    // or internal storage.
-    private IMediaContainerService mContainerService = null;
-
     static final int SEND_PENDING_BROADCAST = 1;
-    static final int MCS_BOUND = 3;
     static final int INIT_COPY = 5;
-    static final int MCS_UNBIND = 6;
     static final int POST_INSTALL = 9;
-    static final int MCS_RECONNECT = 10;
-    static final int MCS_GIVE_UP = 11;
     static final int WRITE_SETTINGS = 13;
     static final int WRITE_PACKAGE_RESTRICTIONS = 14;
     static final int PACKAGE_VERIFIED = 15;
@@ -1258,7 +1236,6 @@
     static final int INTENT_FILTER_VERIFIED = 18;
     static final int WRITE_PACKAGE_LIST = 19;
     static final int INSTANT_APP_RESOLUTION_PHASE_TWO = 20;
-    static final int DEF_CONTAINER_BIND = 21;
 
     static final int WRITE_SETTINGS_DELAY = 10*1000;  // 10 seconds
 
@@ -1273,21 +1250,6 @@
     // Stores a list of users whose package restrictions file needs to be updated
     private ArraySet<Integer> mDirtyUsers = new ArraySet<>();
 
-    final private DefaultContainerConnection mDefContainerConn =
-            new DefaultContainerConnection();
-    class DefaultContainerConnection implements ServiceConnection {
-        public void onServiceConnected(ComponentName name, IBinder service) {
-            if (DEBUG_SD_INSTALL) Log.i(TAG, "onServiceConnected");
-            final IMediaContainerService imcs = IMediaContainerService.Stub
-                    .asInterface(Binder.allowBlocking(service));
-            mHandler.sendMessage(mHandler.obtainMessage(MCS_BOUND, imcs));
-        }
-
-        public void onServiceDisconnected(ComponentName name) {
-            if (DEBUG_SD_INSTALL) Log.i(TAG, "onServiceDisconnected");
-        }
-    }
-
     // Recordkeeping of restore-after-install operations that are currently in flight
     // between the Package Manager and the Backup Manager
     static class PostInstallData {
@@ -1346,31 +1308,6 @@
     private final CompilerStats mCompilerStats = new CompilerStats();
 
     class PackageHandler extends Handler {
-        private boolean mBound = false;
-        final ArrayList<HandlerParams> mPendingInstalls =
-                new ArrayList<>();
-
-        private boolean connectToService() {
-            if (DEBUG_INSTALL) Log.i(TAG, "Trying to bind to DefaultContainerService");
-            Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
-            Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
-            if (mContext.bindServiceAsUser(service, mDefContainerConn,
-                    Context.BIND_AUTO_CREATE, UserHandle.SYSTEM)) {
-                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
-                mBound = true;
-                return true;
-            }
-            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
-            return false;
-        }
-
-        private void disconnectService() {
-            mContainerService = null;
-            mBound = false;
-            Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
-            mContext.unbindService(mDefContainerConn);
-            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
-        }
 
         PackageHandler(Looper looper) {
             super(looper);
@@ -1386,167 +1323,18 @@
 
         void doHandleMessage(Message msg) {
             switch (msg.what) {
-                case DEF_CONTAINER_BIND:
-                    if (!mBound) {
-                        Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "earlyBindingMCS",
-                                System.identityHashCode(mHandler));
-                        if (!connectToService()) {
-                            Slog.e(TAG, "Failed to bind to media container service");
-                        }
-                        Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "earlyBindingMCS",
-                                System.identityHashCode(mHandler));
-                    }
-                    break;
                 case INIT_COPY: {
                     HandlerParams params = (HandlerParams) msg.obj;
-                    int idx = mPendingInstalls.size();
-                    if (DEBUG_INSTALL) Slog.i(TAG, "init_copy idx=" + idx + ": " + params);
-                    // If a bind was already initiated we dont really
-                    // need to do anything. The pending install
-                    // will be processed later on.
-                    if (!mBound) {
-                        Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS",
-                                System.identityHashCode(mHandler));
-                        // If this is the only one pending we might
-                        // have to bind to the service again.
-                        if (!connectToService()) {
-                            Slog.e(TAG, "Failed to bind to media container service");
-                            params.serviceError();
-                            Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS",
-                                    System.identityHashCode(mHandler));
-                            if (params.traceMethod != null) {
-                                Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, params.traceMethod,
-                                        params.traceCookie);
-                            }
-                            return;
-                        } else {
-                            // Once we bind to the service, the first
-                            // pending request will be processed.
-                            mPendingInstalls.add(idx, params);
-                        }
-                    } else {
-                        mPendingInstalls.add(idx, params);
-                        // Already bound to the service. Just make
-                        // sure we trigger off processing the first request.
-                        if (idx == 0) {
-                            mHandler.sendEmptyMessage(MCS_BOUND);
-                        }
+                    if (params != null) {
+                        if (DEBUG_INSTALL) Slog.i(TAG, "init_copy: " + params);
+                        Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
+                                System.identityHashCode(params));
+                        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "startCopy");
+                        params.startCopy();
+                        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                     }
                     break;
                 }
-                case MCS_BOUND: {
-                    if (DEBUG_INSTALL) Slog.i(TAG, "mcs_bound");
-                    if (msg.obj != null) {
-                        mContainerService = (IMediaContainerService) msg.obj;
-                        Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS",
-                                System.identityHashCode(mHandler));
-                    }
-                    if (mContainerService == null) {
-                        if (!mBound) {
-                            // Something seriously wrong since we are not bound and we are not
-                            // waiting for connection. Bail out.
-                            Slog.e(TAG, "Cannot bind to media container service");
-                            for (HandlerParams params : mPendingInstalls) {
-                                // Indicate service bind error
-                                params.serviceError();
-                                Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
-                                        System.identityHashCode(params));
-                                if (params.traceMethod != null) {
-                                    Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER,
-                                            params.traceMethod, params.traceCookie);
-                                }
-                            }
-                            mPendingInstalls.clear();
-                        } else {
-                            Slog.w(TAG, "Waiting to connect to media container service");
-                        }
-                    } else if (mPendingInstalls.size() > 0) {
-                        HandlerParams params = mPendingInstalls.get(0);
-                        if (params != null) {
-                            Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
-                                    System.identityHashCode(params));
-                            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "startCopy");
-                            if (params.startCopy()) {
-                                // We are done...  look for more work or to
-                                // go idle.
-                                if (DEBUG_SD_INSTALL) Log.i(TAG,
-                                        "Checking for more work or unbind...");
-                                // Delete pending install
-                                if (mPendingInstalls.size() > 0) {
-                                    mPendingInstalls.remove(0);
-                                }
-                                if (mPendingInstalls.size() == 0) {
-                                    if (mBound) {
-                                        if (DEBUG_SD_INSTALL) Log.i(TAG,
-                                                "Posting delayed MCS_UNBIND");
-                                        removeMessages(MCS_UNBIND);
-                                        Message ubmsg = obtainMessage(MCS_UNBIND);
-                                        // Unbind after a little delay, to avoid
-                                        // continual thrashing.
-                                        sendMessageDelayed(ubmsg, 10000);
-                                    }
-                                } else {
-                                    // There are more pending requests in queue.
-                                    // Just post MCS_BOUND message to trigger processing
-                                    // of next pending install.
-                                    if (DEBUG_SD_INSTALL) Log.i(TAG,
-                                            "Posting MCS_BOUND for next work");
-                                    mHandler.sendEmptyMessage(MCS_BOUND);
-                                }
-                            }
-                            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
-                        }
-                    } else {
-                        // Should never happen ideally.
-                        Slog.w(TAG, "Empty queue");
-                    }
-                    break;
-                }
-                case MCS_RECONNECT: {
-                    if (DEBUG_INSTALL) Slog.i(TAG, "mcs_reconnect");
-                    if (mPendingInstalls.size() > 0) {
-                        if (mBound) {
-                            disconnectService();
-                        }
-                        if (!connectToService()) {
-                            Slog.e(TAG, "Failed to bind to media container service");
-                            for (HandlerParams params : mPendingInstalls) {
-                                // Indicate service bind error
-                                params.serviceError();
-                                Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
-                                        System.identityHashCode(params));
-                            }
-                            mPendingInstalls.clear();
-                        }
-                    }
-                    break;
-                }
-                case MCS_UNBIND: {
-                    // If there is no actual work left, then time to unbind.
-                    if (DEBUG_INSTALL) Slog.i(TAG, "mcs_unbind");
-
-                    if (mPendingInstalls.size() == 0 && mPendingVerification.size() == 0) {
-                        if (mBound) {
-                            if (DEBUG_INSTALL) Slog.i(TAG, "calling disconnectService()");
-
-                            disconnectService();
-                        }
-                    } else if (mPendingInstalls.size() > 0) {
-                        // There are more pending requests in queue.
-                        // Just post MCS_BOUND message to trigger processing
-                        // of next pending install.
-                        mHandler.sendEmptyMessage(MCS_BOUND);
-                    }
-
-                    break;
-                }
-                case MCS_GIVE_UP: {
-                    if (DEBUG_INSTALL) Slog.i(TAG, "mcs_giveup too many retries");
-                    HandlerParams params = mPendingInstalls.remove(0);
-                    Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
-                            System.identityHashCode(params));
-                    break;
-                }
                 case SEND_PENDING_BROADCAST: {
                     String packages[];
                     ArrayList<String> components[];
@@ -1685,11 +1473,7 @@
                                     PackageManager.VERIFICATION_ALLOW_WITHOUT_SUFFICIENT);
                             broadcastPackageVerified(verificationId, originUri,
                                     PackageManager.VERIFICATION_ALLOW, user);
-                            try {
-                                ret = args.copyApk(mContainerService, true);
-                            } catch (RemoteException e) {
-                                Slog.e(TAG, "Could not contact the ContainerService");
-                            }
+                            ret = args.copyApk();
                         } else {
                             broadcastPackageVerified(verificationId, originUri,
                                     PackageManager.VERIFICATION_REJECT, user);
@@ -1699,7 +1483,6 @@
                                 TRACE_TAG_PACKAGE_MANAGER, "verification", verificationId);
 
                         processPendingInstall(args, ret);
-                        mHandler.sendEmptyMessage(MCS_UNBIND);
                     }
                     break;
                 }
@@ -1724,14 +1507,9 @@
 
                         int ret;
                         if (state.isInstallAllowed()) {
-                            ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
                             broadcastPackageVerified(verificationId, originUri,
                                     response.code, state.getInstallArgs().getUser());
-                            try {
-                                ret = args.copyApk(mContainerService, true);
-                            } catch (RemoteException e) {
-                                Slog.e(TAG, "Could not contact the ContainerService");
-                            }
+                            ret = args.copyApk();
                         } else {
                             ret = PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE;
                         }
@@ -1740,7 +1518,6 @@
                                 TRACE_TAG_PACKAGE_MANAGER, "verification", verificationId);
 
                         processPendingInstall(args, ret);
-                        mHandler.sendEmptyMessage(MCS_UNBIND);
                     }
 
                     break;
@@ -12430,14 +12207,6 @@
         return installReason;
     }
 
-    /**
-     * Attempts to bind to the default container service explicitly instead of doing so lazily on
-     * install commit.
-     */
-    void earlyBindToDefContainer() {
-        mHandler.sendMessage(mHandler.obtainMessage(DEF_CONTAINER_BIND));
-    }
-
     void installStage(String packageName, File stagedDir,
             IPackageInstallObserver2 observer, PackageInstaller.SessionParams sessionParams,
             String installerPackageName, int installerUid, UserHandle user,
@@ -13784,14 +13553,6 @@
     }
 
     private abstract class HandlerParams {
-        private static final int MAX_RETRIES = 4;
-
-        /**
-         * Number of times startCopy() has been attempted and had a non-fatal
-         * error.
-         */
-        private int mRetries = 0;
-
         /** User handle for the user requesting the information or installation. */
         private final UserHandle mUser;
         String traceMethod;
@@ -13815,37 +13576,13 @@
             return this;
         }
 
-        final boolean startCopy() {
-            boolean res;
-            try {
-                if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
-
-                if (++mRetries > MAX_RETRIES) {
-                    Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
-                    mHandler.sendEmptyMessage(MCS_GIVE_UP);
-                    handleServiceError();
-                    return false;
-                } else {
-                    handleStartCopy();
-                    res = true;
-                }
-            } catch (RemoteException e) {
-                if (DEBUG_INSTALL) Slog.i(TAG, "Posting install MCS_RECONNECT");
-                mHandler.sendEmptyMessage(MCS_RECONNECT);
-                res = false;
-            }
-            handleReturnCode();
-            return res;
-        }
-
-        final void serviceError() {
-            if (DEBUG_INSTALL) Slog.i(TAG, "serviceError");
-            handleServiceError();
+        final void startCopy() {
+            if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
+            handleStartCopy();
             handleReturnCode();
         }
 
-        abstract void handleStartCopy() throws RemoteException;
-        abstract void handleServiceError();
+        abstract void handleStartCopy();
         abstract void handleReturnCode();
     }
 
@@ -14088,7 +13825,7 @@
          * policy if needed and then create install arguments based
          * on the install location.
          */
-        public void handleStartCopy() throws RemoteException {
+        public void handleStartCopy() {
             int ret = PackageManager.INSTALL_SUCCEEDED;
 
             // If we're already staged, we've firmly committed to an install location
@@ -14114,8 +13851,8 @@
                 Slog.w(TAG,  "Conflicting flags specified for installing ephemeral on external");
                 ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
             } else {
-                pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath, installFlags,
-                        packageAbiOverride);
+                pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
+                        origin.resolvedPath, installFlags, packageAbiOverride);
 
                 if (DEBUG_INSTANT && ephemeral) {
                     Slog.v(TAG, "pkgLite for install: " + pkgLite);
@@ -14132,15 +13869,16 @@
                     final long lowThreshold = storage.getStorageLowBytes(
                             Environment.getDataDirectory());
 
-                    final long sizeBytes = mContainerService.calculateInstalledSize(
+                    final long sizeBytes = PackageManagerServiceUtils.calculateInstalledSize(
                             origin.resolvedPath, packageAbiOverride);
-
-                    try {
-                        mInstaller.freeCache(null, sizeBytes + lowThreshold, 0, 0);
-                        pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath,
-                                installFlags, packageAbiOverride);
-                    } catch (InstallerException e) {
-                        Slog.w(TAG, "Failed to free cache", e);
+                    if (sizeBytes >= 0) {
+                        try {
+                            mInstaller.freeCache(null, sizeBytes + lowThreshold, 0, 0);
+                            pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
+                                    origin.resolvedPath, installFlags, packageAbiOverride);
+                        } catch (InstallerException e) {
+                            Slog.w(TAG, "Failed to free cache", e);
+                        }
                     }
 
                     /*
@@ -14351,7 +14089,7 @@
                      * No package verification is enabled, so immediately start
                      * the remote call to initiate copy using temporary file.
                      */
-                    ret = args.copyApk(mContainerService, true);
+                    ret = args.copyApk();
                 }
             }
 
@@ -14360,19 +14098,10 @@
 
         @Override
         void handleReturnCode() {
-            // If mArgs is null, then MCS couldn't be reached. When it
-            // reconnects, it will try again to install. At that point, this
-            // will succeed.
             if (mArgs != null) {
                 processPendingInstall(mArgs, mRet);
             }
         }
-
-        @Override
-        void handleServiceError() {
-            mArgs = createInstallArgs(this);
-            mRet = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
-        }
     }
 
     private InstallArgs createInstallArgs(InstallParams params) {
@@ -14439,7 +14168,7 @@
             this.installReason = installReason;
         }
 
-        abstract int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException;
+        abstract int copyApk();
         abstract int doPreInstall(int status);
 
         /**
@@ -14547,16 +14276,16 @@
             this.resourceFile = (resourcePath != null) ? new File(resourcePath) : null;
         }
 
-        int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {
+        int copyApk() {
             Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyApk");
             try {
-                return doCopyApk(imcs, temp);
+                return doCopyApk();
             } finally {
                 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
             }
         }
 
-        private int doCopyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {
+        private int doCopyApk() {
             if (origin.staged) {
                 if (DEBUG_INSTALL) Slog.d(TAG, origin.file + " already staged; skipping copy");
                 codeFile = origin.file;
@@ -14575,25 +14304,8 @@
                 return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
             }
 
-            final IParcelFileDescriptorFactory target = new IParcelFileDescriptorFactory.Stub() {
-                @Override
-                public ParcelFileDescriptor open(String name, int mode) throws RemoteException {
-                    if (!FileUtils.isValidExtFilename(name)) {
-                        throw new IllegalArgumentException("Invalid filename: " + name);
-                    }
-                    try {
-                        final File file = new File(codeFile, name);
-                        final FileDescriptor fd = Os.open(file.getAbsolutePath(),
-                                O_RDWR | O_CREAT, 0644);
-                        Os.chmod(file.getAbsolutePath(), 0644);
-                        return new ParcelFileDescriptor(fd);
-                    } catch (ErrnoException e) {
-                        throw new RemoteException("Failed to open: " + e.getMessage());
-                    }
-                }
-            };
-
-            int ret = imcs.copyPackage(origin.file.getAbsolutePath(), target);
+            int ret = PackageManagerServiceUtils.copyPackage(
+                    origin.file.getAbsolutePath(), codeFile);
             if (ret != PackageManager.INSTALL_SUCCEEDED) {
                 Slog.e(TAG, "Failed to copy package");
                 return ret;
@@ -14754,7 +14466,7 @@
                     params.installReason);
         }
 
-        int copyApk(IMediaContainerService imcs, boolean temp) {
+        int copyApk() {
             if (DEBUG_INSTALL) Slog.d(TAG, "Moving " + move.packageName + " from "
                     + move.fromUuid + " to " + move.toUuid);
             synchronized (mInstaller) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 390c0cc..36948fc 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -18,23 +18,21 @@
 
 import static android.content.pm.PackageManager.INSTALL_FAILED_SHARED_USER_INCOMPATIBLE;
 import static android.content.pm.PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE;
+import static android.system.OsConstants.O_CREAT;
+import static android.system.OsConstants.O_RDWR;
+
 import static com.android.server.pm.PackageManagerService.COMPRESSED_EXTENSION;
 import static com.android.server.pm.PackageManagerService.DEBUG_COMPRESSION;
 import static com.android.server.pm.PackageManagerService.DEBUG_DEXOPT;
 import static com.android.server.pm.PackageManagerService.STUB_SUFFIX;
 import static com.android.server.pm.PackageManagerService.TAG;
-import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;
-
-import com.android.internal.content.NativeLibraryHelper;
-import com.android.internal.util.FastPrintWriter;
-import com.android.server.EventLogTags;
-import com.android.server.pm.dex.DexManager;
-import com.android.server.pm.dex.PackageDexUsage;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.AppGlobals;
+import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageInfoLite;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageParser;
 import android.content.pm.PackageParser.PackageParserException;
@@ -53,18 +51,24 @@
 import android.system.Os;
 import android.util.ArraySet;
 import android.util.Log;
-import android.util.PackageUtils;
 import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
 
+import com.android.internal.content.NativeLibraryHelper;
+import com.android.internal.content.PackageHelper;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.FastPrintWriter;
+import com.android.server.EventLogTags;
+import com.android.server.pm.dex.DexManager;
+import com.android.server.pm.dex.PackageDexUsage;
+
 import dalvik.system.VMRuntime;
 
 import libcore.io.IoUtils;
-import libcore.io.Libcore;
-import libcore.io.Streams;
 
 import java.io.BufferedReader;
 import java.io.File;
+import java.io.FileDescriptor;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.FileReader;
@@ -73,8 +77,6 @@
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.PrintWriter;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
 import java.security.cert.CertificateEncodingException;
 import java.security.cert.CertificateException;
 import java.text.SimpleDateFormat;
@@ -710,4 +712,120 @@
         final File[] compressedFiles = getCompressedFiles(codePath);
         return compressedFiles != null && compressedFiles.length > 0;
     }
+
+    /**
+     * Parse given package and return minimal details.
+     */
+    public static PackageInfoLite getMinimalPackageInfo(Context context, String packagePath,
+            int flags, String abiOverride) {
+        final PackageInfoLite ret = new PackageInfoLite();
+        if (packagePath == null) {
+            Slog.i(TAG, "Invalid package file " + packagePath);
+            ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_APK;
+            return ret;
+        }
+
+        final File packageFile = new File(packagePath);
+        final PackageParser.PackageLite pkg;
+        final long sizeBytes;
+        try {
+            pkg = PackageParser.parsePackageLite(packageFile, 0);
+            sizeBytes = PackageHelper.calculateInstalledSize(pkg, abiOverride);
+        } catch (PackageParserException | IOException e) {
+            Slog.w(TAG, "Failed to parse package at " + packagePath + ": " + e);
+
+            if (!packageFile.exists()) {
+                ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_URI;
+            } else {
+                ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_APK;
+            }
+
+            return ret;
+        }
+
+        final int recommendedInstallLocation = PackageHelper.resolveInstallLocation(context,
+                pkg.packageName, pkg.installLocation, sizeBytes, flags);
+
+        ret.packageName = pkg.packageName;
+        ret.splitNames = pkg.splitNames;
+        ret.versionCode = pkg.versionCode;
+        ret.versionCodeMajor = pkg.versionCodeMajor;
+        ret.baseRevisionCode = pkg.baseRevisionCode;
+        ret.splitRevisionCodes = pkg.splitRevisionCodes;
+        ret.installLocation = pkg.installLocation;
+        ret.verifiers = pkg.verifiers;
+        ret.recommendedInstallLocation = recommendedInstallLocation;
+        ret.multiArch = pkg.multiArch;
+
+        return ret;
+    }
+
+    /**
+     * Calculate estimated footprint of given package post-installation.
+     *
+     * @return -1 if there's some error calculating the size, otherwise installed size of the
+     *         package.
+     */
+    public static long calculateInstalledSize(String packagePath, String abiOverride) {
+        final File packageFile = new File(packagePath);
+        final PackageParser.PackageLite pkg;
+        try {
+            pkg = PackageParser.parsePackageLite(packageFile, 0);
+            return PackageHelper.calculateInstalledSize(pkg, abiOverride);
+        } catch (PackageParserException | IOException e) {
+            Slog.w(TAG, "Failed to calculate installed size: " + e);
+            return -1;
+        }
+    }
+
+    /**
+     * Copy package to the target location.
+     *
+     * @param packagePath absolute path to the package to be copied. Can be
+     *                    a single monolithic APK file or a cluster directory
+     *                    containing one or more APKs.
+     * @return returns status code according to those in
+     *         {@link PackageManager}
+     */
+    public static int copyPackage(String packagePath, File targetDir) {
+        if (packagePath == null) {
+            return PackageManager.INSTALL_FAILED_INVALID_URI;
+        }
+
+        try {
+            final File packageFile = new File(packagePath);
+            final PackageParser.PackageLite pkg = PackageParser.parsePackageLite(packageFile, 0);
+            copyFile(pkg.baseCodePath, targetDir, "base.apk");
+            if (!ArrayUtils.isEmpty(pkg.splitNames)) {
+                for (int i = 0; i < pkg.splitNames.length; i++) {
+                    copyFile(pkg.splitCodePaths[i], targetDir,
+                            "split_" + pkg.splitNames[i] + ".apk");
+                }
+            }
+            return PackageManager.INSTALL_SUCCEEDED;
+        } catch (PackageParserException | IOException | ErrnoException e) {
+            Slog.w(TAG, "Failed to copy package at " + packagePath + ": " + e);
+            return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+        }
+    }
+
+    private static void copyFile(String sourcePath, File targetDir, String targetName)
+            throws ErrnoException, IOException {
+        if (!FileUtils.isValidExtFilename(targetName)) {
+            throw new IllegalArgumentException("Invalid filename: " + targetName);
+        }
+        Slog.d(TAG, "Copying " + sourcePath + " to " + targetName);
+
+        final File targetFile = new File(targetDir, targetName);
+        final FileDescriptor targetFd = Os.open(targetFile.getAbsolutePath(),
+                O_RDWR | O_CREAT, 0644);
+        Os.chmod(targetFile.getAbsolutePath(), 0644);
+        FileInputStream source = null;
+        try {
+            source = new FileInputStream(sourcePath);
+            FileUtils.copy(source.getFD(), targetFd);
+        } finally {
+            IoUtils.closeQuietly(source);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 5befc1f..846c7b7 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -63,7 +63,6 @@
 
 import com.android.internal.util.XmlUtils;
 import com.android.server.LocalServices;
-import com.android.server.pm.PackageManagerService;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -455,13 +454,6 @@
             grantRuntimePermissions(storagePackage, STORAGE_PERMISSIONS, true, userId);
         }
 
-        // Container service
-        PackageParser.Package containerPackage = getSystemPackage(
-                PackageManagerService.DEFAULT_CONTAINER_PACKAGE);
-        if (containerPackage != null) {
-            grantRuntimePermissions(containerPackage, STORAGE_PERMISSIONS, true, userId);
-        }
-
         // CertInstaller
         Intent certInstallerIntent = new Intent(Credentials.INSTALL_ACTION);
         PackageParser.Package certInstallerPackage = getDefaultSystemHandlerActivityPackage(
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 3e0429f..350d6b6 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -4732,8 +4732,8 @@
         }
         final WindowManager.LayoutParams attrs = win.getAttrs();
         final boolean isDefaultDisplay = win.isDefaultDisplay();
-        final boolean needsToOffsetInputMethodTarget = isDefaultDisplay &&
-                (win == mLastInputMethodTargetWindow && mLastInputMethodWindow != null);
+        final boolean needsToOffsetInputMethodTarget =
+                (win == mLastInputMethodTargetWindow) && (mLastInputMethodWindow != null);
         if (needsToOffsetInputMethodTarget) {
             if (DEBUG_LAYOUT) Slog.i(TAG, "Offset ime target window by the last ime window state");
             offsetInputMethodWindowLw(mLastInputMethodWindow, displayFrames);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index d3e534c..5d0101f 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -409,6 +409,11 @@
 
     private InputMonitor mInputMonitor;
 
+    /**
+     * The input method window for this display.
+     */
+    WindowState mInputMethodWindow;
+
     private final Consumer<WindowState> mUpdateWindowsForAnimator = w -> {
         WindowStateAnimator winAnimator = w.mWinAnimator;
         final AppWindowToken atoken = w.mAppToken;
@@ -2107,18 +2112,16 @@
                 mTouchExcludeRegion.op(mTmpRect2, Region.Op.UNION);
             }
         }
-        final WindowState inputMethod = mService.mInputMethodWindow;
-        if (inputMethod != null && inputMethod.isVisibleLw()) {
+        if (mInputMethodWindow != null && mInputMethodWindow.isVisibleLw()) {
             // If the input method is visible and the user is typing, we don't want these touch
             // events to be intercepted and used to change focus. This would likely cause a
             // disappearance of the input method.
-            inputMethod.getTouchableRegion(mTmpRegion);
-            if (inputMethod.getDisplayId() == mDisplayId) {
+            mInputMethodWindow.getTouchableRegion(mTmpRegion);
+            if (mInputMethodWindow.getDisplayId() == mDisplayId) {
                 mTouchExcludeRegion.op(mTmpRegion, Op.UNION);
             } else {
                 // IME is on a different display, so we need to update its tap detector.
-                // TODO(multidisplay): Remove when IME will always appear on same display.
-                inputMethod.getDisplayContent().setTouchExcludeRegion(null /* focusedTask */);
+                setTouchExcludeRegion(null /* focusedTask */);
             }
         }
         for (int i = mTapExcludedWindows.size() - 1; i >= 0; i--) {
@@ -2257,7 +2260,7 @@
     }
 
     void adjustForImeIfNeeded() {
-        final WindowState imeWin = mService.mInputMethodWindow;
+        final WindowState imeWin = mInputMethodWindow;
         final boolean imeVisible = imeWin != null && imeWin.isVisibleLw() && imeWin.isDisplayedLw()
                 && !mDividerControllerLocked.isImeHideRequested();
         final boolean dockVisible = isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
@@ -2640,12 +2643,21 @@
     }
 
     /**
+     * Set input method window for the display.
+     * @param win Set when window added or Null when destroyed.
+     */
+    void setInputMethodWindowLocked(WindowState win) {
+        mInputMethodWindow = win;
+        computeImeTarget(true /* updateImeTarget */);
+    }
+
+    /**
      * Determine and return the window that should be the IME target.
      * @param updateImeTarget If true the system IME target will be updated to match what we found.
      * @return The window that should be used as the IME target or null if there isn't any.
      */
     WindowState computeImeTarget(boolean updateImeTarget) {
-        if (mService.mInputMethodWindow == null) {
+        if (mInputMethodWindow == null) {
             // There isn't an IME so there shouldn't be a target...That was easy!
             if (updateImeTarget) {
                 if (DEBUG_INPUT_METHOD) Slog.w(TAG_WM, "Moving IM target from "
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 86b14337..d92818a 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -681,10 +681,11 @@
                 i--;
                 WindowState win = mService.mDestroySurface.get(i);
                 win.mDestroying = false;
-                if (mService.mInputMethodWindow == win) {
-                    mService.setInputMethodWindowLocked(null);
+                final DisplayContent displayContent = win.getDisplayContent();
+                if (displayContent.mInputMethodWindow == win) {
+                    displayContent.setInputMethodWindowLocked(null);
                 }
-                if (win.getDisplayContent().mWallpaperController.isWallpaperTarget(win)) {
+                if (displayContent.mWallpaperController.isWallpaperTarget(win)) {
                     wallpaperDestroyed = true;
                 }
                 win.destroySurfaceUnchecked();
@@ -1113,4 +1114,18 @@
             callback.accept(mChildren.get(i));
         }
     }
+
+    /**
+     * Get current topmost focused IME window in system.
+     * Will look on all displays in current Z-order.
+     */
+    WindowState getCurrentInputMethodWindow() {
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final DisplayContent displayContent = mChildren.get(i);
+            if (displayContent.mInputMethodWindow != null) {
+                return displayContent.mInputMethodWindow;
+            }
+        }
+        return null;
+    }
 }
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index ac496a8..793ce60 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -335,9 +335,9 @@
     public abstract void registerAppTransitionListener(AppTransitionListener listener);
 
     /**
-     * Retrieves a height of input method window.
+     * Retrieves a height of input method window for given display.
      */
-    public abstract int getInputMethodWindowVisibleHeight();
+    public abstract int getInputMethodWindowVisibleHeight(int displayId);
 
     /**
       * Saves last input method window for transition.
@@ -447,4 +447,9 @@
      * Returns {@code true} if a process that is identified by {@code client} has IME focus.
      */
     public abstract boolean inputMethodClientHasFocus(IInputMethodClient client);
+
+    /**
+     * Return the display Id for given window.
+     */
+    public abstract int getDisplayIdForWindow(IBinder windowToken);
 }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 679e0d8..2ed09ae 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -650,8 +650,6 @@
     /** If true hold off on modifying the animation layer of mInputMethodTarget */
     boolean mInputMethodTargetWaitingAnim;
 
-    WindowState mInputMethodWindow = null;
-
     boolean mHardKeyboardAvailable;
     WindowManagerInternal.OnHardKeyboardStatusChangeListener mHardKeyboardStatusChangeListener;
     SettingsObserver mSettingsObserver;
@@ -1414,7 +1412,7 @@
             win.mToken.addWindow(win);
             if (type == TYPE_INPUT_METHOD) {
                 win.mGivenInsetsPending = true;
-                setInputMethodWindowLocked(win);
+                displayContent.setInputMethodWindowLocked(win);
                 imMayMove = false;
             } else if (type == TYPE_INPUT_METHOD_DIALOG) {
                 displayContent.computeImeTarget(true /* updateImeTarget */);
@@ -1687,8 +1685,9 @@
         mWindowsChanged = true;
         if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG_WM, "Final remove of window: " + win);
 
-        if (mInputMethodWindow == win) {
-            setInputMethodWindowLocked(null);
+        final DisplayContent displayContent = win.getDisplayContent();
+        if (displayContent.mInputMethodWindow == win) {
+            displayContent.setInputMethodWindowLocked(null);
         }
 
         final WindowToken token = win.mToken;
@@ -1733,13 +1732,6 @@
         dc.getInputMonitor().updateInputWindowsLw(true /*force*/);
     }
 
-    void setInputMethodWindowLocked(WindowState win) {
-        mInputMethodWindow = win;
-        final DisplayContent dc = win != null
-                ? win.getDisplayContent() : getDefaultDisplayContentLocked();
-        dc.computeImeTarget(true /* updateImeTarget */);
-    }
-
     private void updateHiddenWhileSuspendedState(ArraySet<String> packages, boolean suspended) {
         synchronized (mWindowMap) {
             mRoot.updateHiddenWhileSuspendedState(packages, suspended);
@@ -2058,8 +2050,10 @@
                 if ((result & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
                     focusMayChange = isDefaultDisplay;
                 }
-                if (win.mAttrs.type == TYPE_INPUT_METHOD && mInputMethodWindow == null) {
-                    setInputMethodWindowLocked(win);
+                final DisplayContent displayContent = win.getDisplayContent();
+                if (win.mAttrs.type == TYPE_INPUT_METHOD
+                        && displayContent.mInputMethodWindow == null) {
+                    displayContent.setInputMethodWindowLocked(win);
                     imMayMove = true;
                 }
                 win.adjustStartingWindowFlags();
@@ -2222,8 +2216,9 @@
             // of a transaction to avoid artifacts.
             win.mAnimatingExit = true;
         } else {
-            if (mInputMethodWindow == win) {
-                setInputMethodWindowLocked(null);
+            final DisplayContent displayContent = win.getDisplayContent();
+            if (displayContent.mInputMethodWindow == win) {
+                displayContent.setInputMethodWindowLocked(null);
             }
             boolean stopped = win.mAppToken != null ? win.mAppToken.mAppStopped : true;
             // We set mDestroying=true so AppWindowToken#notifyAppStopped in-to destroy surfaces
@@ -2828,7 +2823,7 @@
 
     @Override
     public WindowManagerPolicy.WindowState getInputMethodWindowLw() {
-        return mInputMethodWindow;
+        return mRoot.getCurrentInputMethodWindow();
     }
 
     @Override
@@ -5575,10 +5570,10 @@
             // change message pending.
             mH.removeMessages(H.REPORT_FOCUS_CHANGE);
             mH.sendEmptyMessage(H.REPORT_FOCUS_CHANGE);
-            // TODO(multidisplay): Focused windows on default display only.
-            final DisplayContent displayContent = getDefaultDisplayContentLocked();
+            final DisplayContent displayContent = (newFocus != null) ? newFocus.getDisplayContent()
+                    : getDefaultDisplayContentLocked();
             boolean imWindowChanged = false;
-            if (mInputMethodWindow != null) {
+            if (displayContent.mInputMethodWindow != null) {
                 final WindowState prevTarget = mInputMethodTarget;
 
                 final WindowState newTarget =
@@ -5587,10 +5582,11 @@
 
                 if (mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS
                         && mode != UPDATE_FOCUS_WILL_PLACE_SURFACES) {
-                    final int prevImeAnimLayer = mInputMethodWindow.mWinAnimator.mAnimLayer;
+                    final int prevImeAnimLayer =
+                            displayContent.mInputMethodWindow.mWinAnimator.mAnimLayer;
                     displayContent.assignWindowLayers(false /* setLayoutNeeded */);
-                    imWindowChanged |=
-                            prevImeAnimLayer != mInputMethodWindow.mWinAnimator.mAnimLayer;
+                    imWindowChanged |= prevImeAnimLayer
+                            != displayContent.mInputMethodWindow.mWinAnimator.mAnimLayer;
                 }
             }
 
@@ -5613,7 +5609,7 @@
 
             int focusChanged = mPolicy.focusChangedLw(oldFocus, newFocus);
 
-            if (imWindowChanged && oldFocus != mInputMethodWindow) {
+            if (imWindowChanged && oldFocus != displayContent.mInputMethodWindow) {
                 // Focus of the input method window changed. Perform layout if needed.
                 if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
                     displayContent.performLayout(true /*initial*/,  updateInputWindows);
@@ -6033,8 +6029,15 @@
         }
         synchronized (mWindowMap) {
             final Region r = new Region();
-            if (mInputMethodWindow != null) {
-                mInputMethodWindow.getTouchableRegion(r);
+            // TODO(b/111080190): this method is only return the recent focused IME touch region,
+            // For Multi-Session IME, will need to add API for given display Id to
+            // get the right IME touch region.
+            for (int i = mRoot.mChildren.size() - 1; i >= 0; --i) {
+                final DisplayContent displayContent = mRoot.mChildren.get(i);
+                if (displayContent.mInputMethodWindow != null) {
+                    displayContent.mInputMethodWindow.getTouchableRegion(r);
+                    return r;
+                }
             }
             return r;
         }
@@ -6217,8 +6220,9 @@
         if (mFocusedApp != null) {
             mFocusedApp.writeNameToProto(proto, FOCUSED_APP);
         }
-        if (mInputMethodWindow != null) {
-            mInputMethodWindow.writeIdentifierToProto(proto, INPUT_METHOD_WINDOW);
+        final WindowState imeWindow = mRoot.getCurrentInputMethodWindow();
+        if (imeWindow != null) {
+            imeWindow.writeIdentifierToProto(proto, INPUT_METHOD_WINDOW);
         }
         proto.write(DISPLAY_FROZEN, mDisplayFrozen);
         final DisplayContent defaultDisplayContent = getDefaultDisplayContentLocked();
@@ -6388,8 +6392,9 @@
                 pw.print("  mLastStatusBarVisibility=0x");
                         pw.println(Integer.toHexString(mLastStatusBarVisibility));
             }
-            if (mInputMethodWindow != null) {
-                pw.print("  mInputMethodWindow="); pw.println(mInputMethodWindow);
+            final WindowState imeWindow = mRoot.getCurrentInputMethodWindow();
+            if (imeWindow != null) {
+                pw.print("  mInputMethodWindow="); pw.println(imeWindow);
             }
             mWindowPlacerLocked.dump(pw, "  ");
             mRoot.mWallpaperController.dump(pw, "  ");
@@ -7287,10 +7292,9 @@
         }
 
         @Override
-        public int getInputMethodWindowVisibleHeight() {
+        public int getInputMethodWindowVisibleHeight(int displayId) {
             synchronized (mWindowMap) {
-                // TODO(multi-display): Have caller pass in the display they are interested in.
-                final DisplayContent dc = getDefaultDisplayContentLocked();
+                final DisplayContent dc = mRoot.getDisplayContent(displayId);
                 return dc.mDisplayFrames.getInputMethodWindowVisibleHeight();
             }
         }
@@ -7298,8 +7302,9 @@
         @Override
         public void saveLastInputMethodWindowForTransition() {
             synchronized (mWindowMap) {
-                if (mInputMethodWindow != null) {
-                    mPolicy.setLastInputMethodWindowLw(mInputMethodWindow, mInputMethodTarget);
+                final WindowState imeWindow = mRoot.getCurrentInputMethodWindow();
+                if (imeWindow != null) {
+                    mPolicy.setLastInputMethodWindowLw(imeWindow, mInputMethodTarget);
                 }
             }
         }
@@ -7406,28 +7411,42 @@
             }
         }
 
-        @Override
-        public boolean inputMethodClientHasFocus(IInputMethodClient client) {
-            synchronized (mWindowMap) {
-                // TODO: multi-display
-                if (getDefaultDisplayContentLocked().inputMethodClientHasFocus(client)) {
-                    return true;
-                }
-
-                // Okay, how about this...  what is the current focus?
-                // It seems in some cases we may not have moved the IM
-                // target window, such as when it was in a pop-up window,
-                // so let's also look at the current focus.  (An example:
-                // go to Gmail, start searching so the keyboard goes up,
-                // press home.  Sometimes the IME won't go down.)
-                // Would be nice to fix this more correctly, but it's
-                // way at the end of a release, and this should be good enough.
-                if (mCurrentFocus != null && mCurrentFocus.mSession.mClient != null
-                        && mCurrentFocus.mSession.mClient.asBinder() == client.asBinder()) {
+    public boolean inputMethodClientHasFocus(IInputMethodClient client) {
+        boolean hasFocus;
+        synchronized (mWindowMap) {
+            // Check all displays if any input method window has focus.
+            for (int i = mRoot.mChildren.size() - 1; i >= 0; --i) {
+                final DisplayContent displayContent = mRoot.mChildren.get(i);
+                if (displayContent.inputMethodClientHasFocus(client)) {
                     return true;
                 }
             }
-            return false;
+
+            // Okay, how about this...  what is the current focus?
+            // It seems in some cases we may not have moved the IM
+            // target window, such as when it was in a pop-up window,
+            // so let's also look at the current focus.  (An example:
+            // go to Gmail, start searching so the keyboard goes up,
+            // press home.  Sometimes the IME won't go down.)
+            // Would be nice to fix this more correctly, but it's
+            // way at the end of a release, and this should be good enough.
+            if (mCurrentFocus != null && mCurrentFocus.mSession.mClient != null
+                    && mCurrentFocus.mSession.mClient.asBinder() == client.asBinder()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+        @Override
+        public int getDisplayIdForWindow(IBinder windowToken) {
+            synchronized (mWindowMap) {
+                final WindowState window = mWindowMap.get(windowToken);
+                if (window != null) {
+                    return window.getDisplayContent().getDisplayId();
+                }
+                return Display.INVALID_DISPLAY;
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 637c0ea..5272b66 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -845,7 +845,7 @@
                 mWindowFrames.mContainingFrame.bottom =
                         mWindowFrames.mContainingFrame.top + frozen.height();
             }
-            final WindowState imeWin = mService.mInputMethodWindow;
+            final WindowState imeWin = mService.mRoot.getCurrentInputMethodWindow();
             // IME is up and obscuring this window. Adjust the window position so it is visible.
             if (imeWin != null && imeWin.isVisibleNow() && isInputMethodTarget()) {
                 if (inFreeformWindowingMode() && mWindowFrames.mContainingFrame.bottom
@@ -3734,6 +3734,8 @@
         windowInfo.focused = isFocused();
         Task task = getTask();
         windowInfo.inPictureInPicture = (task != null) && task.inPinnedWindowingMode();
+        windowInfo.hasFlagWatchOutsideTouch =
+                (mAttrs.flags & WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH) != 0;
 
         if (mIsChildWindow) {
             windowInfo.parentToken = getParentWindow().mClient.asBinder();
diff --git a/services/net/java/android/net/dns/ResolvUtil.java b/services/net/java/android/net/dns/ResolvUtil.java
deleted file mode 100644
index d9d4b96..0000000
--- a/services/net/java/android/net/dns/ResolvUtil.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.dns;
-
-import static android.system.OsConstants.AI_ADDRCONFIG;
-
-import android.net.Network;
-import android.net.NetworkUtils;
-import android.system.GaiException;
-import android.system.OsConstants;
-import android.system.StructAddrinfo;
-
-import libcore.io.Libcore;
-
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-
-
-/**
- * DNS resolution utility class.
- *
- * @hide
- */
-public class ResolvUtil {
-    // Non-portable DNS resolution flag.
-    private static final long NETID_USE_LOCAL_NAMESERVERS = 0x80000000L;
-
-    private ResolvUtil() {}
-
-    public static InetAddress[] blockingResolveAllLocally(Network network, String name)
-            throws UnknownHostException {
-        // Use AI_ADDRCONFIG by default
-        return blockingResolveAllLocally(network, name, AI_ADDRCONFIG);
-    }
-
-    public static InetAddress[] blockingResolveAllLocally(
-            Network network, String name, int aiFlags) throws UnknownHostException  {
-        final StructAddrinfo hints = new StructAddrinfo();
-        hints.ai_flags = aiFlags;
-        // Other hints identical to the default Inet6AddressImpl implementation
-        hints.ai_family = OsConstants.AF_UNSPEC;
-        hints.ai_socktype = OsConstants.SOCK_STREAM;
-
-        final Network networkForResolv = getNetworkWithUseLocalNameserversFlag(network);
-
-        try {
-            return Libcore.os.android_getaddrinfo(name, hints, (int) networkForResolv.netId);
-        } catch (GaiException gai) {
-            gai.rethrowAsUnknownHostException(name + ": TLS-bypass resolution failed");
-            return null;  // keep compiler quiet
-        }
-    }
-
-    public static Network getNetworkWithUseLocalNameserversFlag(Network network) {
-        final long netidForResolv = NETID_USE_LOCAL_NAMESERVERS | (long) network.netId;
-        return new Network((int) netidForResolv);
-    }
-
-    public static Network makeNetworkWithPrivateDnsBypass(Network network) {
-        return new Network(network) {
-            @Override
-            public InetAddress[] getAllByName(String host) throws UnknownHostException {
-                return blockingResolveAllLocally(network, host);
-            }
-        };
-    }
-}
diff --git a/services/net/java/android/net/ip/IpClient.java b/services/net/java/android/net/ip/IpClient.java
index ccc092d..0176dd4 100644
--- a/services/net/java/android/net/ip/IpClient.java
+++ b/services/net/java/android/net/ip/IpClient.java
@@ -228,6 +228,9 @@
     //       Encourages logging of any available arguments, and all call sites
     //       are necessarily logged identically.
     //
+    // NOTE: Log first because passed objects may or may not be thread-safe and
+    // once passed on to the callback they may be modified by another thread.
+    //
     // TODO: Find an lighter weight approach.
     private class LoggingCallbackWrapper extends Callback {
         private static final String PREFIX = "INVOKE ";
@@ -243,63 +246,63 @@
 
         @Override
         public void onPreDhcpAction() {
-            mCallback.onPreDhcpAction();
             log("onPreDhcpAction()");
+            mCallback.onPreDhcpAction();
         }
         @Override
         public void onPostDhcpAction() {
-            mCallback.onPostDhcpAction();
             log("onPostDhcpAction()");
+            mCallback.onPostDhcpAction();
         }
         @Override
         public void onNewDhcpResults(DhcpResults dhcpResults) {
-            mCallback.onNewDhcpResults(dhcpResults);
             log("onNewDhcpResults({" + dhcpResults + "})");
+            mCallback.onNewDhcpResults(dhcpResults);
         }
         @Override
         public void onProvisioningSuccess(LinkProperties newLp) {
-            mCallback.onProvisioningSuccess(newLp);
             log("onProvisioningSuccess({" + newLp + "})");
+            mCallback.onProvisioningSuccess(newLp);
         }
         @Override
         public void onProvisioningFailure(LinkProperties newLp) {
-            mCallback.onProvisioningFailure(newLp);
             log("onProvisioningFailure({" + newLp + "})");
+            mCallback.onProvisioningFailure(newLp);
         }
         @Override
         public void onLinkPropertiesChange(LinkProperties newLp) {
-            mCallback.onLinkPropertiesChange(newLp);
             log("onLinkPropertiesChange({" + newLp + "})");
+            mCallback.onLinkPropertiesChange(newLp);
         }
         @Override
         public void onReachabilityLost(String logMsg) {
-            mCallback.onReachabilityLost(logMsg);
             log("onReachabilityLost(" + logMsg + ")");
+            mCallback.onReachabilityLost(logMsg);
         }
         @Override
         public void onQuit() {
-            mCallback.onQuit();
             log("onQuit()");
+            mCallback.onQuit();
         }
         @Override
         public void installPacketFilter(byte[] filter) {
-            mCallback.installPacketFilter(filter);
             log("installPacketFilter(byte[" + filter.length + "])");
+            mCallback.installPacketFilter(filter);
         }
         @Override
         public void startReadPacketFilter() {
-            mCallback.startReadPacketFilter();
             log("startReadPacketFilter()");
+            mCallback.startReadPacketFilter();
         }
         @Override
         public void setFallbackMulticastFilter(boolean enabled) {
-            mCallback.setFallbackMulticastFilter(enabled);
             log("setFallbackMulticastFilter(" + enabled + ")");
+            mCallback.setFallbackMulticastFilter(enabled);
         }
         @Override
         public void setNeighborDiscoveryOffload(boolean enable) {
-            mCallback.setNeighborDiscoveryOffload(enable);
             log("setNeighborDiscoveryOffload(" + enable + ")");
+            mCallback.setNeighborDiscoveryOffload(enable);
         }
     }
 
diff --git a/services/robotests/Android.mk b/services/robotests/Android.mk
index 2691701..8b59771 100644
--- a/services/robotests/Android.mk
+++ b/services/robotests/Android.mk
@@ -75,6 +75,7 @@
 LOCAL_STATIC_JAVA_LIBRARIES := \
     platform-robolectric-android-all-stubs \
     android-support-test \
+    guava \
     mockito-robolectric-prebuilt \
     platform-test-annotations \
     truth-prebuilt \
diff --git a/services/robotests/src/com/android/server/backup/encryption/chunk/ChunkHashTest.java b/services/robotests/src/com/android/server/backup/encryption/chunk/ChunkHashTest.java
new file mode 100644
index 0000000..3b6e038
--- /dev/null
+++ b/services/robotests/src/com/android/server/backup/encryption/chunk/ChunkHashTest.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.backup.encryption.chunk;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.platform.test.annotations.Presubmit;
+import com.android.server.testing.FrameworkRobolectricTestRunner;
+import com.android.server.testing.SystemLoaderPackages;
+import com.google.common.primitives.Bytes;
+import java.util.Arrays;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.annotation.Config;
+
+@RunWith(FrameworkRobolectricTestRunner.class)
+@Config(manifest = Config.NONE, sdk = 26)
+@SystemLoaderPackages({"com.android.server.backup"})
+@Presubmit
+public class ChunkHashTest {
+    private static final int HASH_LENGTH_BYTES = 256 / 8;
+    private static final byte[] TEST_HASH_1 = Arrays.copyOf(new byte[] {1}, HASH_LENGTH_BYTES);
+    private static final byte[] TEST_HASH_2 = Arrays.copyOf(new byte[] {2}, HASH_LENGTH_BYTES);
+
+    @Test
+    public void testGetHash_returnsHash() {
+        ChunkHash chunkHash = new ChunkHash(TEST_HASH_1);
+
+        byte[] hash = chunkHash.getHash();
+
+        assertThat(hash).asList().containsExactlyElementsIn(Bytes.asList(TEST_HASH_1)).inOrder();
+    }
+
+    @Test
+    public void testEquals() {
+        ChunkHash chunkHash1 = new ChunkHash(TEST_HASH_1);
+        ChunkHash equalChunkHash1 = new ChunkHash(TEST_HASH_1);
+        ChunkHash chunkHash2 = new ChunkHash(TEST_HASH_2);
+
+        assertThat(chunkHash1).isEqualTo(equalChunkHash1);
+        assertThat(chunkHash1).isNotEqualTo(chunkHash2);
+    }
+
+    @Test
+    public void testHashCode() {
+        ChunkHash chunkHash1 = new ChunkHash(TEST_HASH_1);
+        ChunkHash equalChunkHash1 = new ChunkHash(TEST_HASH_1);
+        ChunkHash chunkHash2 = new ChunkHash(TEST_HASH_2);
+
+        int hash1 = chunkHash1.hashCode();
+        int equalHash1 = equalChunkHash1.hashCode();
+        int hash2 = chunkHash2.hashCode();
+
+        assertThat(hash1).isEqualTo(equalHash1);
+        assertThat(hash1).isNotEqualTo(hash2);
+    }
+
+    @Test
+    public void testCompareTo_whenEqual_returnsZero() {
+        ChunkHash chunkHash = new ChunkHash(TEST_HASH_1);
+        ChunkHash equalChunkHash = new ChunkHash(TEST_HASH_1);
+
+        int result = chunkHash.compareTo(equalChunkHash);
+
+        assertThat(result).isEqualTo(0);
+    }
+
+    @Test
+    public void testCompareTo_whenArgumentGreater_returnsNegative() {
+        ChunkHash chunkHash1 = new ChunkHash(TEST_HASH_1);
+        ChunkHash chunkHash2 = new ChunkHash(TEST_HASH_2);
+
+        int result = chunkHash1.compareTo(chunkHash2);
+
+        assertThat(result).isLessThan(0);
+    }
+
+    @Test
+    public void testCompareTo_whenArgumentSmaller_returnsPositive() {
+        ChunkHash chunkHash1 = new ChunkHash(TEST_HASH_1);
+        ChunkHash chunkHash2 = new ChunkHash(TEST_HASH_2);
+
+        int result = chunkHash2.compareTo(chunkHash1);
+
+        assertThat(result).isGreaterThan(0);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index eb28e1a..1eb88ba 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -100,6 +100,7 @@
 import android.net.NetworkInfo;
 import android.net.NetworkInfo.DetailedState;
 import android.net.NetworkPolicy;
+import android.net.NetworkPolicyManager;
 import android.net.NetworkState;
 import android.net.NetworkStats;
 import android.net.NetworkStatsHistory;
@@ -365,7 +366,7 @@
                 return null;
             }
         }).when(mActivityManager).registerUidObserver(any(), anyInt(),
-                eq(ActivityManager.PROCESS_STATE_UNKNOWN), isNull(String.class));
+                eq(NetworkPolicyManager.FOREGROUND_THRESHOLD_STATE), isNull(String.class));
 
         mFutureIntent = newRestrictBackgroundChangedFuture();
         mService = new NetworkPolicyManagerService(mServiceContext, mActivityManager,
diff --git a/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java b/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java
index e6ca03b..48dda01 100644
--- a/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java
@@ -152,8 +152,7 @@
         final float[] lux = { 0f, 1f };
         final float[] nits = { 0, PowerManager.BRIGHTNESS_ON };
 
-        BrightnessConfiguration config = new BrightnessConfiguration.Builder()
-                .setCurve(lux, nits)
+        BrightnessConfiguration config = new BrightnessConfiguration.Builder(lux, nits)
                 .build();
         strategy.setBrightnessConfiguration(config);
         assertNotEquals(1.0f, strategy.getBrightness(1f), 0.01 /*tolerance*/);
@@ -214,8 +213,7 @@
                 DISPLAY_RANGE_NITS[DISPLAY_RANGE_NITS.length - 1]
         };
 
-        BrightnessConfiguration config = new BrightnessConfiguration.Builder()
-                .setCurve(lux, nits)
+        BrightnessConfiguration config = new BrightnessConfiguration.Builder(lux, nits)
                 .build();
         strategy.setBrightnessConfiguration(config);
         assertEquals(1.0f, strategy.getBrightness(1f), 0.01 /*tolerance*/);
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
index 5db0867..70e4ce4 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -125,7 +125,7 @@
             synchronized (sWm.mWindowMap) {
                 mWallpaperWindow = createCommonWindow(null, TYPE_WALLPAPER, "wallpaperWindow");
                 mImeWindow = createCommonWindow(null, TYPE_INPUT_METHOD, "mImeWindow");
-                sWm.mInputMethodWindow = mImeWindow;
+                mDisplayContent.mInputMethodWindow = mImeWindow;
                 mImeDialogWindow = createCommonWindow(null, TYPE_INPUT_METHOD_DIALOG,
                         "mImeDialogWindow");
                 mStatusBarWindow = createCommonWindow(null, TYPE_STATUS_BAR, "mStatusBarWindow");
diff --git a/startop/OWNERS b/startop/OWNERS
new file mode 100644
index 0000000..bfe96d3
--- /dev/null
+++ b/startop/OWNERS
@@ -0,0 +1,5 @@
+# mailing list: startop-eng@google.com
+chriswailes@google.com
+eholk@google.com
+iam@google.com
+sehr@google.com
diff --git a/startop/scripts/app_startup/analyze_metrics.py b/startop/scripts/app_startup/analyze_metrics.py
new file mode 100755
index 0000000..d74d6f6
--- /dev/null
+++ b/startop/scripts/app_startup/analyze_metrics.py
@@ -0,0 +1,457 @@
+#!/usr/bin/env python3
+#
+# Copyright 2018, The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""
+Perform statistical analysis on measurements produced by app_startup_runner.py
+
+Install:
+$> sudo apt-get install python3-scipy
+
+Usage:
+$> ./analyze_metrics.py <filename.csv> [<filename2.csv> ...]
+$> ./analyze_metrics.py --help
+"""
+
+import argparse
+import csv
+import itertools
+import os
+import subprocess
+import sys
+import tempfile
+from typing import Any, List, Dict, Iterable, TextIO, Tuple
+
+from scipy import stats as sc
+import numpy as np
+
+
+# These CSV columns are considered labels. Everything after them in the same row are metrics.
+_LABEL_COLUMNS=['packages', 'readaheads', 'compiler_filters']
+# The metric series with the 'cold' readahead is the baseline.
+# All others (warm, jit, etc) are the potential improvements.
+
+#fixme: this should probably be an option
+_BASELINE=('readaheads', 'cold')
+# ignore this for some statistic calculations
+_IGNORE_PAIR=('readaheads', 'warm')
+_PLOT_SUBKEY='readaheads'
+_PLOT_GROUPKEY='packages'
+_PLOT_DATA_INDEX = 0
+_DELTA=50
+_DELTA2=100
+_PVALUE_THRESHOLD=0.10
+_debug = False  # See -d/--debug flag.
+
+def parse_options(argv: List[str] = None):
+  """Parse command line arguments and return an argparse Namespace object."""
+  parser = argparse.ArgumentParser(description="Perform statistical analysis on measurements produced by app_start_runner.py.")
+  parser.add_argument('input_files', metavar='file.csv', nargs='+', help='CSV file produced by app_startup_runner.py')
+
+  parser.add_argument('-d', '--debug', dest='debug', action='store_true', help='Add extra debugging output')
+  parser.add_argument('-os', '--output-samples', dest='output_samples', default='/dev/null', action='store', help='Store CSV for per-sample data')
+  parser.add_argument('-oc', '--output-comparable', dest='output_comparable', default='/dev/null', action='store', help='Output CSV for comparable against baseline')
+  parser.add_argument('-ocs', '--output-comparable-significant', dest='output_comparable_significant', default='/dev/null', action='store', help='Output CSV for comparable against baseline (significant only)')
+  parser.add_argument('-pt', '--pvalue-threshold', dest='pvalue_threshold', type=float, default=_PVALUE_THRESHOLD, action='store')
+  parser.add_argument('-dt', '--delta-threshold', dest='delta_threshold', type=int, default=_DELTA, action='store')
+
+  return parser.parse_args(argv)
+
+def _debug_print(*args, **kwargs):
+  """Print the args to sys.stderr if the --debug/-d flag was passed in."""
+  global _debug
+  if _debug:
+    print(*args, **kwargs, file=sys.stderr)
+
+def _expand_gen_repr(args):
+  new_args_list = []
+  for i in args:
+    # detect iterable objects that do not have their own override of __str__
+    if hasattr(i, '__iter__'):
+      to_str = getattr(i, '__str__')
+      if to_str.__objclass__ == object:
+        # the repr for a generator is just type+address, expand it out instead.
+        new_args_list.append([_expand_gen_repr([j])[0] for j in i])
+        continue
+    # normal case: uses the built-in to-string
+    new_args_list.append(i)
+  return new_args_list
+
+def _debug_print_gen(*args, **kwargs):
+  """Like _debug_print but will turn any iterable args into a list."""
+  if not _debug:
+    return
+
+  new_args_list = _expand_gen_repr(args)
+  _debug_print(*new_args_list, **kwargs)
+
+def read_headers(input_file: TextIO) -> Tuple[List[str], List[str]]:
+  _debug_print("read_headers for file: ", input_file.name)
+  csv_reader = csv.reader(input_file)
+
+  label_num_columns = len(_LABEL_COLUMNS)
+
+  try:
+    header = next(csv_reader)
+  except StopIteration:
+    header = None
+  _debug_print('header', header)
+
+  if not header:
+    return (None, None)
+
+  labels = header[0:label_num_columns]
+  data = header[label_num_columns:]
+
+  return (labels, data)
+
+def read_labels_and_data(input_file: TextIO) -> Iterable[Tuple[List[str], List[int]]]:
+  _debug_print("print_analysis for file: ", input_file.name)
+  csv_reader = csv.reader(input_file)
+
+  # Skip the header because it doesn't contain any data.
+  # To get the header see read_headers function.
+  try:
+    header = next(csv_reader)
+  except StopIteration:
+    header = None
+
+  label_num_columns = len(_LABEL_COLUMNS)
+
+  for row in csv_reader:
+    if len(row) > 0 and row[0][0] == ';':
+      _debug_print("skip comment line", row)
+      continue
+
+    labels = row[0:label_num_columns]
+    data = [int(i) for i in row[label_num_columns:]]
+
+#    _debug_print("labels:", labels)
+#    _debug_print("data:", data)
+
+    yield (labels, data)
+
+def group_metrics_by_label(it: Iterable[Tuple[List[str], List[int]]]):
+  prev_labels = None
+  data_2d = []
+
+  for label_list, data_list in it:
+    if prev_labels != label_list:
+      if prev_labels:
+#        _debug_print("grouped labels:", prev_labels, "data_2d:", data_2d)
+        yield (prev_labels, data_2d)
+      data_2d = []
+
+    data_2d.append(data_list)
+    prev_labels = label_list
+
+  if prev_labels:
+#    _debug_print("grouped labels:", prev_labels, "data_2d:", data_2d)
+    yield (prev_labels, data_2d)
+
+def data_to_numpy(it: Iterable[Tuple[List[str], List[List[int]]]]) -> Iterable[Tuple[List[str], Any]]:
+  for label_list, data_2d in it:
+    yield (label_list, np.asarray(data_2d, dtype=int))
+
+def iterate_columns(np_data_2d):
+  for col in range(np_data_2d.shape[1]):
+    col_as_array = np_data_2d[:, col]
+    yield col_as_array
+
+def confidence_interval(np_data_2d, percent=0.95):
+  """
+  Given some data [[a,b,c],[d,e,f,]...]
+
+  We assume the same metric is in the column (e.g. [a,d])
+  and that data in the rows (e.g. [b,e]) are separate metric values.
+
+  We then calculate the CI for each metric individually returning it as a list of tuples.
+  """
+  arr = []
+  for col_2d in iterate_columns(np_data_2d):
+    mean = col_2d.mean()
+    sigma = col_2d.std()
+
+    ci = sc.norm.interval(percent, loc=mean, scale=sigma / np.sqrt(len(col_2d)))
+    arr.append(ci)
+
+  # TODO: This seems to be returning NaN when all the samples have the same exact value
+  # (e.g. stddev=0, which can trivially happen when sample count = 1).
+
+  return arr
+
+def print_analysis(it, label_header: List[str], data_header: List[str], output_samples: str):
+  print(label_header)
+
+  with open(output_samples, "w") as output_file:
+
+    csv_writer = csv.writer(output_file)
+    csv_writer.writerow(label_header + ['mean', 'std', 'confidence_interval_a', 'confidence_interval_b'])
+
+    for label_list, np_data_2d in it:
+      print("**********************")
+      print(label_list)
+      print()
+      print("      ", data_header)
+      # aggregate computation column-wise
+      print("Mean: ", np_data_2d.mean(axis=0))
+      print("Std:  ", np_data_2d.std(axis=0))
+      print("CI95%:", confidence_interval(np_data_2d))
+      print("SEM:  ", stats_standard_error_one(np_data_2d, axis=0))
+
+      #ci = confidence_interval(np_data_2d)[_PLOT_DATA_INDEX]
+      sem = stats_standard_error_one(np_data_2d, axis=0)[_PLOT_DATA_INDEX]
+      mean = np_data_2d.mean(axis=0)[_PLOT_DATA_INDEX]
+
+      ci = (mean - sem, mean + sem)
+
+      csv_writer.writerow(label_list + [mean, np_data_2d.std(axis=0)[_PLOT_DATA_INDEX], ci[0], ci[1]])
+
+def from_file_group_by_labels(input_file):
+  (label_header, data_header) = read_headers(input_file)
+  label_data_iter = read_labels_and_data(input_file)
+  grouped_iter = group_metrics_by_label(label_data_iter)
+  grouped_numpy_iter = data_to_numpy(grouped_iter)
+
+  return grouped_numpy_iter, label_header, data_header
+
+def list_without_index(list, index):
+  return list[:index] + list[index+1:]
+
+def group_by_without_baseline_key(grouped_numpy_iter, label_header):
+  """
+  Data is considered comparable if the only difference is the baseline key
+  (i.e. the readahead is different but the package, compilation filter, etc, are the same).
+
+  Returns iterator that's grouped by the non-baseline labels to an iterator of
+  (label_list, data_2d).
+  """
+  baseline_index = label_header.index(_BASELINE[0])
+
+  def get_label_without_baseline(tpl):
+    label_list, _ = tpl
+    return list_without_index(label_list, baseline_index)
+  # [['pkgname', 'compfilter', 'warm'], [data]]
+  # [['pkgname', 'compfilter', 'cold'], [data2]]
+  # [['pkgname2', 'compfilter', 'warm'], [data3]]
+  #
+  #   ->
+  # ( [['pkgname', 'compfilter', 'warm'], [data]]      # ignore baseline label change.
+  #   [['pkgname', 'compfilter', 'cold'], [data2]] ),  # split here because the pkgname changed.
+  # ( [['pkgname2', 'compfilter', 'warm'], [data3]] )
+  for group_info, it in itertools.groupby(grouped_numpy_iter, key = get_label_without_baseline):
+    yield it
+
+  # TODO: replace this messy manual iteration/grouping with pandas
+
+def iterate_comparable_metrics(without_baseline_iter, label_header):
+  baseline_index = label_header.index(_BASELINE[0])
+  baseline_value = _BASELINE[1]
+
+  _debug_print("iterate comparables")
+
+  def is_baseline_fun(tp):
+    ll, dat = tp
+    return ll[baseline_index] == baseline_value
+
+  # iterating here when everything but the baseline key is the same.
+  for it in without_baseline_iter:
+    it1, it2 = itertools.tee(it)
+
+    # find all the baseline data.
+    baseline_filter_it = filter(is_baseline_fun, it1)
+
+    # find non-baseline data.
+    nonbaseline_filter_it = itertools.filterfalse(is_baseline_fun, it2)
+
+    yield itertools.product(baseline_filter_it, nonbaseline_filter_it)
+
+def stats_standard_error_one(a, axis):
+  a_std = a.std(axis=axis, ddof=0)
+  a_len = a.shape[axis]
+
+  return a_std / np.sqrt(a_len)
+
+def stats_standard_error(a, b, axis):
+  a_std = a.std(axis=axis, ddof=0)
+  b_std = b.std(axis=axis, ddof=0)
+
+  a_len = a.shape[axis]
+  b_len = b.shape[axis]
+
+  temp1 = a_std*a_std/a_len
+  temp2 = b_std*b_std/b_len
+
+  return np.sqrt(temp1 + temp2)
+
+def stats_tvalue(a, b, axis, delta = 0):
+  a_mean = a.mean(axis=axis)
+  b_mean = b.mean(axis=axis)
+
+  return (a_mean - b_mean - delta) / stats_standard_error(a, b, axis)
+
+def stats_pvalue(a, b, axis, delta, left:bool = False):
+  """
+  Single-tailed 2-sample t-test.
+
+  Returns p-value for the null hypothesis: mean(a) - mean(b) >= delta.
+  :param a: numpy 2d array
+  :param b: numpy 2d array
+  :param axis: which axis to do the calculations across
+  :param delta: test value of mean differences
+  :param left: if true then use <= delta instead of >= delta
+  :return: p-value
+  """
+  # implement our own pvalue calculation because the built-in t-test (t,p values)
+  # only offer delta=0 , e.g. m1-m1 ? 0
+  # we are however interested in m1-m2 ? delta
+  t_value = stats_tvalue(a, b, axis, delta)
+
+  # 2-sample degrees of freedom is using the array sizes - 2.
+  dof = a.shape[axis] + b.shape[axis] - 2
+
+  if left:
+    # left tailed test. e.g. m1-m2 <= delta
+    return sc.t.cdf(t_value, dof)
+  else:
+    # right tailed test. e.g. m1-m2 >= delta
+    return sc.t.sf(t_value, dof)
+  # a left+right tailed test is a 2-tail t-test and can be done using ttest_ind for delta=0
+
+def print_comparable_analysis(comparable_metrics_iter, label_header, data_header, output_comparable: str, output_comparable_significant: str):
+  baseline_value = _BASELINE[1]
+  baseline_index = label_header.index(_BASELINE[0])
+
+  old_baseline_label_list = None
+  delta = _DELTA
+  filter_value = _IGNORE_PAIR[1]
+  filter_index = label_header.index(_IGNORE_PAIR[0])
+
+  pvalue_threshold = _PVALUE_THRESHOLD
+  ci_threshold = (1 - _PVALUE_THRESHOLD) * 100.0
+
+  with open(output_comparable, "w") as output_file:
+
+    csv_writer = csv.writer(output_file)
+    csv_writer.writerow(label_header + ['mean', 'mean_diff', 'sem', 'pvalue_2tailed', 'pvalue_gt%d' %(_DELTA), 'pvalue_gt%d' %(_DELTA2)])
+
+    print("------------------------------------------------------------------")
+    print("Comparison against the baseline %s = %s" %(_BASELINE, baseline_value))
+    print("--- Right-tailed t-test checks if the baseline >= current %s by at least %d" %(_BASELINE[0], delta))
+    print()
+
+    global_stats = {'better_than_delta': [], 'better_than_delta_p95': []}
+
+    for nested_it in comparable_metrics_iter:
+      print("************************")
+
+      better_than_delta = []
+      better_than_delta_p95 = []
+
+      saw_baseline_once = False
+
+      for ((baseline_label_list, baseline_np_data_2d), (rest_label_list, rest_np_data_2d)) in nested_it:
+        _debug_print("baseline_label_list:", baseline_label_list)
+        _debug_print("baseline_np_data_2d:", baseline_np_data_2d)
+        _debug_print("rest_label_list:", rest_label_list)
+        _debug_print("rest_np_data_2d:", rest_np_data_2d)
+
+        mean_diff = baseline_np_data_2d.mean(axis=0) - rest_np_data_2d.mean(axis=0)
+        # 2-sample 2-tailed t-test with delta=0
+        # e.g. "Is it true that usually the two sample means are different?"
+        t_statistic, t_pvalue = sc.ttest_ind(baseline_np_data_2d, rest_np_data_2d, axis=0)
+
+        # 2-sample 1-tailed t-test with delta=50
+        # e.g. "Is it true that usually the sample means better than 50ms?"
+        t2 = stats_tvalue(baseline_np_data_2d, rest_np_data_2d, axis=0, delta=delta)
+        p2 = stats_pvalue(baseline_np_data_2d, rest_np_data_2d, axis=0, delta=delta)
+
+        t2_b = stats_tvalue(baseline_np_data_2d, rest_np_data_2d, axis=0, delta=_DELTA2)
+        p2_b = stats_pvalue(baseline_np_data_2d, rest_np_data_2d, axis=0, delta=_DELTA2)
+
+        print("%s vs %s" %(rest_label_list, baseline_value))
+        print("                           ", data_header)
+        print("Mean Difference:           ", mean_diff)
+        print("T-test (2-tailed) != 0:      t=%s, p=%s" %(t_statistic, t_pvalue))
+        print("T-test (right-tailed) >= %d: t=%s, p=%s" %(_DELTA, t2, p2))
+        print("T-test (right-tailed) >= %d: t=%s, p=%s" %(_DELTA2, t2_b, p2_b))
+
+        def write_out_values(label_list, *args):
+          csv_writer.writerow(label_list + [i[_PLOT_DATA_INDEX] for i in args])
+
+        sem = stats_standard_error(baseline_np_data_2d, rest_np_data_2d, axis=0)
+        if saw_baseline_once == False:
+          saw_baseline_once = True
+          base_sem = stats_standard_error_one(baseline_np_data_2d, axis=0)
+          write_out_values(baseline_label_list, baseline_np_data_2d.mean(axis=0), [0], base_sem, [None], [None], [None])
+        write_out_values(rest_label_list, rest_np_data_2d.mean(axis=0), mean_diff, sem, t_pvalue, p2, p2_b)
+
+        # now do the global statistics aggregation
+
+        if rest_label_list[filter_index] == filter_value:
+          continue
+
+        if mean_diff > delta:
+          better_than_delta.append((mean_diff, p2, rest_label_list))
+
+          if p2 <= pvalue_threshold:
+            better_than_delta_p95.append((mean_diff, rest_label_list))
+
+      if better_than_delta:
+        global_stats['better_than_delta'].append(better_than_delta)
+      if better_than_delta_p95:
+        global_stats['better_than_delta_p95'].append(better_than_delta_p95)
+
+    print("------------------------")
+    print("Global statistics:")
+    print("//// Rows with %s=%s are ignored here." %_IGNORE_PAIR)
+    print("- # of results with mean diff better than delta(%d)       = %d" %(delta, len(global_stats['better_than_delta'])))
+    print("    > (meandiff, pvalue, labels)")
+    for i in global_stats['better_than_delta']:
+      print("    > %s" %i)
+    print("- # of results with mean diff better than delta(%d) CI%d%% = %d" %(delta, ci_threshold, len(global_stats['better_than_delta_p95'])))
+    print("    > (meandiff, labels)")
+    for i in global_stats['better_than_delta_p95']:
+      print("    > %s" %i)
+
+def main():
+  global _debug
+  global _DELTA
+  global _PVALUE_THRESHOLD
+
+  opts = parse_options()
+  _debug = opts.debug
+  _debug_print("parsed options: ", opts)
+
+  _PVALUE_THRESHOLD = opts.pvalue_threshold or _PVALUE_THRESHOLD
+
+  for file_name in opts.input_files:
+    with open(file_name, 'r') as input_file:
+      (grouped_numpy_iter, label_header, data_header) = from_file_group_by_labels(input_file)
+      print_analysis(grouped_numpy_iter, label_header, data_header, opts.output_samples)
+
+    with open(file_name, 'r') as input_file:
+      (grouped_numpy_iter, label_header, data_header) = from_file_group_by_labels(input_file)
+      without_baseline_iter = group_by_without_baseline_key(grouped_numpy_iter, label_header)
+      #_debug_print_gen(without_baseline_iter)
+
+      comparable_metrics_iter = iterate_comparable_metrics(without_baseline_iter, label_header)
+      print_comparable_analysis(comparable_metrics_iter, label_header, data_header, opts.output_comparable, opts.output_comparable_significant)
+
+  return 0
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/startop/scripts/app_startup/app_startup_runner.py b/startop/scripts/app_startup/app_startup_runner.py
new file mode 100755
index 0000000..780bb4e
--- /dev/null
+++ b/startop/scripts/app_startup/app_startup_runner.py
@@ -0,0 +1,322 @@
+#!/usr/bin/env python3
+#
+# Copyright 2018, The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+#
+# Measure application start-up time by launching applications under various combinations.
+# See --help for more details.
+#
+#
+# Sample usage:
+# $> ./app_startup_runner.py -p com.google.android.calculator -r warm -r cold -lc 10  -o out.csv
+# $> ./analyze_metrics.py out.csv
+#
+#
+
+import argparse
+import csv
+import itertools
+import os
+import subprocess
+import sys
+import tempfile
+from typing import Any, Callable, Dict, Generic, Iterable, List, NamedTuple, TextIO, Tuple, TypeVar, Optional, Union
+
+# The following command line options participate in the combinatorial generation.
+# All other arguments have a global effect.
+_COMBINATORIAL_OPTIONS=['packages', 'readaheads', 'compiler_filters']
+_TRACING_READAHEADS=['mlock', 'fadvise']
+_FORWARD_OPTIONS={'loop_count': '--count'}
+_RUN_SCRIPT=os.path.join(os.path.dirname(os.path.realpath(__file__)), 'run_app_with_prefetch')
+
+RunCommandArgs = NamedTuple('RunCommandArgs', [('package', str), ('readahead', str), ('compiler_filter', Optional[str])])
+CollectorPackageInfo = NamedTuple('CollectorPackageInfo', [('package', str), ('compiler_filter', str)])
+_COLLECTOR_SCRIPT=os.path.join(os.path.dirname(os.path.realpath(__file__)), 'collector')
+_COLLECTOR_TIMEOUT_MULTIPLIER = 2 # take the regular --timeout and multiply by 2; systrace starts up slowly.
+
+_UNLOCK_SCREEN_SCRIPT=os.path.join(os.path.dirname(os.path.realpath(__file__)), 'unlock_screen')
+
+# This must be the only mutable global variable. All other global variables are constants to avoid magic literals.
+_debug = False  # See -d/--debug flag.
+_DEBUG_FORCE = None  # Ignore -d/--debug if this is not none.
+
+# Type hinting names.
+T = TypeVar('T')
+NamedTupleMeta = Callable[..., T]  # approximation of a (S : NamedTuple<T> where S() == T) metatype.
+
+def parse_options(argv: List[str] = None):
+  """Parse command line arguments and return an argparse Namespace object."""
+  parser = argparse.ArgumentParser(description="Run one or more Android applications under various settings in order to measure startup time.")
+  # argparse considers args starting with - and -- optional in --help, even though required=True.
+  # by using a named argument group --help will clearly say that it's required instead of optional.
+  required_named = parser.add_argument_group('required named arguments')
+  required_named.add_argument('-p', '--package', action='append', dest='packages', help='package of the application', required=True)
+  required_named.add_argument('-r', '--readahead', action='append', dest='readaheads', help='which readahead mode to use', choices=('warm', 'cold', 'mlock', 'fadvise'), required=True)
+
+  # optional arguments
+  # use a group here to get the required arguments to appear 'above' the optional arguments in help.
+  optional_named = parser.add_argument_group('optional named arguments')
+  optional_named.add_argument('-c', '--compiler-filter', action='append', dest='compiler_filters', help='which compiler filter to use. if omitted it does not enforce the app\'s compiler filter', choices=('speed', 'speed-profile', 'quicken'))
+  optional_named.add_argument('-s', '--simulate', dest='simulate', action='store_true', help='Print which commands will run, but don\'t run the apps')
+  optional_named.add_argument('-d', '--debug', dest='debug', action='store_true', help='Add extra debugging output')
+  optional_named.add_argument('-o', '--output', dest='output', action='store', help='Write CSV output to file.')
+  optional_named.add_argument('-t', '--timeout', dest='timeout', action='store', type=int, help='Timeout after this many seconds when executing a single run.')
+  optional_named.add_argument('-lc', '--loop-count', dest='loop_count', default=1, type=int, action='store', help='How many times to loop a single run.')
+  optional_named.add_argument('-in', '--inodes', dest='inodes', type=str, action='store', help='Path to inodes file (system/extras/pagecache/pagecache.py -d inodes)')
+
+  return parser.parse_args(argv)
+
+# TODO: refactor this with a common library file with analyze_metrics.py
+def _debug_print(*args, **kwargs):
+  """Print the args to sys.stderr if the --debug/-d flag was passed in."""
+  if _debug:
+    print(*args, **kwargs, file=sys.stderr)
+
+def _expand_gen_repr(args):
+  """Like repr but any generator-like object has its iterator consumed
+  and then called repr on."""
+  new_args_list = []
+  for i in args:
+    # detect iterable objects that do not have their own override of __str__
+    if hasattr(i, '__iter__'):
+      to_str = getattr(i, '__str__')
+      if to_str.__objclass__ == object:
+        # the repr for a generator is just type+address, expand it out instead.
+        new_args_list.append([_expand_gen_repr([j])[0] for j in i])
+        continue
+    # normal case: uses the built-in to-string
+    new_args_list.append(i)
+  return new_args_list
+
+def _debug_print_gen(*args, **kwargs):
+  """Like _debug_print but will turn any iterable args into a list."""
+  if not _debug:
+    return
+
+  new_args_list = _expand_gen_repr(args)
+  _debug_print(*new_args_list, **kwargs)
+
+def _debug_print_nd(*args, **kwargs):
+  """Like _debug_print but will turn any NamedTuple-type args into a string."""
+  if not _debug:
+    return
+
+  new_args_list = []
+  for i in args:
+    if hasattr(i, '_field_types'):
+      new_args_list.append("%s: %s" %(i.__name__, i._field_types))
+    else:
+      new_args_list.append(i)
+
+  _debug_print(*new_args_list, **kwargs)
+
+def dict_lookup_any_key(dictionary: dict, *keys: List[Any]):
+  for k in keys:
+    if k in dictionary:
+      return dictionary[k]
+  raise KeyError("None of the keys %s were in the dictionary" %(keys))
+
+def generate_run_combinations(named_tuple: NamedTupleMeta[T], opts_dict: Dict[str, List[Optional[str]]])\
+    -> Iterable[T]:
+  """
+  Create all possible combinations given the values in opts_dict[named_tuple._fields].
+
+  :type T: type annotation for the named_tuple type.
+  :param named_tuple: named tuple type, whose fields are used to make combinations for
+  :param opts_dict: dictionary of keys to value list. keys correspond to the named_tuple fields.
+  :return: an iterable over named_tuple instances.
+  """
+  combinations_list = []
+  for k in named_tuple._fields:
+    # the key can be either singular or plural , e.g. 'package' or 'packages'
+    val = dict_lookup_any_key(opts_dict, k, k + "s")
+
+    # treat {'x': None} key value pairs as if it was [None]
+    # otherwise itertools.product throws an exception about not being able to iterate None.
+    combinations_list.append(val or [None])
+
+  _debug_print("opts_dict: ", opts_dict)
+  _debug_print_nd("named_tuple: ", named_tuple)
+  _debug_print("combinations_list: ", combinations_list)
+
+  for combo in itertools.product(*combinations_list):
+    yield named_tuple(*combo)
+
+def key_to_cmdline_flag(key: str) -> str:
+  """Convert key into a command line flag, e.g. 'foo-bars' -> '--foo-bar' """
+  if key.endswith("s"):
+    key = key[:-1]
+  return "--" + key.replace("_", "-")
+
+def as_run_command(tpl: NamedTuple) -> List[Union[str, Any]]:
+  """
+  Convert a named tuple into a command-line compatible arguments list.
+
+  Example: ABC(1, 2, 3) -> ['--a', 1, '--b', 2, '--c', 3]
+  """
+  args = []
+  for key, value in tpl._asdict().items():
+    if value is None:
+      continue
+    args.append(key_to_cmdline_flag(key))
+    args.append(value)
+  return args
+
+def generate_group_run_combinations(run_combinations: Iterable[NamedTuple], dst_nt: NamedTupleMeta[T])\
+    -> Iterable[Tuple[T, Iterable[NamedTuple]]]:
+
+  def group_by_keys(src_nt):
+    src_d = src_nt._asdict()
+    # now remove the keys that aren't legal in dst.
+    for illegal_key in set(src_d.keys()) - set(dst_nt._fields):
+      if illegal_key in src_d:
+        del src_d[illegal_key]
+
+    return dst_nt(**src_d)
+
+  for args_list_it in itertools.groupby(run_combinations, group_by_keys):
+    (group_key_value, args_it) = args_list_it
+    yield (group_key_value, args_it)
+
+def parse_run_script_csv_file(csv_file: TextIO) -> List[int]:
+  """Parse a CSV file full of integers into a flat int list."""
+  csv_reader = csv.reader(csv_file)
+  arr = []
+  for row in csv_reader:
+    for i in row:
+      if i:
+        arr.append(int(i))
+  return arr
+
+def make_script_command_with_temp_output(script: str, args: List[str], **kwargs)\
+    -> Tuple[str, TextIO]:
+  """
+  Create a command to run a script given the args.
+  Appends --count <loop_count> --output <tmp-file-name>.
+  Returns a tuple (cmd, tmp_file)
+  """
+  tmp_output_file = tempfile.NamedTemporaryFile(mode='r')
+  cmd = [script] + args
+  for key, value in kwargs.items():
+    cmd += ['--%s' %(key), "%s" %(value)]
+  if _debug:
+    cmd += ['--verbose']
+  cmd = cmd + ["--output", tmp_output_file.name]
+  return cmd, tmp_output_file
+
+def execute_arbitrary_command(cmd: List[str], simulate: bool, timeout: int) -> Tuple[bool, str]:
+  if simulate:
+    print(" ".join(cmd))
+    return (True, "")
+  else:
+    _debug_print("[EXECUTE]", cmd)
+    proc = subprocess.Popen(cmd,
+                            stderr=subprocess.STDOUT,
+                            stdout=subprocess.PIPE,
+                            universal_newlines=True)
+    try:
+      script_output = proc.communicate(timeout=timeout)[0]
+    except subprocess.TimeoutExpired:
+      print("[TIMEDOUT]")
+      proc.kill()
+      script_output = proc.communicate()[0]
+
+    _debug_print("[STDOUT]", script_output)
+    return_code = proc.wait()
+    passed = (return_code == 0)
+    _debug_print("[$?]", return_code)
+    if not passed:
+      print("[FAILED, code:%s]" %(return_code), script_output, file=sys.stderr)
+
+    return (passed, script_output)
+
+def execute_run_combos(grouped_run_combos: Iterable[Tuple[CollectorPackageInfo, Iterable[RunCommandArgs]]], simulate: bool, inodes_path: str, timeout: int, loop_count: int, need_trace: bool):
+  # nothing will work if the screen isn't unlocked first.
+  execute_arbitrary_command([_UNLOCK_SCREEN_SCRIPT], simulate, timeout)
+
+  for collector_info, run_combos in grouped_run_combos:
+    #collector_args = ["--package", package_name]
+    collector_args = as_run_command(collector_info)
+    # TODO: forward --wait_time for how long systrace runs?
+    # TODO: forward --trace_buffer_size for size of systrace buffer size?
+    collector_cmd, collector_tmp_output_file = make_script_command_with_temp_output(_COLLECTOR_SCRIPT, collector_args, inodes=inodes_path)
+
+    with collector_tmp_output_file:
+      collector_passed = True
+      if need_trace:
+        collector_timeout = timeout and _COLLECTOR_TIMEOUT_MULTIPLIER * timeout
+        (collector_passed, collector_script_output) = execute_arbitrary_command(collector_cmd, simulate, collector_timeout)
+        # TODO: consider to print a ; collector wrote file to <...> into the CSV file so we know it was ran.
+
+      for combos in run_combos:
+        args = as_run_command(combos)
+
+        cmd, tmp_output_file = make_script_command_with_temp_output(_RUN_SCRIPT, args, count=loop_count, input=collector_tmp_output_file.name)
+        with tmp_output_file:
+          (passed, script_output) = execute_arbitrary_command(cmd, simulate, timeout)
+          parsed_output = simulate and [1,2,3] or parse_run_script_csv_file(tmp_output_file)
+          yield (passed, script_output, parsed_output)
+
+def gather_results(commands: Iterable[Tuple[bool, str, List[int]]], key_list: List[str], value_list: List[Tuple[str, ...]]):
+  _debug_print("gather_results: key_list = ", key_list)
+  yield key_list + ["time(ms)"]
+
+  stringify_none = lambda s: s is None and "<none>" or s
+
+  for ((passed, script_output, run_result_list), values) in itertools.zip_longest(commands, value_list):
+    if not passed:
+      continue
+    for result in run_result_list:
+      yield [stringify_none(i) for i in values] + [result]
+
+    yield ["; avg(%s), min(%s), max(%s), count(%s)" %(sum(run_result_list, 0.0) / len(run_result_list), min(run_result_list), max(run_result_list), len(run_result_list)) ]
+
+def eval_and_save_to_csv(output, annotated_result_values):
+  csv_writer = csv.writer(output)
+  for row in annotated_result_values:
+    csv_writer.writerow(row)
+    output.flush() # see the output live.
+
+def main():
+  global _debug
+
+  opts = parse_options()
+  _debug = opts.debug
+  if _DEBUG_FORCE is not None:
+    _debug = _DEBUG_FORCE
+  _debug_print("parsed options: ", opts)
+  need_trace = not not set(opts.readaheads).intersection(set(_TRACING_READAHEADS))
+  if need_trace and not opts.inodes:
+    print("Error: Missing -in/--inodes, required when using a readahead of %s" %(_TRACING_READAHEADS), file=sys.stderr)
+    return 1
+
+  output_file = opts.output and open(opts.output, 'w') or sys.stdout
+
+  combos = lambda: generate_run_combinations(RunCommandArgs, vars(opts))
+  _debug_print_gen("run combinations: ", combos())
+
+  grouped_combos = lambda: generate_group_run_combinations(combos(), CollectorPackageInfo)
+  _debug_print_gen("grouped run combinations: ", grouped_combos())
+
+  exec = execute_run_combos(grouped_combos(), opts.simulate, opts.inodes, opts.timeout, opts.loop_count, need_trace)
+  results = gather_results(exec, _COMBINATORIAL_OPTIONS, combos())
+  eval_and_save_to_csv(output_file, results)
+
+  return 0
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/startop/scripts/app_startup/app_startup_runner_test.py b/startop/scripts/app_startup/app_startup_runner_test.py
new file mode 100755
index 0000000..f96f802a
--- /dev/null
+++ b/startop/scripts/app_startup/app_startup_runner_test.py
@@ -0,0 +1,210 @@
+#!/usr/bin/env python3
+#
+# Copyright 2018, The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+"""
+Unit tests for the app_startup_runner.py script.
+
+Install:
+  $> sudo apt-get install python3-pytest   ##  OR
+  $> pip install -U pytest
+See also https://docs.pytest.org/en/latest/getting-started.html
+
+Usage:
+  $> ./app_startup_runner_test.py
+  $> pytest app_startup_runner_test.py
+  $> python -m pytest app_startup_runner_test.py
+
+See also https://docs.pytest.org/en/latest/usage.html
+"""
+
+# global imports
+from contextlib import contextmanager
+import io
+import shlex
+import sys
+import typing
+
+# pip imports
+import pytest
+
+# local imports
+import app_startup_runner as asr
+
+#
+# Argument Parsing Helpers
+#
+
+@contextmanager
+def ignore_stdout_stderr():
+  """Ignore stdout/stderr output for duration of this context."""
+  old_stdout = sys.stdout
+  old_stderr = sys.stderr
+  sys.stdout = io.StringIO()
+  sys.stderr = io.StringIO()
+  try:
+    yield
+  finally:
+    sys.stdout = old_stdout
+    sys.stderr = old_stderr
+
+@contextmanager
+def argparse_bad_argument(msg):
+  """
+  Assert that a SystemExit is raised when executing this context.
+  If the assertion fails, print the message 'msg'.
+  """
+  with pytest.raises(SystemExit, message=msg):
+    with ignore_stdout_stderr():
+      yield
+
+def assert_bad_argument(args, msg):
+  """
+  Assert that the command line arguments in 'args' are malformed.
+  Prints 'msg' if the assertion fails.
+  """
+  with argparse_bad_argument(msg):
+    parse_args(args)
+
+def parse_args(args):
+  """
+  :param args: command-line like arguments as a single string
+  :return:  dictionary of parsed key/values
+  """
+  # "-a b -c d"    => ['-a', 'b', '-c', 'd']
+  return vars(asr.parse_options(shlex.split(args)))
+
+def default_dict_for_parsed_args(**kwargs):
+  """
+  # Combine it with all of the "optional" parameters' default values.
+  """
+  d = {'compiler_filters': None, 'simulate': False, 'debug': False, 'output': None, 'timeout': None, 'loop_count': 1, 'inodes': None}
+  d.update(kwargs)
+  return d
+
+def default_mock_dict_for_parsed_args(include_optional=True, **kwargs):
+  """
+  Combine default dict with all optional parameters with some mock required parameters.
+  """
+  d = {'packages': ['com.fake.package'], 'readaheads': ['warm']}
+  if include_optional:
+    d.update(default_dict_for_parsed_args())
+  d.update(kwargs)
+  return d
+
+def parse_optional_args(str):
+  """
+  Parse an argument string which already includes all the required arguments
+  in default_mock_dict_for_parsed_args.
+  """
+  req = "--package com.fake.package --readahead warm"
+  return parse_args("%s %s" %(req, str))
+
+def test_argparse():
+  # missing arguments
+  assert_bad_argument("", "-p and -r are required")
+  assert_bad_argument("-r warm", "-p is required")
+  assert_bad_argument("--readahead warm", "-p is required")
+  assert_bad_argument("-p com.fake.package", "-r is required")
+  assert_bad_argument("--package com.fake.package", "-r is required")
+
+  # required arguments are parsed correctly
+  ad = default_dict_for_parsed_args  # assert dict
+
+  assert parse_args("--package xyz --readahead warm") == ad(packages=['xyz'], readaheads=['warm'])
+  assert parse_args("-p xyz -r warm") == ad(packages=['xyz'], readaheads=['warm'])
+
+  assert parse_args("-p xyz -r warm -s") == ad(packages=['xyz'], readaheads=['warm'], simulate=True)
+  assert parse_args("-p xyz -r warm --simulate") == ad(packages=['xyz'], readaheads=['warm'], simulate=True)
+
+  # optional arguments are parsed correctly.
+  mad = default_mock_dict_for_parsed_args  # mock assert dict
+  assert parse_optional_args("--output filename.csv") == mad(output='filename.csv')
+  assert parse_optional_args("-o filename.csv") == mad(output='filename.csv')
+
+  assert parse_optional_args("--timeout 123") == mad(timeout=123)
+  assert parse_optional_args("-t 456") == mad(timeout=456)
+
+  assert parse_optional_args("--loop-count 123") == mad(loop_count=123)
+  assert parse_optional_args("-lc 456") == mad(loop_count=456)
+
+  assert parse_optional_args("--inodes bar") == mad(inodes="bar")
+  assert parse_optional_args("-in baz") == mad(inodes="baz")
+
+
+def generate_run_combinations(*args):
+  # expand out the generator values so that assert x == y works properly.
+  return [i for i in asr.generate_run_combinations(*args)]
+
+def test_generate_run_combinations():
+  blank_nd = typing.NamedTuple('Blank')
+  assert generate_run_combinations(blank_nd, {}) == [()], "empty"
+  assert generate_run_combinations(blank_nd, {'a' : ['a1', 'a2']}) == [()], "empty filter"
+  a_nd = typing.NamedTuple('A', [('a', str)])
+  assert generate_run_combinations(a_nd, {'a': None}) == [(None,)], "None"
+  assert generate_run_combinations(a_nd, {'a': ['a1', 'a2']}) == [('a1',), ('a2',)], "one item"
+  assert generate_run_combinations(a_nd,
+                                   {'a' : ['a1', 'a2'], 'b': ['b1', 'b2']}) == [('a1',), ('a2',)],\
+      "one item filter"
+  ab_nd = typing.NamedTuple('AB', [('a', str), ('b', str)])
+  assert generate_run_combinations(ab_nd,
+                                   {'a': ['a1', 'a2'],
+                                    'b': ['b1', 'b2']}) == [ab_nd('a1', 'b1'),
+                                                            ab_nd('a1', 'b2'),
+                                                            ab_nd('a2', 'b1'),
+                                                            ab_nd('a2', 'b2')],\
+      "two items"
+
+  assert generate_run_combinations(ab_nd,
+                                   {'as': ['a1', 'a2'],
+                                    'bs': ['b1', 'b2']}) == [ab_nd('a1', 'b1'),
+                                                             ab_nd('a1', 'b2'),
+                                                             ab_nd('a2', 'b1'),
+                                                             ab_nd('a2', 'b2')],\
+      "two items plural"
+
+def test_key_to_cmdline_flag():
+  assert asr.key_to_cmdline_flag("abc") == "--abc"
+  assert asr.key_to_cmdline_flag("foos") == "--foo"
+  assert asr.key_to_cmdline_flag("ba_r") == "--ba-r"
+  assert asr.key_to_cmdline_flag("ba_zs") == "--ba-z"
+
+
+def test_make_script_command_with_temp_output():
+  cmd_str, tmp_file = asr.make_script_command_with_temp_output("fake_script", args=[], count=1)
+  with tmp_file:
+    assert cmd_str == ["fake_script", "--count", "1", "--output", tmp_file.name]
+
+  cmd_str, tmp_file = asr.make_script_command_with_temp_output("fake_script", args=['a', 'b'], count=2)
+  with tmp_file:
+    assert cmd_str == ["fake_script", "a", "b", "--count", "2", "--output", tmp_file.name]
+
+def test_parse_run_script_csv_file():
+  # empty file -> empty list
+  f = io.StringIO("")
+  assert asr.parse_run_script_csv_file(f) == []
+
+  # common case
+  f = io.StringIO("1,2,3")
+  assert asr.parse_run_script_csv_file(f) == [1,2,3]
+
+  # ignore trailing comma
+  f = io.StringIO("1,2,3,4,5,")
+  assert asr.parse_run_script_csv_file(f) == [1,2,3,4,5]
+
+
+if __name__ == '__main__':
+  pytest.main()
diff --git a/startop/scripts/app_startup/launch_application b/startop/scripts/app_startup/launch_application
new file mode 100755
index 0000000..bc4ec51
--- /dev/null
+++ b/startop/scripts/app_startup/launch_application
@@ -0,0 +1,41 @@
+#!/bin/bash
+#
+# Copyright 2018, The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+source "$DIR/lib/common"
+
+launch_application() {
+  local package="$1"
+  local activity="$2"
+  local am_output="$(adb shell am start -S -W "$package"/"$activity")"
+  verbose_print adb shell am start -S -W "$package"/"$activity"
+  if [[ $? -ne 0 ]]; then
+    echo "am start failed" >&2
+
+    return 1
+  fi
+
+  # for everything else use the am start "TotalTime" output.
+  verbose_print "$am_output"
+  local total_time="$(echo "$am_output" | grep 'TotalTime:' | sed 's/TotalTime: //g')"
+  verbose_print "total time: $total_time"
+
+  # TODO: Extract alternative metrics such as the #reportFullyDrawn.
+
+  echo "$total_time"
+}
+
+launch_application "$@"
diff --git a/startop/scripts/app_startup/lib/common b/startop/scripts/app_startup/lib/common
new file mode 100755
index 0000000..4d5a53e
--- /dev/null
+++ b/startop/scripts/app_startup/lib/common
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+if [[ -z $ANDROID_BUILD_TOP ]]; then
+  echo "Please run source build/envsetup.sh first" >&2
+  exit 1
+fi
+
+source $ANDROID_BUILD_TOP/build/envsetup.sh
+
+verbose_print() {
+  if [[ "$verbose" == "y" ]]; then
+    echo "$@" >&2
+  fi
+}
diff --git a/startop/scripts/app_startup/run_app_with_prefetch b/startop/scripts/app_startup/run_app_with_prefetch
new file mode 100755
index 0000000..1ff5fc6
--- /dev/null
+++ b/startop/scripts/app_startup/run_app_with_prefetch
@@ -0,0 +1,344 @@
+#!/bin/bash
+#
+# Copyright 2018, The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+usage() {
+    cat <<EOF
+Usage: run_app_with_prefetch --package <name> [OPTIONS]...
+
+    -p, --package <name>        package of the app to test
+    -a, --activity <name>       activity to use
+    -h, --help                  usage information (this)
+    -v, --verbose               enable extra verbose printing
+    -i, --input <file>          trace file protobuf (default 'TraceFile.pb')
+    -r, --readahead <mode>      cold, warm, fadvise, mlock (default 'warm')
+    -w, --when <when>           aot or jit (default 'aot')
+    -c, --count <count>         how many times to run (default 1)
+    -s, --sleep <sec>           how long to sleep after readahead
+    -t, --timeout <sec>         how many seconds to timeout in between each app run (default 10)
+    -o, --output <file.csv>     what file to write the performance results into as csv (default stdout)
+EOF
+}
+
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+source "$DIR/lib/common"
+
+needs_trace_file="n"
+input_file=""
+package=""
+mode='warm'
+count=2
+sleep_time=2
+timeout=10
+output="" # stdout by default
+when="aot"
+parse_arguments() {
+  while [[ $# -gt 0 ]]; do
+    case "$1" in
+      -h|--help)
+        usage
+        exit 0
+        ;;
+      -p|--package)
+        package="$2"
+        shift
+        ;;
+      -a|--activity)
+        activity="$2"
+        shift
+        ;;
+      -i|--input)
+        input_file="$2"
+        shift
+        ;;
+      -v|--verbose)
+        export verbose="y"
+        ;;
+      -r|--readahead)
+        mode="$2"
+        shift
+        ;;
+      -c|--count)
+        count="$2"
+        ((count+=1))
+        shift
+        ;;
+      -s|--sleep)
+        sleep_time="$2"
+        shift
+        ;;
+      -t|--timeout)
+        timeout="$2"
+        shift
+        ;;
+      -o|--output)
+        output="$2"
+        shift
+        ;;
+      -w|--when)
+        when="$2"
+        shift
+        ;;
+      --compiler-filter)
+        # ignore any '--compiler-filter xyz' settings.
+        # FIXME: app_startup_runner.py should not be passing this flag.
+        shift
+        ;;
+      *)
+        echo "Invalid argument: $1" >&2
+        exit 1
+    esac
+    shift
+  done
+}
+
+echo_to_output_file() {
+  if [[ "x$output" != x ]]; then
+    echo "$@" >> $output
+  fi
+  # Always echo to stdout as well.
+  echo "$@"
+}
+
+get_activity_name() {
+  local package="$1"
+  local action_key="android.intent.action.MAIN:"
+
+  local activity_line="$(adb shell cmd package query-activities --brief -a android.intent.action.MAIN -c android.intent.category.LAUNCHER | grep "$package")"
+  #echo $activity_line
+  IFS="/" read -a array <<< "$activity_line"
+  local activity_name="${array[1]}"
+  echo "$activity_name"
+  #adb shell am start "$package/$activity_name"
+}
+
+find_package_path() {
+  local pkg="$1"
+
+  res="$(adb shell find "/data/app/$pkg"-'*' -maxdepth 0 2> /dev/null)"
+  if [[ -z $res ]]; then
+    res="$(adb shell find "/system/app/$pkg"-'*' -maxdepth 0 2> /dev/null)"
+  fi
+  echo "$res"
+}
+
+remote_pkill() {
+  local what="$1"
+  adb shell "for i in $(pid $what); do kill \$i; done"
+}
+
+# Main entry point
+if [[ $# -eq 0 ]]; then
+  usage
+  exit 1
+else
+  parse_arguments "$@"
+
+  # if we do not have have package exit early with an error
+  [[ "$package" == "" ]] && echo "--package not specified" 1>&2 && exit 1
+
+  if [[ $mode != "cold" && $mode != "warm" ]]; then
+    needs_trace_file="y"
+    if [[ -z "$input_file" ]] || ! [[ -f $input_file ]]; then
+      echo "--input not specified" 1>&2
+      exit 1
+    fi
+  fi
+
+  if [[ "$activity" == "" ]]; then
+    activity="$(get_activity_name "$package")"
+    if [[ "$activity" == "" ]]; then
+      echo "Activity name could not be found, invalid package name?" 1>&2
+      exit 1
+    else
+      verbose_print "Activity name inferred: " "$activity"
+    fi
+  fi
+fi
+
+adb root > /dev/null
+
+if [[ ($when == jit) || ($when == aot) ]] && [[ "$(adb shell getenforce)" != "Permissive" ]]; then
+  echo "Disable selinux permissions and restart framework."
+  adb shell setenforce 0
+  adb shell stop
+  adb shell start
+  adb wait-for-device
+fi
+
+# TODO: set performance governor etc, preferrably only once
+# before every single app run.
+
+# Kill everything before running.
+remote_pkill "$package"
+sleep 1
+
+timings_array=()
+
+package_path="$(find_package_path "$package")"
+if [[ $? -ne 0 ]]; then
+  echo "Failed to detect package path for '$package'" >&2
+  exit 1
+fi
+verbose_print "Package was in path '$package_path'"
+
+
+
+
+keep_application_trace_file=n
+application_trace_file_path="$package_path/TraceFile.pb"
+trace_file_directory="$package_path"
+if [[ $needs_trace_file == y ]]; then
+  # system server always passes down the package path in a hardcoded spot.
+  if [[ $when == "jit" ]]; then
+    verbose_print adb push "$input_file" "$application_trace_file_path"
+    adb push "$input_file" "$application_trace_file_path"
+    keep_application_trace_file="y"
+  else
+    # otherwise use a temporary directory to get normal non-jit behavior.
+    trace_file_directory="/data/local/tmp/prefetch/$package"
+    adb shell mkdir -p "$trace_file_directory"
+    verbose_print  adb push "$input_file" "$trace_file_directory/TraceFile.pb"
+    adb push "$input_file" "$trace_file_directory/TraceFile.pb"
+  fi
+fi
+
+# Everything other than JIT: remove the trace file,
+# otherwise system server activity hints will kick in
+# and the new just-in-time app pre-warmup will happen.
+if [[ $keep_application_trace_file == "n" ]]; then
+  adb shell "[[ -f '$application_trace_file_path' ]] && rm '$application_trace_file_path'"
+fi
+
+# Perform AOT readahead/pinning/etc when an application is about to be launched.
+# For JIT readahead, we allow the system to handle it itself (this is a no-op).
+#
+# For warm, cold, etc modes which don't need readahead this is always a no-op.
+perform_aot() {
+  local the_when="$1" # user: aot, jit
+  local the_mode="$2" # warm, cold, fadvise, mlock, etc.
+
+  if [[ $the_when != "aot" ]]; then
+    # TODO: just in time implementation.. should probably use system server.
+    return 0
+  fi
+
+  # any non-warm/non-cold modes should use the iorap-activity-hint wrapper script.
+  if [[ $the_mode != 'warm' && $the_mode != 'cold' ]]; then
+
+    # TODO: add activity_hint_sender.exp
+    verbose_print "starting with package=$package package_path=$trace_file_directory"
+    coproc hint_sender_fd { $ANDROID_BUILD_TOP/system/iorap/src/sh/activity_hint_sender.exp "$package" "$trace_file_directory" "$the_mode"; }
+    hint_sender_pid=$!
+    verbose_print "Activity hint sender began"
+
+    notification_success="n"
+    while read -r -u "${hint_sender_fd[0]}" hint_sender_output; do
+      verbose_print "$hint_sender_output"
+      if [[ "$hint_sender_output" == "Press any key to send completed event..."* ]]; then
+        verbose_print "WE DID SEE NOTIFICATION SUCCESS."
+        notification_success='y'
+        # Give it some time to actually perform the readaheads.
+        sleep $sleep_time
+        break
+      fi
+    done
+
+    if [[ $notification_success == 'n' ]]; then
+      echo "[FATAL] Activity hint notification failed." 1>&2
+      exit 1
+    fi
+  fi
+}
+
+perform_aot_cleanup() {
+  local the_when="$1" # user: aot, jit
+  local the_mode="$2" # warm, cold, fadvise, mlock, etc.
+
+  if [[ $the_when != "aot" ]]; then
+    # TODO: just in time implementation.. should probably use system server.
+    return 0
+  fi
+
+  # any non-warm/non-cold modes should use the iorap-activity-hint wrapper script.
+  if [[ $the_mode != 'warm' && $the_mode != 'cold' ]]; then
+    # Clean up the hint sender by telling it that the launch was completed,
+    # and to shutdown the watcher.
+    echo "Done\n" >&"${hint_sender_fd[1]}"
+
+    while read -r -u "${hint_sender_fd[0]}" hint_sender_output; do
+      verbose_print "$hint_sender_output"
+    done
+
+    wait $hint_sender_pid
+  fi
+}
+
+# TODO: This loop logic could probably be moved into app_startup_runner.py
+for ((i=0;i<count;++i)) do
+  verbose_print "=========================================="
+  verbose_print "====         ITERATION $i             ===="
+  verbose_print "=========================================="
+  if [[ $mode != "warm" ]]; then
+    verbose_print "Drop caches for non-warm start."
+    # Drop all caches to get cold starts.
+    adb shell "echo 3 > /proc/sys/vm/drop_caches"
+  fi
+
+  perform_aot "$when" "$mode"
+
+  verbose_print "Running with timeout $timeout"
+
+  # TODO: multiple metrics output.
+  total_time="$(timeout $timeout $DIR/launch_application "$package" "$activity")"
+
+  if [[ $? -ne 0 ]]; then
+    echo "WARNING: Skip bad result, try iteration again." >&2
+    ((i=i-1))
+    continue
+  fi
+
+  perform_aot_cleanup "$when" "$mode"
+
+  echo "Iteration $i. Total time was: $total_time"
+
+  timings_array+=($total_time)
+done
+
+# drop the first result which is usually garbage.
+timings_array=("${timings_array[@]:1}")
+
+
+# Print out interactive/debugging timings and averages.
+# Other scripts should use the --output flag and parse the CSV.
+for tim in "${timings_array[@]}"; do
+  echo_to_output_file -ne "$tim,"
+done
+echo_to_output_file ""
+
+average_string=$(echo "${timings_array[@]}" | awk '{s+=$0}END{print "Average:",s/NR}' RS=" ")
+echo -ne ${average_string}.
+if [[ x$output != x ]]; then
+  echo " Saved results to '$output'"
+fi
+
+# Temporary hack around multiple activities being launched with different package paths (for same app):
+# Clean up all left-over TraceFile.pb
+adb shell 'for i in $(find /data/app -name TraceFile.pb); do rm \$i; done'
+
+# Kill the process to ensure AM isn't keeping it around.
+remote_pkill "$package"
+
+exit 0
diff --git a/startop/scripts/app_startup/unlock_screen b/startop/scripts/app_startup/unlock_screen
new file mode 100755
index 0000000..478294c
--- /dev/null
+++ b/startop/scripts/app_startup/unlock_screen
@@ -0,0 +1,22 @@
+#!/bin/bash
+#
+# Copyright 2018, The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# This turns the screen on if it's off.
+# If it's on it does nothing unless its on the home screen, in which case it opens up some background
+# menu.
+#
+# However, this menu is ignored because "am start" commands still work as expected.
+adb shell input keyevent MENU
diff --git a/telecomm/java/android/telecom/ParcelableCallAnalytics.java b/telecomm/java/android/telecom/ParcelableCallAnalytics.java
index 383d10b..bb066ad 100644
--- a/telecomm/java/android/telecom/ParcelableCallAnalytics.java
+++ b/telecomm/java/android/telecom/ParcelableCallAnalytics.java
@@ -195,6 +195,8 @@
         public static final int BLOCK_CHECK_FINISHED_TIMING = 9;
         public static final int FILTERING_COMPLETED_TIMING = 10;
         public static final int FILTERING_TIMED_OUT_TIMING = 11;
+        /** {@hide} */
+        public static final int START_CONNECTION_TO_REQUEST_DISCONNECT_TIMING = 12;
 
         public static final int INVALID = 999999;
 
@@ -256,6 +258,27 @@
     public static final int SIP_PHONE = 0x8;
     public static final int THIRD_PARTY_PHONE = 0x10;
 
+    /**
+     * Indicating the call source is not specified.
+     *
+     * @hide
+     */
+    public static final int CALL_SOURCE_UNSPECIFIED = 0;
+
+    /**
+     * Indicating the call is initiated via emergency dialer's dialpad.
+     *
+     * @hide
+     */
+    public static final int CALL_SOURCE_EMERGENCY_DIALPAD = 1;
+
+    /**
+     * Indicating the call is initiated via emergency dialer's shortcut button.
+     *
+     * @hide
+     */
+    public static final int CALL_SOURCE_EMERGENCY_SHORTCUT = 2;
+
     public static final long MILLIS_IN_5_MINUTES = 1000 * 60 * 5;
     public static final long MILLIS_IN_1_SECOND = 1000;
 
@@ -319,6 +342,9 @@
     // A list of video events that have occurred.
     private List<VideoEvent> videoEvents;
 
+    // The source where user initiated this call. ONE OF the CALL_SOURCE_* constants.
+    private int callSource = CALL_SOURCE_UNSPECIFIED;
+
     public ParcelableCallAnalytics(long startTimeMillis, long callDurationMillis, int callType,
             boolean isAdditionalCall, boolean isInterrupted, int callTechnologies,
             int callTerminationCode, boolean isEmergencyCall, String connectionService,
@@ -356,6 +382,7 @@
         isVideoCall = readByteAsBoolean(in);
         videoEvents = new LinkedList<>();
         in.readTypedList(videoEvents, VideoEvent.CREATOR);
+        callSource = in.readInt();
     }
 
     public void writeToParcel(Parcel out, int flags) {
@@ -373,6 +400,7 @@
         out.writeTypedList(eventTimings);
         writeBooleanAsByte(out, isVideoCall);
         out.writeTypedList(videoEvents);
+        out.writeInt(callSource);
     }
 
     /** {@hide} */
@@ -385,6 +413,11 @@
         this.videoEvents = videoEvents;
     }
 
+    /** {@hide} */
+    public void setCallSource(int callSource) {
+        this.callSource = callSource;
+    }
+
     public long getStartTimeMillis() {
         return startTimeMillis;
     }
@@ -443,6 +476,11 @@
         return videoEvents;
     }
 
+    /** {@hide} */
+    public int getCallSource() {
+        return callSource;
+    }
+
     @Override
     public int describeContents() {
         return 0;
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 48c1e24..4e22823 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -622,6 +622,18 @@
             "android.telecom.extra.USE_ASSISTED_DIALING";
 
     /**
+     * Optional extra for {@link #placeCall(Uri, Bundle)} containing an integer that specifies
+     * the source where user initiated this call. This data is used in metrics.
+     * Valid source are:
+     * {@link ParcelableCallAnalytics#CALL_SOURCE_UNSPECIFIED},
+     * {@link ParcelableCallAnalytics#CALL_SOURCE_EMERGENCY_DIALPAD},
+     * {@link ParcelableCallAnalytics#CALL_SOURCE_EMERGENCY_SHORTCUT}.
+     *
+     * @hide
+     */
+    public static final String EXTRA_CALL_SOURCE = "android.telecom.extra.CALL_SOURCE";
+
+    /**
      * The following 4 constants define how properties such as phone numbers and names are
      * displayed to the user.
      */
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 1d9e605..8ebfec4 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -1589,12 +1589,14 @@
     }
 
     /**
-     * @return true if a valid subId else false
-     * @hide
+     * Checks if the supplied subscription ID is valid.
+     * Note: a valid subscription ID does not necessarily correspond to an active subscription.
+     *
+     * @param subscriptionId The subscription ID.
+     * @return true if the supplied subscriptionId is valid; false otherwise.
      */
-    @UnsupportedAppUsage
-    public static boolean isValidSubscriptionId(int subId) {
-        return subId > INVALID_SUBSCRIPTION_ID ;
+    public static boolean isValidSubscriptionId(int subscriptionId) {
+        return subscriptionId > INVALID_SUBSCRIPTION_ID;
     }
 
     /**
diff --git a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
index 102cb7c..99a5a69 100644
--- a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
@@ -41,9 +41,9 @@
 import android.net.NetworkUtils;
 import android.os.Binder;
 import android.os.ParcelFileDescriptor;
-import android.test.mock.MockContext;
 import android.support.test.filters.SmallTest;
 import android.system.Os;
+import android.test.mock.MockContext;
 
 import java.net.Socket;
 import java.util.Arrays;
@@ -121,6 +121,7 @@
     IpSecService.IpSecServiceConfiguration mMockIpSecSrvConfig;
     IpSecService mIpSecService;
     Network fakeNetwork = new Network(0xAB);
+    int mUid = Os.getuid();
 
     private static final IpSecAlgorithm AUTH_ALGO =
             new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, AUTH_KEY, AUTH_KEY.length * 4);
@@ -181,7 +182,7 @@
 
         verify(mMockNetd)
                 .ipSecDeleteSecurityAssociation(
-                        eq(spiResp.resourceId),
+                        eq(mUid),
                         anyString(),
                         anyString(),
                         eq(TEST_SPI),
@@ -189,8 +190,7 @@
                         anyInt());
 
         // Verify quota and RefcountedResource objects cleaned up
-        IpSecService.UserRecord userRecord =
-                mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
+        IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
         assertEquals(0, userRecord.mSpiQuotaTracker.mCurrent);
         try {
             userRecord.mSpiRecords.getRefcountedResourceOrThrow(spiResp.resourceId);
@@ -209,8 +209,7 @@
                 mIpSecService.allocateSecurityParameterIndex(
                         mDestinationAddr, TEST_SPI, new Binder());
 
-        IpSecService.UserRecord userRecord =
-                mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
+        IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
         IpSecService.RefcountedResource refcountedRecord =
                 userRecord.mSpiRecords.getRefcountedResourceOrThrow(spiResp.resourceId);
 
@@ -218,7 +217,7 @@
 
         verify(mMockNetd)
                 .ipSecDeleteSecurityAssociation(
-                        eq(spiResp.resourceId),
+                        eq(mUid),
                         anyString(),
                         anyString(),
                         eq(TEST_SPI),
@@ -270,7 +269,7 @@
 
         verify(mMockNetd)
                 .ipSecAddSecurityAssociation(
-                        eq(createTransformResp.resourceId),
+                        eq(mUid),
                         anyInt(),
                         anyString(),
                         anyString(),
@@ -305,7 +304,7 @@
 
         verify(mMockNetd)
                 .ipSecAddSecurityAssociation(
-                        eq(createTransformResp.resourceId),
+                        eq(mUid),
                         anyInt(),
                         anyString(),
                         anyString(),
@@ -361,13 +360,12 @@
 
         IpSecTransformResponse createTransformResp =
                 mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
-        IpSecService.UserRecord userRecord =
-                mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
+        IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
         assertEquals(1, userRecord.mSpiQuotaTracker.mCurrent);
         mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
         verify(mMockNetd, times(0))
                 .ipSecDeleteSecurityAssociation(
-                        eq(createTransformResp.resourceId),
+                        eq(mUid),
                         anyString(),
                         anyString(),
                         eq(TEST_SPI),
@@ -389,7 +387,7 @@
 
         verify(mMockNetd, times(1))
                 .ipSecDeleteSecurityAssociation(
-                        eq(createTransformResp.resourceId),
+                        eq(mUid),
                         anyString(),
                         anyString(),
                         eq(TEST_SPI),
@@ -397,8 +395,7 @@
                         anyInt());
 
         // Verify quota and RefcountedResource objects cleaned up
-        IpSecService.UserRecord userRecord =
-                mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
+        IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
         assertEquals(0, userRecord.mTransformQuotaTracker.mCurrent);
         assertEquals(1, userRecord.mSpiQuotaTracker.mCurrent);
 
@@ -433,8 +430,7 @@
         IpSecTransformResponse createTransformResp =
                 mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
 
-        IpSecService.UserRecord userRecord =
-                mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
+        IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
         IpSecService.RefcountedResource refcountedRecord =
                 userRecord.mTransformRecords.getRefcountedResourceOrThrow(
                         createTransformResp.resourceId);
@@ -443,7 +439,7 @@
 
         verify(mMockNetd)
                 .ipSecDeleteSecurityAssociation(
-                        eq(createTransformResp.resourceId),
+                        eq(mUid),
                         anyString(),
                         anyString(),
                         eq(TEST_SPI),
@@ -477,7 +473,7 @@
         verify(mMockNetd)
                 .ipSecApplyTransportModeTransform(
                         eq(pfd.getFileDescriptor()),
-                        eq(resourceId),
+                        eq(mUid),
                         eq(IpSecManager.DIRECTION_OUT),
                         anyString(),
                         anyString(),
@@ -509,8 +505,7 @@
                 createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage");
 
         // Check that we have stored the tracking object, and retrieve it
-        IpSecService.UserRecord userRecord =
-                mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
+        IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
         IpSecService.RefcountedResource refcountedRecord =
                 userRecord.mTunnelInterfaceRecords.getRefcountedResourceOrThrow(
                         createTunnelResp.resourceId);
@@ -530,8 +525,7 @@
         IpSecTunnelInterfaceResponse createTunnelResp =
                 createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage");
 
-        IpSecService.UserRecord userRecord =
-                mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
+        IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
 
         mIpSecService.deleteTunnelInterface(createTunnelResp.resourceId, "blessedPackage");
 
@@ -551,8 +545,7 @@
         IpSecTunnelInterfaceResponse createTunnelResp =
                 createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage");
 
-        IpSecService.UserRecord userRecord =
-                mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
+        IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
         IpSecService.RefcountedResource refcountedRecord =
                 userRecord.mTunnelInterfaceRecords.getRefcountedResourceOrThrow(
                         createTunnelResp.resourceId);
diff --git a/tools/aosp/aosp_sha.sh b/tools/aosp/aosp_sha.sh
index 29bf74c..e50c70d 100755
--- a/tools/aosp/aosp_sha.sh
+++ b/tools/aosp/aosp_sha.sh
@@ -1,18 +1,24 @@
 #!/bin/bash
-LOCAL_DIR="$( dirname ${BASH_SOURCE} )"
+LOCAL_DIR="$( dirname "${BASH_SOURCE}" )"
 
-if git branch -vv | grep "^*" | grep "\[aosp/master" > /dev/null; then
+if git branch -vv | grep -q -P "^\*[^\[]+\[aosp/"; then
     # Change appears to be in AOSP
     exit 0
 else
     # Change appears to be non-AOSP; search for files
-    git show --name-only --pretty=format: $1 | grep $2 | while read file; do
-        echo
+    count=0
+    while read -r file ; do
+        if (( count == 0 )); then
+            echo
+        fi
         echo -e "\033[0;31mThe source of truth for '$file' is in AOSP.\033[0m"
+        (( count++ ))
+    done < <(git show --name-only --pretty=format: $1 | grep -- "$2")
+    if (( count != 0 )); then
         echo
-        echo "If your change contains no confidential details, please upload and merge"
-        echo "this change at https://android-review.googlesource.com/."
+        echo "If your change contains no confidential details (such as security fixes), please"
+        echo "upload and merge this change at https://android-review.googlesource.com/."
         echo
         exit 77
-    done
+    fi
 fi