Merge "Do not throttle EXEMPT apps on battery saver"
diff --git a/Android.bp b/Android.bp
index ee2281f..7fac01a 100644
--- a/Android.bp
+++ b/Android.bp
@@ -113,6 +113,7 @@
         "core/java/android/content/IOnPrimaryClipChangedListener.aidl",
         "core/java/android/content/IRestrictionsManager.aidl",
         "core/java/android/content/ISyncAdapter.aidl",
+        "core/java/android/content/ISyncAdapterUnsyncableAccountCallback.aidl",
         "core/java/android/content/ISyncContext.aidl",
         "core/java/android/content/ISyncServiceAdapter.aidl",
         "core/java/android/content/ISyncStatusObserver.aidl",
@@ -211,6 +212,11 @@
         "core/java/android/nfc/INfcUnlockHandler.aidl",
         "core/java/android/nfc/INfcDta.aidl",
         "core/java/android/nfc/ITagRemovedCallback.aidl",
+        "core/java/android/se/omapi/ISecureElementService.aidl",
+        "core/java/android/se/omapi/ISecureElementListener.aidl",
+        "core/java/android/se/omapi/ISecureElementChannel.aidl",
+        "core/java/android/se/omapi/ISecureElementReader.aidl",
+        "core/java/android/se/omapi/ISecureElementSession.aidl",
         "core/java/android/os/IBatteryPropertiesListener.aidl",
         "core/java/android/os/IBatteryPropertiesRegistrar.aidl",
         "core/java/android/os/ICancellationSignal.aidl",
@@ -331,6 +337,8 @@
         "core/java/android/view/IPinnedStackController.aidl",
         "core/java/android/view/IPinnedStackListener.aidl",
         "core/java/android/view/IRemoteAnimationRunner.aidl",
+        "core/java/android/view/IRecentsAnimationController.aidl",
+        "core/java/android/view/IRecentsAnimationRunner.aidl",
         "core/java/android/view/IRemoteAnimationFinishedCallback.aidl",
         "core/java/android/view/IRotationWatcher.aidl",
         "core/java/android/view/IWallpaperVisibilityListener.aidl",
diff --git a/api/current.txt b/api/current.txt
index fbcedc0..2b6da9f 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -73,7 +73,6 @@
     field public static final java.lang.String DUMP = "android.permission.DUMP";
     field public static final java.lang.String EXPAND_STATUS_BAR = "android.permission.EXPAND_STATUS_BAR";
     field public static final java.lang.String FACTORY_TEST = "android.permission.FACTORY_TEST";
-    field public static final java.lang.String FOREGROUND_SERVICE = "android.permission.FOREGROUND_SERVICE";
     field public static final java.lang.String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS";
     field public static final java.lang.String GET_ACCOUNTS_PRIVILEGED = "android.permission.GET_ACCOUNTS_PRIVILEGED";
     field public static final java.lang.String GET_PACKAGE_SIZE = "android.permission.GET_PACKAGE_SIZE";
@@ -8767,6 +8766,7 @@
     method public void onSecurityException(android.accounts.Account, android.os.Bundle, java.lang.String, android.content.SyncResult);
     method public void onSyncCanceled();
     method public void onSyncCanceled(java.lang.Thread);
+    method public boolean onUnsyncableAccount();
     field public static final deprecated int LOG_SYNC_DETAILS = 2743; // 0xab7
   }
 
@@ -13569,6 +13569,7 @@
   public static class ImageDecoder.ImageInfo {
     method public java.lang.String getMimeType();
     method public android.util.Size getSize();
+    method public boolean isAnimated();
   }
 
   public static class ImageDecoder.IncompleteException extends java.io.IOException {
@@ -14439,6 +14440,22 @@
     method public void onAnimationStart(android.graphics.drawable.Drawable);
   }
 
+  public class AnimatedImageDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Animatable2 {
+    ctor public AnimatedImageDrawable();
+    method public void clearAnimationCallbacks();
+    method public void draw(android.graphics.Canvas);
+    method public int getOpacity();
+    method public boolean isRunning();
+    method public void registerAnimationCallback(android.graphics.drawable.Animatable2.AnimationCallback);
+    method public void setAlpha(int);
+    method public void setColorFilter(android.graphics.ColorFilter);
+    method public void setLoopCount(int);
+    method public void start();
+    method public void stop();
+    method public boolean unregisterAnimationCallback(android.graphics.drawable.Animatable2.AnimationCallback);
+    field public static final int LOOP_INFINITE = -1; // 0xffffffff
+  }
+
   public class AnimatedStateListDrawable extends android.graphics.drawable.StateListDrawable {
     ctor public AnimatedStateListDrawable();
     method public void addState(int[], android.graphics.drawable.Drawable, int);
@@ -23414,6 +23431,7 @@
     method public java.util.Map<java.util.UUID, byte[]> getPsshInfo();
     method public boolean getSampleCryptoInfo(android.media.MediaCodec.CryptoInfo);
     method public int getSampleFlags();
+    method public long getSampleSize();
     method public long getSampleTime();
     method public int getSampleTrackIndex();
     method public final int getTrackCount();
@@ -36517,6 +36535,18 @@
     field public static final deprecated java.lang.String WINDOW_ANIMATION_SCALE = "window_animation_scale";
   }
 
+  public class SettingsSlicesContract {
+    field public static final java.lang.String AUTHORITY = "android.settings.slices";
+    field public static final android.net.Uri BASE_URI;
+    field public static final java.lang.String KEY_AIRPLANE_MODE = "airplane_mode";
+    field public static final java.lang.String KEY_BATTERY_SAVER = "battery_saver";
+    field public static final java.lang.String KEY_BLUETOOTH = "bluetooth";
+    field public static final java.lang.String KEY_LOCATION = "location";
+    field public static final java.lang.String KEY_WIFI = "wifi";
+    field public static final java.lang.String PATH_SETTING_ACTION = "action";
+    field public static final java.lang.String PATH_SETTING_INTENT = "intent";
+  }
+
   public class SyncStateContract {
     ctor public SyncStateContract();
   }
@@ -38054,6 +38084,59 @@
 
 }
 
+package android.se.omapi {
+
+  public class Channel {
+    method public void close();
+    method public byte[] getSelectResponse();
+    method public android.se.omapi.Session getSession();
+    method public boolean isBasicChannel();
+    method public boolean isClosed();
+    method public boolean selectNext() throws java.io.IOException;
+    method public byte[] transmit(byte[]) throws java.io.IOException;
+  }
+
+  public abstract interface ISecureElementListener implements android.os.IInterface {
+    method public abstract void serviceConnected() throws android.os.RemoteException;
+  }
+
+  public static abstract class ISecureElementListener.Stub extends android.os.Binder implements android.se.omapi.ISecureElementListener {
+    ctor public ISecureElementListener.Stub();
+    method public android.os.IBinder asBinder();
+    method public static android.se.omapi.ISecureElementListener asInterface(android.os.IBinder);
+    method public boolean onTransact(int, android.os.Parcel, android.os.Parcel, int) throws android.os.RemoteException;
+  }
+
+  public class Reader {
+    method public void closeSessions();
+    method public java.lang.String getName();
+    method public android.se.omapi.SEService getSEService();
+    method public boolean isSecureElementPresent();
+    method public android.se.omapi.Session openSession() throws java.io.IOException;
+  }
+
+  public class SEService {
+    ctor public SEService(android.content.Context, android.se.omapi.ISecureElementListener);
+    method public android.se.omapi.Reader[] getReaders();
+    method public java.lang.String getVersion();
+    method public boolean isConnected();
+    method public void shutdown();
+  }
+
+  public class Session {
+    method public void close();
+    method public void closeChannels();
+    method public byte[] getATR();
+    method public android.se.omapi.Reader getReader();
+    method public boolean isClosed();
+    method public android.se.omapi.Channel openBasicChannel(byte[], byte) throws java.io.IOException;
+    method public android.se.omapi.Channel openBasicChannel(byte[]) throws java.io.IOException;
+    method public android.se.omapi.Channel openLogicalChannel(byte[], byte) throws java.io.IOException;
+    method public android.se.omapi.Channel openLogicalChannel(byte[]) throws java.io.IOException;
+  }
+
+}
+
 package android.security {
 
   public final class AttestedKeyPair {
@@ -43780,13 +43863,19 @@
   public class QuoteSpan implements android.text.style.LeadingMarginSpan android.text.ParcelableSpan {
     ctor public QuoteSpan();
     ctor public QuoteSpan(int);
+    ctor public QuoteSpan(int, int, int);
     ctor public QuoteSpan(android.os.Parcel);
     method public int describeContents();
     method public void drawLeadingMargin(android.graphics.Canvas, android.graphics.Paint, int, int, int, int, int, java.lang.CharSequence, int, int, boolean, android.text.Layout);
     method public int getColor();
+    method public int getGapWidth();
     method public int getLeadingMargin(boolean);
     method public int getSpanTypeId();
+    method public int getStripeWidth();
     method public void writeToParcel(android.os.Parcel, int);
+    field public static final int STANDARD_COLOR = -16776961; // 0xff0000ff
+    field public static final int STANDARD_GAP_WIDTH_PX = 2; // 0x2
+    field public static final int STANDARD_STRIPE_WIDTH_PX = 2; // 0x2
   }
 
   public class RelativeSizeSpan extends android.text.style.MetricAffectingSpan implements android.text.ParcelableSpan {
diff --git a/api/removed.txt b/api/removed.txt
index 77088e5..2aab223 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -265,7 +265,6 @@
     method public android.graphics.drawable.Drawable getBadgedDrawableForUser(android.graphics.drawable.Drawable, android.os.UserHandle, android.graphics.Rect, int);
     method public android.graphics.drawable.Drawable getBadgedIconForUser(android.graphics.drawable.Drawable, android.os.UserHandle);
     method public java.lang.CharSequence getBadgedLabelForUser(java.lang.CharSequence, android.os.UserHandle);
-    method public deprecated boolean trySetQuietModeEnabled(boolean, android.os.UserHandle);
   }
 
 }
diff --git a/api/system-current.txt b/api/system-current.txt
index 6be004c..b384920 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -4739,7 +4739,9 @@
     method public int describeContents();
     method public int getAccessNetworkTechnology();
     method public int[] getAvailableServices();
+    method public android.telephony.CellIdentity getCellIdentity();
     method public int getDomain();
+    method public int getReasonForDenial();
     method public int getRegState();
     method public int getTransportType();
     method public boolean isEmergencyEnabled();
@@ -5625,7 +5627,7 @@
     field public final java.lang.String description;
     field public final boolean isFallback;
     field public final java.lang.String packageName;
-    field public final java.lang.String[] signatures;
+    field public final android.content.pm.Signature[] signatures;
   }
 
   public final class WebViewUpdateService {
diff --git a/cmds/bootanimation/FORMAT.md b/cmds/bootanimation/FORMAT.md
index 9ea6fea..5946515 100644
--- a/cmds/bootanimation/FORMAT.md
+++ b/cmds/bootanimation/FORMAT.md
@@ -30,7 +30,7 @@
 
 It is followed by a number of rows of the form:
 
-    TYPE COUNT PAUSE PATH [#RGBHEX CLOCK]
+    TYPE COUNT PAUSE PATH [#RGBHEX [CLOCK1 [CLOCK2]]]
 
   * **TYPE:** a single char indicating what type of animation segment this is:
       + `p` -- this part will play unless interrupted by the end of the boot
@@ -39,11 +39,38 @@
   * **PAUSE:** number of FRAMES to delay after this part ends
   * **PATH:** directory in which to find the frames for this part (e.g. `part0`)
   * **RGBHEX:** _(OPTIONAL)_ a background color, specified as `#RRGGBB`
-  * **CLOCK:** _(OPTIONAL)_ the y-coordinate at which to draw the current time (for watches)
+  * **CLOCK1, CLOCK2:** _(OPTIONAL)_ the coordinates at which to draw the current time (for watches):
+      + If only `CLOCK1` is provided it is the y-coordinate of the clock and the x-coordinate
+        defaults to `c`
+      + If both `CLOCK1` and `CLOCK2` are provided then `CLOCK1` is the x-coordinate and `CLOCK2` is
+        the y-coodinate
+      + Values can be either a positive integer, a negative integer, or `c`
+          - `c` -- will centre the text
+          - `n` -- will position the text n pixels from the start; left edge for x-axis, bottom edge
+            for y-axis
+          - `-n` -- will position the text n pixels from the end; right edge for x-axis, top edge
+            for y-axis
+          - Examples:
+              * `-24` or `c -24` will position the text 24 pixels from the top of the screen,
+                centred horizontally
+              * `16 c` will position the text 16 pixels from the left of the screen, centred
+                vertically
+              * `-32 32` will position the text such that the bottom right corner is 32 pixels above
+                and 32 pixels left of the edges of the screen
 
 There is also a special TYPE, `$SYSTEM`, that loads `/system/media/bootanimation.zip`
 and plays that.
 
+## clock_font.png
+
+The file used to draw the time on top of the boot animation. The font format is as follows:
+  * The file specifies glyphs for the ascii characters 32-127 (0x20-0x7F), both regular weight and
+    bold weight.
+  * The image is divided into a grid of characters
+  * There are 16 columns and 6 rows
+  * Each row is divided in half: regular weight glyphs on the top half, bold glyphs on the bottom
+  * For a NxM image each character glyph will be N/16 pixels wide and M/(12*2) pixels high
+
 ## loading and playing frames
 
 Each part is scanned and loaded directly from the zip archive. Within a part directory, every file
diff --git a/cmds/incident/main.cpp b/cmds/incident/main.cpp
index 519852d..cdec6a0 100644
--- a/cmds/incident/main.cpp
+++ b/cmds/incident/main.cpp
@@ -148,9 +148,19 @@
 static int
 get_dest(const char* arg)
 {
-    if (strcmp(arg, "LOCAL") == 0) return 0;
-    if (strcmp(arg, "EXPLICIT") == 0) return 1;
-    if (strcmp(arg, "AUTOMATIC") == 0) return 2;
+    if (strcmp(arg, "L") == 0
+        || strcmp(arg, "LOCAL") == 0) {
+      return DEST_LOCAL;
+    }
+    if (strcmp(arg, "E") == 0
+        || strcmp(arg, "EXPLICIT") == 0) {
+      return DEST_EXPLICIT;
+    }
+    if (strcmp(arg, "A") == 0
+        || strcmp(arg, "AUTO") == 0
+        || strcmp(arg, "AUTOMATIC") == 0) {
+      return DEST_AUTOMATIC;
+    }
     return -1; // return the default value
 }
 
diff --git a/cmds/incidentd/src/Privacy.cpp b/cmds/incidentd/src/Privacy.cpp
index 5db2239..44adaec 100644
--- a/cmds/incidentd/src/Privacy.cpp
+++ b/cmds/incidentd/src/Privacy.cpp
@@ -67,8 +67,14 @@
 
 PrivacySpec new_spec_from_args(int dest)
 {
-  if (dest < 0) return PrivacySpec();
-  return PrivacySpec(dest);
+    switch (dest) {
+        case android::os::DEST_AUTOMATIC:
+        case android::os::DEST_EXPLICIT:
+        case android::os::DEST_LOCAL:
+            return PrivacySpec(dest);
+        default:
+            return PrivacySpec();
+    }
 }
 
 PrivacySpec get_default_dropbox_spec() { return PrivacySpec(android::os::DEST_AUTOMATIC); }
\ No newline at end of file
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index eabbb96..565b092 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -137,7 +137,7 @@
 
 LOCAL_MODULE_CLASS := EXECUTABLES
 
-LOCAL_INIT_RC := statsd.rc
+#LOCAL_INIT_RC := statsd.rc
 
 include $(BUILD_EXECUTABLE)
 
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 77b156f8..8f0a44a 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -21,7 +21,10 @@
 option java_package = "com.android.os";
 option java_outer_classname = "AtomsProto";
 
-import "frameworks/base/core/proto/android/app/activitymanager.proto";
+import "frameworks/base/core/proto/android/app/enums.proto";
+import "frameworks/base/core/proto/android/os/enums.proto";
+import "frameworks/base/core/proto/android/telephony/enums.proto";
+import "frameworks/base/core/proto/android/view/enums.proto";
 
 /**
  * The master atom class. This message defines all of the available
@@ -44,7 +47,7 @@
         BleUnoptimizedScanStateChanged ble_unoptimized_scan_state_changed = 3;
         BleScanResultReceived ble_scan_result_received = 4;
         SensorStateChanged sensor_state_changed = 5;
-        GpsScanStateChanged gps_scan_state_changed = 6; // TODO: untested
+        GpsScanStateChanged gps_scan_state_changed = 6;
         SyncStateChanged sync_state_changed = 7;
         ScheduledJobStateChanged scheduled_job_state_changed = 8;
         ScreenBrightnessChanged screen_brightness_changed = 9;
@@ -162,18 +165,8 @@
  *   frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
  */
 message ScreenStateChanged {
-    // TODO: Use the real screen state.
-    enum State {
-        STATE_UNKNOWN = 0;
-        STATE_OFF = 1;
-        STATE_ON = 2;
-        STATE_DOZE = 3;
-        STATE_DOZE_SUSPEND = 4;
-        STATE_VR = 5;
-        STATE_ON_SUSPEND = 6;
-    }
-    // New screen state.
-    optional State display_state = 1;
+    // New screen state, from frameworks/base/core/proto/android/view/enums.proto.
+    optional android.view.DisplayStateEnum state = 1;
 }
 
 /**
@@ -185,9 +178,8 @@
 message UidProcessStateChanged {
     optional int32 uid = 1; // TODO: should be a string tagged w/ uid annotation
 
-    // The state.
-    // TODO: Use the real (mapped) process states.
-    optional android.app.ProcessState state = 2;
+    // The state, from frameworks/base/core/proto/android/app/enums.proto.
+    optional android.app.ProcessStateEnum state = 2;
 }
 
 /**
@@ -197,7 +189,6 @@
  *   frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
  */
 message ProcessLifeCycleStateChanged {
-    // TODO: Use the real (mapped) process states.
     optional int32 uid = 1; // TODO: should be a string tagged w/ uid annotation
 
     // TODO: What is this?
@@ -413,13 +404,9 @@
 message WakelockStateChanged {
     repeated AttributionNode attribution_node = 1;
 
-    // Type of wakelock.
-    enum Type {
-        PARTIAL = 0;
-        FULL = 1;
-        WINDOW = 2;
-    }
-    optional Type type = 2;
+    // The type (level) of the wakelock; e.g. a partial wakelock or a full wakelock.
+    // From frameworks/base/core/proto/android/os/enums.proto.
+    optional android.os.WakeLockLevelEnum level = 2;
 
     // The wakelock tag (Called tag in the Java API, sometimes name elsewhere).
     optional string tag = 3;
@@ -531,15 +518,8 @@
  *   frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
  */
 message ChargingStateChanged {
-    // TODO: Link directly to BatteryManager.java's constants (via a proto).
-    enum State {
-        BATTERY_STATUS_UNKNOWN = 1;
-        BATTERY_STATUS_CHARGING = 2;
-        BATTERY_STATUS_DISCHARGING = 3;
-        BATTERY_STATUS_NOT_CHARGING = 4;
-        BATTERY_STATUS_FULL = 5;
-    }
-    optional State charging_state = 1;
+    // State of the battery, from frameworks/base/core/proto/android/os/enums.proto.
+    optional android.os.BatteryStatusEnum state = 1;
 }
 
 /**
@@ -549,18 +529,8 @@
  *   frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
  */
 message PluggedStateChanged {
-    // TODO: Link directly to BatteryManager.java's constants (via a proto).
-    enum State {
-        // Note that NONE is not in BatteryManager.java's constants.
-        BATTERY_PLUGGED_NONE = 0;
-        // Power source is an AC charger.
-        BATTERY_PLUGGED_AC = 1;
-        // Power source is a USB port.
-        BATTERY_PLUGGED_USB = 2;
-        // Power source is wireless.
-        BATTERY_PLUGGED_WIRELESS = 4;
-    }
-    optional State plugged_state = 1;
+    // Whether the device is plugged in, from frameworks/base/core/proto/android/os/enums.proto.
+    optional android.os.BatteryPluggedStateEnum state = 1;
 }
 
 /**
@@ -614,13 +584,8 @@
     // TODO: Add attribution instead of uid?
     optional int32 uid = 1;
 
-    // TODO: Reference telephony/java/android/telephony/DataConnectionRealTimeInfo.java states.
-    enum PowerState {
-        DC_POWER_STATE_LOW = 1;
-        DC_POWER_STATE_MEDIUM = 2;
-        DC_POWER_STATE_HIGH = 3;
-    }
-    optional PowerState power_state = 2;
+    // Power state, from frameworks/base/core/proto/android/telephony/enums.proto.
+    optional android.telephony.DataConnectionPowerStateEnum state = 2;
 }
 
 /**
@@ -634,13 +599,8 @@
     // TODO: Add attribution instead of uid?
     optional int32 uid = 1;
 
-    // TODO: Reference telephony/java/android/telephony/DataConnectionRealTimeInfo.java states.
-    enum PowerState {
-        DC_POWER_STATE_LOW = 1;
-        DC_POWER_STATE_MEDIUM = 2;
-        DC_POWER_STATE_HIGH = 3;
-    }
-    optional PowerState power_state = 2;
+    // Power state, from frameworks/base/core/proto/android/telephony/enums.proto.
+    optional android.telephony.DataConnectionPowerStateEnum state = 2;
 }
 
 /**
@@ -680,15 +640,8 @@
  *   frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
  */
 message WifiSignalStrengthChanged {
-    // TODO: Reference the actual telephony/java/android/telephony/SignalStrength.java states.
-    enum SignalStrength {
-        SIGNAL_STRENGTH_NONE_OR_UNKNOWN = 0;
-        SIGNAL_STRENGTH_POOR = 1;
-        SIGNAL_STRENGTH_MODERATE = 2;
-        SIGNAL_STRENGTH_GOOD = 3;
-        SIGNAL_STRENGTH_GREAT = 4;
-    }
-    optional SignalStrength signal_strength = 1;
+    // Signal strength, from frameworks/base/core/proto/android/telephony/enums.proto.
+    optional android.telephony.SignalStrengthEnum signal_strength = 1;
 }
 
 /**
@@ -730,15 +683,8 @@
  *   frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
  */
 message PhoneSignalStrengthChanged {
-    // TODO: Reference the actual telephony/java/android/telephony/SignalStrength.java states.
-    enum SignalStrength {
-        SIGNAL_STRENGTH_NONE_OR_UNKNOWN = 0;
-        SIGNAL_STRENGTH_POOR = 1;
-        SIGNAL_STRENGTH_MODERATE = 2;
-        SIGNAL_STRENGTH_GOOD = 3;
-        SIGNAL_STRENGTH_GREAT = 4;
-    }
-    optional SignalStrength signal_strength = 1;
+    // Signal strength, from frameworks/base/core/proto/android/telephony/enums.proto.
+    optional android.telephony.SignalStrengthEnum signal_strength = 1;
 }
 
 /**
diff --git a/cmds/statsd/src/storage/StorageManager.cpp b/cmds/statsd/src/storage/StorageManager.cpp
index 83b72d9..00d8658 100644
--- a/cmds/statsd/src/storage/StorageManager.cpp
+++ b/cmds/statsd/src/storage/StorageManager.cpp
@@ -63,7 +63,7 @@
 }
 
 static string getFilePath(const char* path, int64_t timestamp, int64_t uid, int64_t configID) {
-    return StringPrintf("%s/%lld-%d-%lld", path, (long long)timestamp, (int)uid,
+    return StringPrintf("%s/%lld_%d_%lld", path, (long long)timestamp, (int)uid,
                         (long long)configID);
 }
 
diff --git a/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp b/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
index eda16a2..4504a95 100644
--- a/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
@@ -123,11 +123,13 @@
     auto crashEvent10 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 2 * bucketSizeNs - 2);
 
     auto screenTurnedOnEvent =
-        CreateScreenStateChangedEvent(ScreenStateChanged::STATE_ON, bucketStartTimeNs + 2);
+        CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
+                                      bucketStartTimeNs + 2);
     auto screenTurnedOffEvent =
-        CreateScreenStateChangedEvent(ScreenStateChanged::STATE_OFF, bucketStartTimeNs + 200);
+        CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
+                                      bucketStartTimeNs + 200);
     auto screenTurnedOnEvent2 =
-        CreateScreenStateChangedEvent(ScreenStateChanged::STATE_ON,
+        CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
                                       bucketStartTimeNs + 2 * bucketSizeNs - 100);
 
     auto syncOnEvent1 =
diff --git a/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp b/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
index e656b98..1186a16 100644
--- a/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
@@ -73,11 +73,13 @@
         EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
 
         auto screenTurnedOnEvent =
-            CreateScreenStateChangedEvent(ScreenStateChanged::STATE_ON, bucketStartTimeNs + 1);
+            CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
+                                          bucketStartTimeNs + 1);
         auto screenTurnedOffEvent =
-            CreateScreenStateChangedEvent(ScreenStateChanged::STATE_OFF, bucketStartTimeNs + 200);
+            CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
+                                          bucketStartTimeNs + 200);
         auto screenTurnedOnEvent2 =
-            CreateScreenStateChangedEvent(ScreenStateChanged::STATE_ON,
+            CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
                                           bucketStartTimeNs + bucketSizeNs + 500);
 
         std::vector<AttributionNode> attributions1 =
@@ -156,7 +158,8 @@
 
         events.clear();
         events.push_back(CreateScreenStateChangedEvent(
-            ScreenStateChanged::STATE_OFF, bucketStartTimeNs + 2 * bucketSizeNs + 90));
+            android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
+            bucketStartTimeNs + 2 * bucketSizeNs + 90));
         events.push_back(CreateAcquireWakelockEvent(
             attributions1, "wl3", bucketStartTimeNs + 2 * bucketSizeNs + 100));
         events.push_back(CreateReleaseWakelockEvent(
diff --git a/cmds/statsd/tests/statsd_test_util.cpp b/cmds/statsd/tests/statsd_test_util.cpp
index 718b2e1..9f4582d 100644
--- a/cmds/statsd/tests/statsd_test_util.cpp
+++ b/cmds/statsd/tests/statsd_test_util.cpp
@@ -48,7 +48,7 @@
 }
 
 AtomMatcher CreateScreenStateChangedAtomMatcher(
-    const string& name, ScreenStateChanged::State state) {
+    const string& name, android::view::DisplayStateEnum state) {
     AtomMatcher atom_matcher;
     atom_matcher.set_id(StringToId(name));
     auto simple_atom_matcher = atom_matcher.mutable_simple_atom_matcher();
@@ -60,11 +60,13 @@
 }
 
 AtomMatcher CreateScreenTurnedOnAtomMatcher() {
-    return CreateScreenStateChangedAtomMatcher("ScreenTurnedOn", ScreenStateChanged::STATE_ON);
+    return CreateScreenStateChangedAtomMatcher("ScreenTurnedOn",
+            android::view::DisplayStateEnum::DISPLAY_STATE_ON);
 }
 
 AtomMatcher CreateScreenTurnedOffAtomMatcher() {
-    return CreateScreenStateChangedAtomMatcher("ScreenTurnedOff", ScreenStateChanged::STATE_OFF);
+    return CreateScreenStateChangedAtomMatcher("ScreenTurnedOff",
+            ::android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
 }
 
 AtomMatcher CreateSyncStateChangedAtomMatcher(
@@ -209,7 +211,7 @@
 }
 
 std::unique_ptr<LogEvent> CreateScreenStateChangedEvent(
-    const ScreenStateChanged::State state, uint64_t timestampNs) {
+    const android::view::DisplayStateEnum state, uint64_t timestampNs) {
     auto event = std::make_unique<LogEvent>(android::util::SCREEN_STATE_CHANGED, timestampNs);
     EXPECT_TRUE(event->write(state));
     event->init();
@@ -221,7 +223,7 @@
     const WakelockStateChanged::State state, uint64_t timestampNs) {
     auto event = std::make_unique<LogEvent>(android::util::WAKELOCK_STATE_CHANGED, timestampNs);
     event->write(attributions);
-    event->write(WakelockStateChanged::PARTIAL);
+    event->write(android::os::WakeLockLevelEnum::PARTIAL_WAKE_LOCK);
     event->write(wakelockName);
     event->write(state);
     event->init();
diff --git a/cmds/statsd/tests/statsd_test_util.h b/cmds/statsd/tests/statsd_test_util.h
index 1fc33de..ff8fef0c 100644
--- a/cmds/statsd/tests/statsd_test_util.h
+++ b/cmds/statsd/tests/statsd_test_util.h
@@ -84,7 +84,7 @@
 
 // Create log event for screen state changed.
 std::unique_ptr<LogEvent> CreateScreenStateChangedEvent(
-    const ScreenStateChanged::State state, uint64_t timestampNs);
+    const android::view::DisplayStateEnum state, uint64_t timestampNs);
 
 // Create log event for app moving to background.
 std::unique_ptr<LogEvent> CreateMoveToBackgroundEvent(const int uid, uint64_t timestampNs);
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/SequencePusher.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/SequencePusher.java
index d4b2aa4..5dcce9a 100644
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/SequencePusher.java
+++ b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/SequencePusher.java
@@ -90,7 +90,7 @@
             case 2:
             case 10:
                 StatsLog.write(StatsLog.CHARGING_STATE_CHANGED,
-                    StatsLog.CHARGING_STATE_CHANGED__CHARGING_STATE__BATTERY_STATUS_CHARGING
+                    StatsLog.CHARGING_STATE_CHANGED__STATE__BATTERY_STATUS_CHARGING
                     /* charging_state */);
                 break;
             case 3:
@@ -103,7 +103,7 @@
             case 4:
             case 12:
                 StatsLog.write(StatsLog.CHARGING_STATE_CHANGED,
-                    StatsLog.CHARGING_STATE_CHANGED__CHARGING_STATE__BATTERY_STATUS_NOT_CHARGING
+                    StatsLog.CHARGING_STATE_CHANGED__STATE__BATTERY_STATUS_NOT_CHARGING
                     /* charging_state */);
                 break;
             case 5:
@@ -115,7 +115,7 @@
                 break;
             case 6:
                 StatsLog.write(StatsLog.SCREEN_STATE_CHANGED,
-                    StatsLog.SCREEN_STATE_CHANGED__DISPLAY_STATE__STATE_ON /* display_state */);
+                    StatsLog.SCREEN_STATE_CHANGED__STATE__DISPLAY_STATE_ON /* display_state */);
                 break;
             case 7:
                 for (int i = 0; i < mBurst; i++) {
@@ -125,7 +125,7 @@
                 break;
             case 14:
                 StatsLog.write(StatsLog.SCREEN_STATE_CHANGED,
-                    StatsLog.SCREEN_STATE_CHANGED__DISPLAY_STATE__STATE_OFF /* display_state */);
+                    StatsLog.SCREEN_STATE_CHANGED__STATE__DISPLAY_STATE_OFF /* display_state */);
                 break;
             case 15:
                 for (int i = 0; i < mBurst; i++) {
@@ -147,14 +147,14 @@
     public void finish() {
         // Screen goes back to off. This will ensure that conditions get back to false.
         StatsLog.write(StatsLog.SCREEN_STATE_CHANGED,
-            StatsLog.SCREEN_STATE_CHANGED__DISPLAY_STATE__STATE_OFF /* display_state */);
+            StatsLog.SCREEN_STATE_CHANGED__STATE__DISPLAY_STATE_OFF /* display_state */);
         for (int i = 0; i < mBurst; i++) {
           StatsLog.write(StatsLog.AUDIO_STATE_CHANGED, i /* uid */,
               StatsLog.AUDIO_STATE_CHANGED__STATE__OFF /* state */);
         }
         // Stop charging, to ensure the corresponding durations are closed.
         StatsLog.write(StatsLog.CHARGING_STATE_CHANGED,
-            StatsLog.CHARGING_STATE_CHANGED__CHARGING_STATE__BATTERY_STATUS_NOT_CHARGING
+            StatsLog.CHARGING_STATE_CHANGED__STATE__BATTERY_STATUS_NOT_CHARGING
             /* charging_state */);
         // Stop scanning GPS, to ensure the corresponding conditions get back to false.
         for (int i = 0; i < mBurst; i++) {
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index cd029c0..b58c523 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -129,6 +129,8 @@
 import com.android.internal.policy.DecorView;
 import com.android.internal.policy.PhoneWindow;
 
+import dalvik.system.VMRuntime;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
@@ -2136,11 +2138,15 @@
      * @param params non-null parameters to be combined with previously set parameters when entering
      * picture-in-picture.
      *
-     * @return true if the system puts this activity into picture-in-picture mode or was already
-     * in picture-in-picture mode (@see {@link #isInPictureInPictureMode())
+     * @return true if the system successfully put this activity into picture-in-picture mode or was
+     * already in picture-in-picture mode (@see {@link #isInPictureInPictureMode()). If the device
+     * does not support picture-in-picture, return false.
      */
     public boolean enterPictureInPictureMode(@NonNull PictureInPictureParams params) {
         try {
+            if (!deviceSupportsPictureInPictureMode()) {
+                return false;
+            }
             if (params == null) {
                 throw new IllegalArgumentException("Expected non-null picture-in-picture params");
             }
@@ -2168,6 +2174,9 @@
      */
     public void setPictureInPictureParams(@NonNull PictureInPictureParams params) {
         try {
+            if (!deviceSupportsPictureInPictureMode()) {
+                return;
+            }
             if (params == null) {
                 throw new IllegalArgumentException("Expected non-null picture-in-picture params");
             }
@@ -2190,6 +2199,13 @@
         }
     }
 
+    /**
+     * @return Whether this device supports picture-in-picture.
+     */
+    private boolean deviceSupportsPictureInPictureMode() {
+        return getPackageManager().hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE);
+    }
+
     void dispatchMovedToDisplay(int displayId, Configuration config) {
         updateDisplay(displayId);
         onMovedToDisplay(displayId, config);
@@ -7099,11 +7115,12 @@
         mFragments.dispatchStart();
         mFragments.reportLoaderStart();
 
-        // This property is set for all builds except final release
-        boolean isDlwarningEnabled = SystemProperties.getInt("ro.bionic.ld.warning", 0) == 1;
         boolean isAppDebuggable =
                 (mApplication.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
 
+        // This property is set for all builds except final release
+        boolean isDlwarningEnabled = SystemProperties.getInt("ro.bionic.ld.warning", 0) == 1;
+
         if (isAppDebuggable || isDlwarningEnabled) {
             String dlwarning = getDlWarning();
             if (dlwarning != null) {
@@ -7124,6 +7141,28 @@
             }
         }
 
+        // We might disable this for final builds.
+        boolean isApiWarningEnabled = true;
+
+        if (isAppDebuggable || isApiWarningEnabled) {
+            if (VMRuntime.getRuntime().hasUsedHiddenApi()) {
+                String appName = getApplicationInfo().loadLabel(getPackageManager())
+                        .toString();
+                String warning = "Detected problems with API compatiblity\n"
+                                 + "(please consult log for detail)";
+                if (isAppDebuggable) {
+                    new AlertDialog.Builder(this)
+                        .setTitle(appName)
+                        .setMessage(warning)
+                        .setPositiveButton(android.R.string.ok, null)
+                        .setCancelable(false)
+                        .show();
+                } else {
+                    Toast.makeText(this, appName + "\n" + warning, Toast.LENGTH_LONG).show();
+                }
+            }
+        }
+
         mActivityTransitionState.enterReady(this);
     }
 
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 8035058..4d5ac6f 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -28,7 +28,6 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.content.UriPermission;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ConfigurationInfo;
@@ -576,18 +575,68 @@
     /** @hide Process does not exist. */
     public static final int PROCESS_STATE_NONEXISTENT = 19;
 
-    // NOTE: If PROCESS_STATEs are added or changed, then new fields must be added
-    // to frameworks/base/core/proto/android/app/activitymanager.proto and the following method must
+    // NOTE: If PROCESS_STATEs are added, then new fields must be added
+    // to frameworks/base/core/proto/android/app/enums.proto and the following method must
     // be updated to correctly map between them.
+    // However, if the current ActivityManager values are merely modified, no update should be made
+    // to enums.proto, to which values can only be added but never modified. Note that the proto
+    // versions do NOT have the ordering restrictions of the ActivityManager process state.
     /**
-     * Maps ActivityManager.PROCESS_STATE_ values to ProcessState enum.
+     * Maps ActivityManager.PROCESS_STATE_ values to enums.proto ProcessStateEnum value.
      *
      * @param amInt a process state of the form ActivityManager.PROCESS_STATE_
-     * @return the value of the corresponding ActivityManager's ProcessState enum.
+     * @return the value of the corresponding enums.proto ProcessStateEnum value.
      * @hide
      */
     public static final int processStateAmToProto(int amInt) {
-        return amInt * 100;
+        switch (amInt) {
+            case PROCESS_STATE_UNKNOWN:
+                return AppProtoEnums.PROCESS_STATE_UNKNOWN;
+            case PROCESS_STATE_PERSISTENT:
+                return AppProtoEnums.PROCESS_STATE_PERSISTENT;
+            case PROCESS_STATE_PERSISTENT_UI:
+                return AppProtoEnums.PROCESS_STATE_PERSISTENT_UI;
+            case PROCESS_STATE_TOP:
+                return AppProtoEnums.PROCESS_STATE_TOP;
+            case PROCESS_STATE_FOREGROUND_SERVICE:
+                return AppProtoEnums.PROCESS_STATE_FOREGROUND_SERVICE;
+            case PROCESS_STATE_BOUND_FOREGROUND_SERVICE:
+                return AppProtoEnums.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
+            case PROCESS_STATE_IMPORTANT_FOREGROUND:
+                return AppProtoEnums.PROCESS_STATE_IMPORTANT_FOREGROUND;
+            case PROCESS_STATE_IMPORTANT_BACKGROUND:
+                return AppProtoEnums.PROCESS_STATE_IMPORTANT_BACKGROUND;
+            case PROCESS_STATE_TRANSIENT_BACKGROUND:
+                return AppProtoEnums.PROCESS_STATE_TRANSIENT_BACKGROUND;
+            case PROCESS_STATE_BACKUP:
+                return AppProtoEnums.PROCESS_STATE_BACKUP;
+            case PROCESS_STATE_SERVICE:
+                return AppProtoEnums.PROCESS_STATE_SERVICE;
+            case PROCESS_STATE_RECEIVER:
+                return AppProtoEnums.PROCESS_STATE_RECEIVER;
+            case PROCESS_STATE_TOP_SLEEPING:
+                return AppProtoEnums.PROCESS_STATE_TOP_SLEEPING;
+            case PROCESS_STATE_HEAVY_WEIGHT:
+                return AppProtoEnums.PROCESS_STATE_HEAVY_WEIGHT;
+            case PROCESS_STATE_HOME:
+                return AppProtoEnums.PROCESS_STATE_HOME;
+            case PROCESS_STATE_LAST_ACTIVITY:
+                return AppProtoEnums.PROCESS_STATE_LAST_ACTIVITY;
+            case PROCESS_STATE_CACHED_ACTIVITY:
+                return AppProtoEnums.PROCESS_STATE_CACHED_ACTIVITY;
+            case PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
+                return AppProtoEnums.PROCESS_STATE_CACHED_ACTIVITY_CLIENT;
+            case PROCESS_STATE_CACHED_RECENT:
+                return AppProtoEnums.PROCESS_STATE_CACHED_RECENT;
+            case PROCESS_STATE_CACHED_EMPTY:
+                return AppProtoEnums.PROCESS_STATE_CACHED_EMPTY;
+            case PROCESS_STATE_NONEXISTENT:
+                return AppProtoEnums.PROCESS_STATE_NONEXISTENT;
+            default:
+                // ActivityManager process state (amInt)
+                // could not be mapped to an AppProtoEnums ProcessState state.
+                return AppProtoEnums.PROCESS_STATE_UNKNOWN_TO_PROTO;
+        }
     }
 
     /** @hide The lowest process state number */
@@ -2686,17 +2735,22 @@
     /**
      * Permits an application to get the persistent URI permissions granted to another.
      *
-     * <p>Typically called by Settings.
+     * <p>Typically called by Settings or DocumentsUI, requires
+     * {@code GET_APP_GRANTED_URI_PERMISSIONS}.
      *
-     * @param packageName application to look for the granted permissions
+     * @param packageName application to look for the granted permissions, or {@code null} to get
+     * granted permissions for all applications
      * @return list of granted URI permissions
      *
      * @hide
      */
-    public ParceledListSlice<UriPermission> getGrantedUriPermissions(String packageName) {
+    public ParceledListSlice<GrantedUriPermission> getGrantedUriPermissions(
+            @Nullable String packageName) {
         try {
-            return getService().getGrantedUriPermissions(packageName,
-                    UserHandle.myUserId());
+            @SuppressWarnings("unchecked")
+            final ParceledListSlice<GrantedUriPermission> castedList = getService()
+                    .getGrantedUriPermissions(packageName, UserHandle.myUserId());
+            return castedList;
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -2705,7 +2759,7 @@
     /**
      * Permits an application to clear the persistent URI permissions granted to another.
      *
-     * <p>Typically called by Settings.
+     * <p>Typically called by Settings, requires {@code CLEAR_APP_GRANTED_URI_PERMISSIONS}.
      *
      * @param packageName application to clear its granted permissions
      *
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 4bcd677..fee5827 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -207,6 +207,12 @@
             "android.activity.taskOverlayCanResume";
 
     /**
+     * See {@link #setAvoidMoveToFront()}.
+     * @hide
+     */
+    private static final String KEY_AVOID_MOVE_TO_FRONT = "android.activity.avoidMoveToFront";
+
+    /**
      * Where the split-screen-primary stack should be positioned.
      * @hide
      */
@@ -307,6 +313,7 @@
     private boolean mDisallowEnterPictureInPictureWhileLaunching;
     private boolean mTaskOverlay;
     private boolean mTaskOverlayCanResume;
+    private boolean mAvoidMoveToFront;
     private AppTransitionAnimationSpec mAnimSpecs[];
     private int mRotationAnimationHint = -1;
     private Bundle mAppVerificationBundle;
@@ -923,6 +930,7 @@
         mLaunchTaskId = opts.getInt(KEY_LAUNCH_TASK_ID, -1);
         mTaskOverlay = opts.getBoolean(KEY_TASK_OVERLAY, false);
         mTaskOverlayCanResume = opts.getBoolean(KEY_TASK_OVERLAY_CAN_RESUME, false);
+        mAvoidMoveToFront = opts.getBoolean(KEY_AVOID_MOVE_TO_FRONT, false);
         mSplitScreenCreateMode = opts.getInt(KEY_SPLIT_SCREEN_CREATE_MODE,
                 SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT);
         mDisallowEnterPictureInPictureWhileLaunching = opts.getBoolean(
@@ -1239,6 +1247,25 @@
         return mTaskOverlayCanResume;
     }
 
+    /**
+     * Sets whether the activity launched should not cause the activity stack it is contained in to
+     * be moved to the front as a part of launching.
+     *
+     * @hide
+     */
+    public void setAvoidMoveToFront() {
+        mAvoidMoveToFront = true;
+    }
+
+    /**
+     * @return whether the activity launch should prevent moving the associated activity stack to
+     *         the front.
+     * @hide
+     */
+    public boolean getAvoidMoveToFront() {
+        return mAvoidMoveToFront;
+    }
+
     /** @hide */
     public int getSplitScreenCreateMode() {
         return mSplitScreenCreateMode;
@@ -1416,6 +1443,7 @@
         b.putInt(KEY_LAUNCH_TASK_ID, mLaunchTaskId);
         b.putBoolean(KEY_TASK_OVERLAY, mTaskOverlay);
         b.putBoolean(KEY_TASK_OVERLAY_CAN_RESUME, mTaskOverlayCanResume);
+        b.putBoolean(KEY_AVOID_MOVE_TO_FRONT, mAvoidMoveToFront);
         b.putInt(KEY_SPLIT_SCREEN_CREATE_MODE, mSplitScreenCreateMode);
         b.putBoolean(KEY_DISALLOW_ENTER_PICTURE_IN_PICTURE_WHILE_LAUNCHING,
                 mDisallowEnterPictureInPictureWhileLaunching);
diff --git a/core/proto/android/os/batterymanager.proto b/core/java/android/app/GrantedUriPermission.aidl
similarity index 64%
rename from core/proto/android/os/batterymanager.proto
rename to core/java/android/app/GrantedUriPermission.aidl
index 669bf2d..2734af0 100644
--- a/core/proto/android/os/batterymanager.proto
+++ b/core/java/android/app/GrantedUriPermission.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * 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.
@@ -14,16 +14,7 @@
  * limitations under the License.
  */
 
-syntax = "proto2";
-package android.os;
+package android.app;
 
-option java_multiple_files = true;
-
-message BatteryManagerProto {
-    enum PlugType {
-        PLUG_TYPE_NONE = 0;
-        PLUG_TYPE_AC = 1;
-        PLUG_TYPE_USB = 2;
-        PLUG_TYPE_WIRELESS = 4;
-    }
-}
+/** @hide */
+parcelable GrantedUriPermission;
\ No newline at end of file
diff --git a/core/java/android/app/GrantedUriPermission.java b/core/java/android/app/GrantedUriPermission.java
new file mode 100644
index 0000000..9e84fe1
--- /dev/null
+++ b/core/java/android/app/GrantedUriPermission.java
@@ -0,0 +1,74 @@
+/*
+ * 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.app;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.UriPermission;
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Represents an {@link UriPermission} granted to a package.
+ *
+ * {@hide}
+ */
+public class GrantedUriPermission implements Parcelable {
+
+    public final Uri uri;
+    public final String packageName;
+
+    public GrantedUriPermission(@NonNull Uri uri, @Nullable String packageName) {
+        this.uri = uri;
+        this.packageName = packageName;
+    }
+
+    @Override
+    public String toString() {
+        return packageName + ":" + uri;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeParcelable(uri, flags);
+        out.writeString(packageName);
+    }
+
+    public static final Parcelable.Creator<GrantedUriPermission> CREATOR =
+            new Parcelable.Creator<GrantedUriPermission>() {
+                @Override
+                public GrantedUriPermission createFromParcel(Parcel in) {
+                    return new GrantedUriPermission(in);
+                }
+
+                @Override
+                public GrantedUriPermission[] newArray(int size) {
+                    return new GrantedUriPermission[size];
+                }
+            };
+
+    private GrantedUriPermission(Parcel in) {
+        uri = in.readParcelable(null);
+        packageName = in.readString();
+    }
+}
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 9c15562..6dcecf1 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -19,6 +19,7 @@
 import android.app.ActivityManager;
 import android.app.ApplicationErrorReport;
 import android.app.ContentProviderHolder;
+import android.app.GrantedUriPermission;
 import android.app.IApplicationThread;
 import android.app.IActivityController;
 import android.app.IAppTask;
@@ -65,6 +66,7 @@
 import android.os.StrictMode;
 import android.os.WorkSource;
 import android.service.voice.IVoiceInteractionSession;
+import android.view.IRecentsAnimationRunner;
 import android.view.RemoteAnimationDefinition;
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.os.IResultReceiver;
@@ -145,6 +147,7 @@
     void publishService(in IBinder token, in Intent intent, in IBinder service);
     void activityResumed(in IBinder token);
     void setDebugApp(in String packageName, boolean waitForDebugger, boolean persistent);
+    void setAgentApp(in String packageName, @nullable String agent);
     void setAlwaysFinish(boolean enabled);
     boolean startInstrumentation(in ComponentName className, in String profileFile,
             int flags, in Bundle arguments, in IInstrumentationWatcher watcher,
@@ -441,8 +444,9 @@
             in Bundle options, int userId);
     int startAssistantActivity(in String callingPackage, int callingPid, int callingUid,
             in Intent intent, in String resolvedType, in Bundle options, int userId);
-    int startRecentsActivity(in IAssistDataReceiver assistDataReceiver, in Bundle options,
-            in Bundle activityOptions, int userId);
+    void startRecentsActivity(in Intent intent, in IAssistDataReceiver assistDataReceiver,
+            in IRecentsAnimationRunner recentsAnimationRunner);
+    void cancelRecentsAnimation();
     int startActivityFromRecents(int taskId, in Bundle options);
     Bundle getActivityOptions(in IBinder token);
     List<IBinder> getAppTasks(in String callingPackage);
@@ -569,7 +573,7 @@
             in Rect tempDockedTaskInsetBounds,
             in Rect tempOtherTaskBounds, in Rect tempOtherTaskInsetBounds);
     int setVrMode(in IBinder token, boolean enabled, in ComponentName packageName);
-    // Gets the URI permissions granted to an arbitrary package.
+    // Gets the URI permissions granted to an arbitrary package (or all packages if null)
     // NOTE: this is different from getPersistedUriPermissions(), which returns the URIs the package
     // granted to another packages (instead of those granted to it).
     ParceledListSlice getGrantedUriPermissions(in String packageName, int userId);
diff --git a/core/java/android/app/LocalActivityManager.java b/core/java/android/app/LocalActivityManager.java
index 998ac5f..c34f4d9 100644
--- a/core/java/android/app/LocalActivityManager.java
+++ b/core/java/android/app/LocalActivityManager.java
@@ -16,6 +16,8 @@
 
 package android.app;
 
+import android.app.ActivityThread.ActivityClientRecord;
+import android.app.servertransaction.PendingTransactionActions;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.os.Binder;
@@ -141,6 +143,21 @@
             }
             r.window = r.activity.getWindow();
             r.instanceState = null;
+
+            final ActivityClientRecord clientRecord = mActivityThread.getActivityClient(r);
+            final PendingTransactionActions pendingActions;
+
+            if (!r.activity.mFinished) {
+                // This matches pending actions set in ActivityThread#handleLaunchActivity
+                pendingActions = new PendingTransactionActions();
+                pendingActions.setOldState(clientRecord.state);
+                pendingActions.setRestoreInstanceState(true);
+                pendingActions.setCallOnPostCreate(true);
+            } else {
+                pendingActions = null;
+            }
+
+            mActivityThread.handleStartActivity(clientRecord, pendingActions);
             r.curState = STARTED;
             
             if (desiredState == RESUMED) {
diff --git a/core/java/android/app/ProfilerInfo.java b/core/java/android/app/ProfilerInfo.java
index 0ed1b08..6fbe9c6 100644
--- a/core/java/android/app/ProfilerInfo.java
+++ b/core/java/android/app/ProfilerInfo.java
@@ -87,6 +87,15 @@
     }
 
     /**
+     * Return a new ProfilerInfo instance, with fields populated from this object,
+     * and {@link agent} and {@link attachAgentDuringBind} as given.
+     */
+    public ProfilerInfo setAgent(String agent, boolean attachAgentDuringBind) {
+        return new ProfilerInfo(this.profileFile, this.profileFd, this.samplingInterval,
+                this.autoStopProfiler, this.streamingOutput, agent, attachAgentDuringBind);
+    }
+
+    /**
      * Close profileFd, if it is open. The field will be null after a call to this function.
      */
     public void closeFd() {
diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java
index ea0fd75..256c479 100644
--- a/core/java/android/app/Service.java
+++ b/core/java/android/app/Service.java
@@ -471,6 +471,14 @@
      * {@link #onStart} and returns either {@link #START_STICKY}
      * or {@link #START_STICKY_COMPATIBILITY}.
      * 
+     * <p>If you need your application to run on platform versions prior to API
+     * level 5, you can use the following model to handle the older {@link #onStart}
+     * callback in that case.  The <code>handleCommand</code> method is implemented by
+     * you as appropriate:
+     * 
+     * {@sample development/samples/ApiDemos/src/com/example/android/apis/app/ForegroundService.java
+     *   start_compatibility}
+     *
      * <p class="caution">Note that the system calls this on your
      * service's main thread.  A service's main thread is the same
      * thread where UI operations take place for Activities running in the
@@ -679,10 +687,6 @@
      * {@link #startService(Intent)} first to tell the system it should keep the service running,
      * and then use this method to tell it to keep it running harder.</p>
      *
-     * <p>Apps targeting API {@link android.os.Build.VERSION_CODES#P} or later must request
-     * the permission {@link android.Manifest.permission#FOREGROUND_SERVICE} in order to use
-     * this API.</p>
-     *
      * @param id The identifier for this notification as per
      * {@link NotificationManager#notify(int, Notification)
      * NotificationManager.notify(int, Notification)}; must not be 0.
diff --git a/core/java/android/content/AbstractThreadedSyncAdapter.java b/core/java/android/content/AbstractThreadedSyncAdapter.java
index 2629929..5a1216b7 100644
--- a/core/java/android/content/AbstractThreadedSyncAdapter.java
+++ b/core/java/android/content/AbstractThreadedSyncAdapter.java
@@ -21,6 +21,7 @@
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.Process;
+import android.os.RemoteException;
 import android.os.Trace;
 import android.util.Log;
 
@@ -166,6 +167,12 @@
 
     private class ISyncAdapterImpl extends ISyncAdapter.Stub {
         @Override
+        public void onUnsyncableAccount(ISyncAdapterUnsyncableAccountCallback cb)
+                throws RemoteException {
+            cb.onUnsyncableAccountDone(AbstractThreadedSyncAdapter.this.onUnsyncableAccount());
+        }
+
+        @Override
         public void startSync(ISyncContext syncContext, String authority, Account account,
                 Bundle extras) {
             if (ENABLE_LOG) {
@@ -374,6 +381,26 @@
     }
 
     /**
+     * Allows to defer syncing until all accounts are properly set up.
+     *
+     * <p>Called when a account / authority pair
+     * <ul>
+     * <li>that can be handled by this adapter</li>
+     * <li>{@link ContentResolver#requestSync(SyncRequest) is synced}</li>
+     * <li>and the account/provider {@link ContentResolver#getIsSyncable(Account, String) has
+     * unknown state (<0)}.</li>
+     * </ul>
+     *
+     * <p>This might be called on a different service connection as {@link #onPerformSync}.
+     *
+     * @return If {@code false} syncing is deferred. Returns {@code true} by default, i.e. by
+     *         default syncing starts immediately.
+     */
+    public boolean onUnsyncableAccount() {
+        return true;
+    }
+
+    /**
      * Perform a sync for this account. SyncAdapter-specific parameters may
      * be specified in extras, which is guaranteed to not be null. Invocations
      * of this method are guaranteed to be serialized.
diff --git a/core/java/android/content/ISyncAdapter.aidl b/core/java/android/content/ISyncAdapter.aidl
index 4660527..0eb581e 100644
--- a/core/java/android/content/ISyncAdapter.aidl
+++ b/core/java/android/content/ISyncAdapter.aidl
@@ -19,6 +19,7 @@
 import android.accounts.Account;
 import android.os.Bundle;
 import android.content.ISyncContext;
+import android.content.ISyncAdapterUnsyncableAccountCallback;
 
 /**
  * Interface used to control the sync activity on a SyncAdapter
@@ -26,6 +27,14 @@
  */
 oneway interface ISyncAdapter {
     /**
+     * Called before {@link #startSync}. This allows the adapter to defer syncs until the
+     * adapter is ready for the account
+     *
+     * @param cb If called back with {@code false} accounts are not synced.
+     */
+    void onUnsyncableAccount(ISyncAdapterUnsyncableAccountCallback cb);
+
+    /**
      * Initiate a sync for this account. SyncAdapter-specific parameters may
      * be specified in extras, which is guaranteed to not be null.
      *
diff --git a/core/java/android/content/ISyncAdapterUnsyncableAccountCallback.aidl b/core/java/android/content/ISyncAdapterUnsyncableAccountCallback.aidl
new file mode 100644
index 0000000..a738ac2
--- /dev/null
+++ b/core/java/android/content/ISyncAdapterUnsyncableAccountCallback.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content;
+
+/**
+ * Callback for {@link ISyncAdapter#onUnsyncableAccount}
+ * @hide
+ */
+oneway interface ISyncAdapterUnsyncableAccountCallback {
+    /**
+     * Deliver the result for {@link ISyncAdapter#onUnsyncableAccount}
+     *
+     * @param isReady Iff {@code false} account is not synced.
+     */
+    void onUnsyncableAccountDone(boolean isReady);
+}
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 746a090..f6697e8 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -602,6 +602,13 @@
      */
     public static final int PRIVATE_FLAG_VENDOR = 1 << 18;
 
+    /**
+     * Value for {@linl #privateFlags}: whether this app is pre-installed on the
+     * product partition of the system image.
+     * @hide
+     */
+    public static final int PRIVATE_FLAG_PRODUCT = 1 << 19;
+
     /** @hide */
     @IntDef(flag = true, prefix = { "PRIVATE_FLAG_" }, value = {
             PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE,
@@ -619,6 +626,7 @@
             PRIVATE_FLAG_OEM,
             PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE,
             PRIVATE_FLAG_PRIVILEGED,
+            PRIVATE_FLAG_PRODUCT,
             PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER,
             PRIVATE_FLAG_STATIC_SHARED_LIBRARY,
             PRIVATE_FLAG_VENDOR,
@@ -1699,6 +1707,11 @@
         return (privateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0;
     }
 
+    /** @hide */
+    public boolean isProduct() {
+        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0;
+    }
+
     /**
      * Returns whether or not this application was installed as a virtual preload.
      */
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 3bb812b..3d26af1 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -54,7 +54,6 @@
 import android.content.pm.split.DefaultSplitAssetLoader;
 import android.content.pm.split.SplitAssetDependencyLoader;
 import android.content.pm.split.SplitAssetLoader;
-import android.content.res.ApkAssets;
 import android.content.res.AssetManager;
 import android.content.res.Configuration;
 import android.content.res.Resources;
@@ -1595,19 +1594,21 @@
             int flags) throws PackageParserException {
         final String apkPath = fd != null ? debugPathName : apkFile.getAbsolutePath();
 
-        ApkAssets apkAssets = null;
+        AssetManager assets = null;
         XmlResourceParser parser = null;
         try {
-            try {
-                apkAssets = fd != null
-                        ? ApkAssets.loadFromFd(fd, debugPathName, false, false)
-                        : ApkAssets.loadFromPath(apkPath);
-            } catch (IOException e) {
+            assets = newConfiguredAssetManager();
+            int cookie = fd != null
+                    ? assets.addAssetFd(fd, debugPathName) : assets.addAssetPath(apkPath);
+            if (cookie == 0) {
                 throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
                         "Failed to parse " + apkPath);
             }
 
-            parser = apkAssets.openXml(ANDROID_MANIFEST_FILENAME);
+            final DisplayMetrics metrics = new DisplayMetrics();
+            metrics.setToDefaults();
+
+            parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
 
             final SigningDetails signingDetails;
             if ((flags & PARSE_COLLECT_CERTIFICATES) != 0) {
@@ -1634,7 +1635,7 @@
                     "Failed to parse " + apkPath, e);
         } finally {
             IoUtils.closeQuietly(parser);
-            IoUtils.closeQuietly(apkAssets);
+            IoUtils.closeQuietly(assets);
         }
     }
 
@@ -6393,6 +6394,11 @@
         }
 
         /** @hide */
+        public boolean isProduct() {
+            return applicationInfo.isProduct();
+        }
+
+        /** @hide */
         public boolean isPrivileged() {
             return applicationInfo.isPrivilegedApp();
         }
diff --git a/core/java/android/content/res/ApkAssets.java b/core/java/android/content/res/ApkAssets.java
deleted file mode 100644
index b087c48..0000000
--- a/core/java/android/content/res/ApkAssets.java
+++ /dev/null
@@ -1,221 +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.content.res;
-
-import android.annotation.NonNull;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.Preconditions;
-
-import java.io.FileDescriptor;
-import java.io.IOException;
-
-/**
- * The loaded, immutable, in-memory representation of an APK.
- *
- * The main implementation is native C++ and there is very little API surface exposed here. The APK
- * is mainly accessed via {@link AssetManager}.
- *
- * Since the ApkAssets instance is immutable, it can be reused and shared across AssetManagers,
- * making the creation of AssetManagers very cheap.
- * @hide
- */
-public final class ApkAssets implements AutoCloseable {
-    @GuardedBy("this") private long mNativePtr;
-    @GuardedBy("this") private StringBlock mStringBlock;
-
-    /**
-     * Creates a new ApkAssets instance from the given path on disk.
-     *
-     * @param path The path to an APK on disk.
-     * @return a new instance of ApkAssets.
-     * @throws IOException if a disk I/O error or parsing error occurred.
-     */
-    public static @NonNull ApkAssets loadFromPath(@NonNull String path) throws IOException {
-        return new ApkAssets(path, false /*system*/, false /*forceSharedLib*/, false /*overlay*/);
-    }
-
-    /**
-     * Creates a new ApkAssets instance from the given path on disk.
-     *
-     * @param path The path to an APK on disk.
-     * @param system When true, the APK is loaded as a system APK (framework).
-     * @return a new instance of ApkAssets.
-     * @throws IOException if a disk I/O error or parsing error occurred.
-     */
-    public static @NonNull ApkAssets loadFromPath(@NonNull String path, boolean system)
-            throws IOException {
-        return new ApkAssets(path, system, false /*forceSharedLib*/, false /*overlay*/);
-    }
-
-    /**
-     * Creates a new ApkAssets instance from the given path on disk.
-     *
-     * @param path The path to an APK on disk.
-     * @param system When true, the APK is loaded as a system APK (framework).
-     * @param forceSharedLibrary When true, any packages within the APK with package ID 0x7f are
-     *                           loaded as a shared library.
-     * @return a new instance of ApkAssets.
-     * @throws IOException if a disk I/O error or parsing error occurred.
-     */
-    public static @NonNull ApkAssets loadFromPath(@NonNull String path, boolean system,
-            boolean forceSharedLibrary) throws IOException {
-        return new ApkAssets(path, system, forceSharedLibrary, false /*overlay*/);
-    }
-
-    /**
-     * Creates a new ApkAssets instance from the given file descriptor. Not for use by applications.
-     *
-     * Performs a dup of the underlying fd, so you must take care of still closing
-     * the FileDescriptor yourself (and can do that whenever you want).
-     *
-     * @param fd The FileDescriptor of an open, readable APK.
-     * @param friendlyName The friendly name used to identify this ApkAssets when logging.
-     * @param system When true, the APK is loaded as a system APK (framework).
-     * @param forceSharedLibrary When true, any packages within the APK with package ID 0x7f are
-     *                           loaded as a shared library.
-     * @return a new instance of ApkAssets.
-     * @throws IOException if a disk I/O error or parsing error occurred.
-     */
-    public static @NonNull ApkAssets loadFromFd(@NonNull FileDescriptor fd,
-            @NonNull String friendlyName, boolean system, boolean forceSharedLibrary)
-            throws IOException {
-        return new ApkAssets(fd, friendlyName, system, forceSharedLibrary);
-    }
-
-    /**
-     * Creates a new ApkAssets instance from the IDMAP at idmapPath. The overlay APK path
-     * is encoded within the IDMAP.
-     *
-     * @param idmapPath Path to the IDMAP of an overlay APK.
-     * @param system When true, the APK is loaded as a system APK (framework).
-     * @return a new instance of ApkAssets.
-     * @throws IOException if a disk I/O error or parsing error occurred.
-     */
-    public static @NonNull ApkAssets loadOverlayFromPath(@NonNull String idmapPath, boolean system)
-            throws IOException {
-        return new ApkAssets(idmapPath, system, false /*forceSharedLibrary*/, true /*overlay*/);
-    }
-
-    private ApkAssets(@NonNull String path, boolean system, boolean forceSharedLib, boolean overlay)
-            throws IOException {
-        Preconditions.checkNotNull(path, "path");
-        mNativePtr = nativeLoad(path, system, forceSharedLib, overlay);
-        mStringBlock = new StringBlock(nativeGetStringBlock(mNativePtr), true /*useSparse*/);
-    }
-
-    private ApkAssets(@NonNull FileDescriptor fd, @NonNull String friendlyName, boolean system,
-            boolean forceSharedLib) throws IOException {
-        Preconditions.checkNotNull(fd, "fd");
-        Preconditions.checkNotNull(friendlyName, "friendlyName");
-        mNativePtr = nativeLoadFromFd(fd, friendlyName, system, forceSharedLib);
-        mStringBlock = new StringBlock(nativeGetStringBlock(mNativePtr), true /*useSparse*/);
-    }
-
-    @NonNull String getAssetPath() {
-        synchronized (this) {
-            ensureValidLocked();
-            return nativeGetAssetPath(mNativePtr);
-        }
-    }
-
-    CharSequence getStringFromPool(int idx) {
-        synchronized (this) {
-            ensureValidLocked();
-            return mStringBlock.get(idx);
-        }
-    }
-
-    /**
-     * Retrieve a parser for a compiled XML file. This is associated with a single APK and
-     * <em>NOT</em> a full AssetManager. This means that shared-library references will not be
-     * dynamically assigned runtime package IDs.
-     *
-     * @param fileName The path to the file within the APK.
-     * @return An XmlResourceParser.
-     * @throws IOException if the file was not found or an error occurred retrieving it.
-     */
-    public @NonNull XmlResourceParser openXml(@NonNull String fileName) throws IOException {
-        Preconditions.checkNotNull(fileName, "fileName");
-        synchronized (this) {
-            ensureValidLocked();
-            long nativeXmlPtr = nativeOpenXml(mNativePtr, fileName);
-            try (XmlBlock block = new XmlBlock(null, nativeXmlPtr)) {
-                XmlResourceParser parser = block.newParser();
-                // If nativeOpenXml doesn't throw, it will always return a valid native pointer,
-                // which makes newParser always return non-null. But let's be paranoid.
-                if (parser == null) {
-                    throw new AssertionError("block.newParser() returned a null parser");
-                }
-                return parser;
-            }
-        }
-    }
-
-    /**
-     * Returns false if the underlying APK was changed since this ApkAssets was loaded.
-     */
-    public boolean isUpToDate() {
-        synchronized (this) {
-            ensureValidLocked();
-            return nativeIsUpToDate(mNativePtr);
-        }
-    }
-
-    /**
-     * Closes the ApkAssets and destroys the underlying native implementation. Further use of the
-     * ApkAssets object will cause exceptions to be thrown.
-     *
-     * Calling close on an already closed ApkAssets does nothing.
-     */
-    @Override
-    public void close() {
-        synchronized (this) {
-            if (mNativePtr == 0) {
-                return;
-            }
-
-            mStringBlock = null;
-            nativeDestroy(mNativePtr);
-            mNativePtr = 0;
-        }
-    }
-
-    @Override
-    protected void finalize() throws Throwable {
-        if (mNativePtr != 0) {
-            nativeDestroy(mNativePtr);
-        }
-    }
-
-    private void ensureValidLocked() {
-        if (mNativePtr == 0) {
-            throw new RuntimeException("ApkAssets is closed");
-        }
-    }
-
-    private static native long nativeLoad(
-            @NonNull String path, boolean system, boolean forceSharedLib, boolean overlay)
-            throws IOException;
-    private static native long nativeLoadFromFd(@NonNull FileDescriptor fd,
-            @NonNull String friendlyName, boolean system, boolean forceSharedLib)
-            throws IOException;
-    private static native void nativeDestroy(long ptr);
-    private static native @NonNull String nativeGetAssetPath(long ptr);
-    private static native long nativeGetStringBlock(long ptr);
-    private static native boolean nativeIsUpToDate(long ptr);
-    private static native long nativeOpenXml(long ptr, @NonNull String fileName) throws IOException;
-}
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index 78370f4..7866560 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -18,11 +18,9 @@
 
 import android.annotation.AnyRes;
 import android.annotation.ArrayRes;
-import android.annotation.AttrRes;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.StringRes;
-import android.annotation.StyleRes;
 import android.content.pm.ActivityInfo;
 import android.content.res.Configuration.NativeConfig;
 import android.os.ParcelFileDescriptor;
@@ -30,18 +28,10 @@
 import android.util.SparseArray;
 import android.util.TypedValue;
 
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.Preconditions;
-
-import java.io.BufferedReader;
-import java.io.FileInputStream;
+import java.io.FileDescriptor;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.nio.channels.FileLock;
-import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.HashMap;
 
 /**
@@ -52,17 +42,7 @@
  * bytes.
  */
 public final class AssetManager implements AutoCloseable {
-    private static final String TAG = "AssetManager";
-    private static final boolean DEBUG_REFS = false;
-
-    private static final String FRAMEWORK_APK_PATH = "/system/framework/framework-res.apk";
-
-    private static final Object sSync = new Object();
-
-    // Not private for LayoutLib's BridgeAssetManager.
-    @GuardedBy("sSync") static AssetManager sSystem = null;
-
-    @GuardedBy("sSync") private static ApkAssets[] sSystemApkAssets = new ApkAssets[0];
+    /* modes used when opening an asset */
 
     /**
      * Mode for {@link #open(String, int)}: no specific information about how
@@ -85,279 +65,87 @@
      */
     public static final int ACCESS_BUFFER = 3;
 
-    @GuardedBy("this") private final TypedValue mValue = new TypedValue();
-    @GuardedBy("this") private final long[] mOffsets = new long[2];
+    private static final String TAG = "AssetManager";
+    private static final boolean localLOGV = false || false;
+    
+    private static final boolean DEBUG_REFS = false;
+    
+    private static final Object sSync = new Object();
+    /*package*/ static AssetManager sSystem = null;
 
-    // Pointer to native implementation, stuffed inside a long.
-    @GuardedBy("this") private long mObject;
+    private final TypedValue mValue = new TypedValue();
+    private final long[] mOffsets = new long[2];
+    
+    // For communication with native code.
+    private long mObject;
 
-    // The loaded asset paths.
-    @GuardedBy("this") private ApkAssets[] mApkAssets;
-
-    // Debug/reference counting implementation.
-    @GuardedBy("this") private boolean mOpen = true;
-    @GuardedBy("this") private int mNumRefs = 1;
-    @GuardedBy("this") private HashMap<Long, RuntimeException> mRefStacks;
-
+    private StringBlock mStringBlocks[] = null;
+    
+    private int mNumRefs = 1;
+    private boolean mOpen = true;
+    private HashMap<Long, RuntimeException> mRefStacks;
+ 
     /**
      * Create a new AssetManager containing only the basic system assets.
      * Applications will not generally use this method, instead retrieving the
      * appropriate asset manager with {@link Resources#getAssets}.    Not for
      * use by applications.
-     * @hide
+     * {@hide}
      */
     public AssetManager() {
-        final ApkAssets[] assets;
-        synchronized (sSync) {
-            createSystemAssetsInZygoteLocked();
-            assets = sSystemApkAssets;
-        }
-
-        mObject = nativeCreate();
-        if (DEBUG_REFS) {
-            mNumRefs = 0;
-            incRefsLocked(hashCode());
-        }
-
-        // Always set the framework resources.
-        setApkAssets(assets, false /*invalidateCaches*/);
-    }
-
-    /**
-     * Private constructor that doesn't call ensureSystemAssets.
-     * Used for the creation of system assets.
-     */
-    @SuppressWarnings("unused")
-    private AssetManager(boolean sentinel) {
-        mObject = nativeCreate();
-        if (DEBUG_REFS) {
-            mNumRefs = 0;
-            incRefsLocked(hashCode());
-        }
-    }
-
-    /**
-     * This must be called from Zygote so that system assets are shared by all applications.
-     * @hide
-     */
-    private static void createSystemAssetsInZygoteLocked() {
-        if (sSystem != null) {
-            return;
-        }
-
-        // Make sure that all IDMAPs are up to date.
-        nativeVerifySystemIdmaps();
-
-        try {
-            ArrayList<ApkAssets> apkAssets = new ArrayList<>();
-            apkAssets.add(ApkAssets.loadFromPath(FRAMEWORK_APK_PATH, true /*system*/));
-
-            // Load all static RROs.
-            try (FileInputStream fis = new FileInputStream(
-                    "/data/resource-cache/overlays.list");
-                 BufferedReader br = new BufferedReader(new InputStreamReader(fis))) {
-                // Acquire a lock so that any idmap scanning doesn't impact the current set.
-                try (FileLock flock = fis.getChannel().lock(0, Long.MAX_VALUE,
-                        true /*shared*/)) {
-                    for (String line; (line = br.readLine()) != null; ) {
-                        String idmapPath = line.split(" ")[1];
-                        apkAssets.add(
-                                ApkAssets.loadOverlayFromPath(idmapPath, true /*system*/));
-                    }
-                }
+        synchronized (this) {
+            if (DEBUG_REFS) {
+                mNumRefs = 0;
+                incRefsLocked(this.hashCode());
             }
-
-            sSystemApkAssets = apkAssets.toArray(new ApkAssets[apkAssets.size()]);
-            sSystem = new AssetManager(true /*sentinel*/);
-            sSystem.setApkAssets(sSystemApkAssets, false /*invalidateCaches*/);
-        } catch (IOException e) {
-            throw new IllegalStateException("Failed to create system AssetManager", e);
+            init(false);
+            if (localLOGV) Log.v(TAG, "New asset manager: " + this);
+            ensureSystemAssets();
         }
     }
 
+    private static void ensureSystemAssets() {
+        synchronized (sSync) {
+            if (sSystem == null) {
+                AssetManager system = new AssetManager(true);
+                system.makeStringBlocks(null);
+                sSystem = system;
+            }
+        }
+    }
+    
+    private AssetManager(boolean isSystem) {
+        if (DEBUG_REFS) {
+            synchronized (this) {
+                mNumRefs = 0;
+                incRefsLocked(this.hashCode());
+            }
+        }
+        init(true);
+        if (localLOGV) Log.v(TAG, "New asset manager: " + this);
+    }
+
     /**
      * Return a global shared asset manager that provides access to only
      * system assets (no application assets).
-     * @hide
+     * {@hide}
      */
     public static AssetManager getSystem() {
-        synchronized (sSync) {
-            createSystemAssetsInZygoteLocked();
-            return sSystem;
-        }
+        ensureSystemAssets();
+        return sSystem;
     }
 
     /**
      * Close this asset manager.
      */
-    @Override
     public void close() {
-        synchronized (this) {
-            if (!mOpen) {
-                return;
+        synchronized(this) {
+            //System.out.println("Release: num=" + mNumRefs
+            //                   + ", released=" + mReleased);
+            if (mOpen) {
+                mOpen = false;
+                decRefsLocked(this.hashCode());
             }
-
-            mOpen = false;
-            decRefsLocked(hashCode());
-        }
-    }
-
-    /**
-     * Changes the asset paths in this AssetManager. This replaces the {@link #addAssetPath(String)}
-     * family of methods.
-     *
-     * @param apkAssets The new set of paths.
-     * @param invalidateCaches Whether to invalidate any caches. This should almost always be true.
-     *                         Set this to false if you are appending new resources
-     *                         (not new configurations).
-     * @hide
-     */
-    public void setApkAssets(@NonNull ApkAssets[] apkAssets, boolean invalidateCaches) {
-        Preconditions.checkNotNull(apkAssets, "apkAssets");
-        synchronized (this) {
-            ensureValidLocked();
-            mApkAssets = apkAssets;
-            nativeSetApkAssets(mObject, apkAssets, invalidateCaches);
-            if (invalidateCaches) {
-                // Invalidate all caches.
-                invalidateCachesLocked(-1);
-            }
-        }
-    }
-
-    /**
-     * Invalidates the caches in this AssetManager according to the bitmask `diff`.
-     *
-     * @param diff The bitmask of changes generated by {@link Configuration#diff(Configuration)}.
-     * @see ActivityInfo.Config
-     */
-    private void invalidateCachesLocked(int diff) {
-        // TODO(adamlesinski): Currently there are no caches to invalidate in Java code.
-    }
-
-    /**
-     * @hide
-     */
-    public @NonNull ApkAssets[] getApkAssets() {
-        synchronized (this) {
-            ensureValidLocked();
-            return mApkAssets;
-        }
-    }
-
-    /**
-     * @deprecated Use {@link #setApkAssets(ApkAssets[], boolean)}
-     * @hide
-     */
-    @Deprecated
-    public int addAssetPath(String path) {
-        return addAssetPathInternal(path, false /*overlay*/, false /*appAsLib*/);
-    }
-
-    /**
-     * @deprecated Use {@link #setApkAssets(ApkAssets[], boolean)}
-     * @hide
-     */
-    @Deprecated
-    public int addAssetPathAsSharedLibrary(String path) {
-        return addAssetPathInternal(path, false /*overlay*/, true /*appAsLib*/);
-    }
-
-    /**
-     * @deprecated Use {@link #setApkAssets(ApkAssets[], boolean)}
-     * @hide
-     */
-    @Deprecated
-    public int addOverlayPath(String path) {
-        return addAssetPathInternal(path, true /*overlay*/, false /*appAsLib*/);
-    }
-
-    private int addAssetPathInternal(String path, boolean overlay, boolean appAsLib) {
-        Preconditions.checkNotNull(path, "path");
-        synchronized (this) {
-            ensureOpenLocked();
-            final int count = mApkAssets.length;
-            for (int i = 0; i < count; i++) {
-                if (mApkAssets[i].getAssetPath().equals(path)) {
-                    return i + 1;
-                }
-            }
-
-            final ApkAssets assets;
-            try {
-                if (overlay) {
-                    // TODO(b/70343104): This hardcoded path will be removed once
-                    // addAssetPathInternal is deleted.
-                    final String idmapPath = "/data/resource-cache/"
-                            + path.substring(1).replace('/', '@')
-                            + "@idmap";
-                    assets = ApkAssets.loadOverlayFromPath(idmapPath, false /*system*/);
-                } else {
-                    assets = ApkAssets.loadFromPath(path, false /*system*/, appAsLib);
-                }
-            } catch (IOException e) {
-                return 0;
-            }
-
-            final ApkAssets[] newApkAssets = Arrays.copyOf(mApkAssets, count + 1);
-            newApkAssets[count] = assets;
-            setApkAssets(newApkAssets, true);
-            return count + 1;
-        }
-    }
-
-    /**
-     * Ensures that the native implementation has not been destroyed.
-     * The AssetManager may have been closed, but references to it still exist
-     * and therefore the native implementation is not destroyed.
-     */
-    private void ensureValidLocked() {
-        if (mObject == 0) {
-            throw new RuntimeException("AssetManager has been destroyed");
-        }
-    }
-
-    /**
-     * Ensures that the AssetManager has not been explicitly closed. If this method passes,
-     * then this implies that ensureValidLocked() also passes.
-     */
-    private void ensureOpenLocked() {
-        if (!mOpen) {
-            throw new RuntimeException("AssetManager has been closed");
-        }
-    }
-
-    /**
-     * Populates {@code outValue} with the data associated a particular
-     * resource identifier for the current configuration.
-     *
-     * @param resId the resource identifier to load
-     * @param densityDpi the density bucket for which to load the resource
-     * @param outValue the typed value in which to put the data
-     * @param resolveRefs {@code true} to resolve references, {@code false}
-     *                    to leave them unresolved
-     * @return {@code true} if the data was loaded into {@code outValue},
-     *         {@code false} otherwise
-     */
-    boolean getResourceValue(@AnyRes int resId, int densityDpi, @NonNull TypedValue outValue,
-            boolean resolveRefs) {
-        Preconditions.checkNotNull(outValue, "outValue");
-        synchronized (this) {
-            ensureValidLocked();
-            final int cookie = nativeGetResourceValue(
-                    mObject, resId, (short) densityDpi, outValue, resolveRefs);
-            if (cookie <= 0) {
-                return false;
-            }
-
-            // Convert the changing configurations flags populated by native code.
-            outValue.changingConfigurations = ActivityInfo.activityInfoConfigNativeToJava(
-                    outValue.changingConfigurations);
-
-            if (outValue.type == TypedValue.TYPE_STRING) {
-                outValue.string = mApkAssets[cookie - 1].getStringFromPool(outValue.data);
-            }
-            return true;
         }
     }
 
@@ -368,7 +156,8 @@
      * @param resId the resource identifier to load
      * @return the string value, or {@code null}
      */
-    @Nullable CharSequence getResourceText(@StringRes int resId) {
+    @Nullable
+    final CharSequence getResourceText(@StringRes int resId) {
         synchronized (this) {
             final TypedValue outValue = mValue;
             if (getResourceValue(resId, 0, outValue, true)) {
@@ -383,15 +172,15 @@
      * identifier for the current configuration.
      *
      * @param resId the resource identifier to load
-     * @param bagEntryId the index into the bag to load
+     * @param bagEntryId
      * @return the string value, or {@code null}
      */
-    @Nullable CharSequence getResourceBagText(@StringRes int resId, int bagEntryId) {
+    @Nullable
+    final CharSequence getResourceBagText(@StringRes int resId, int bagEntryId) {
         synchronized (this) {
-            ensureValidLocked();
             final TypedValue outValue = mValue;
-            final int cookie = nativeGetResourceBagValue(mObject, resId, bagEntryId, outValue);
-            if (cookie <= 0) {
+            final int block = loadResourceBagValue(resId, bagEntryId, outValue, true);
+            if (block < 0) {
                 return null;
             }
 
@@ -400,49 +189,12 @@
                     outValue.changingConfigurations);
 
             if (outValue.type == TypedValue.TYPE_STRING) {
-                return mApkAssets[cookie - 1].getStringFromPool(outValue.data);
+                return mStringBlocks[block].get(outValue.data);
             }
             return outValue.coerceToString();
         }
     }
 
-    int getResourceArraySize(@ArrayRes int resId) {
-        synchronized (this) {
-            ensureValidLocked();
-            return nativeGetResourceArraySize(mObject, resId);
-        }
-    }
-
-    /**
-     * Populates `outData` with array elements of `resId`. `outData` is normally
-     * used with
-     * {@link TypedArray}.
-     *
-     * Each logical element in `outData` is {@link TypedArray#STYLE_NUM_ENTRIES}
-     * long,
-     * with the indices of the data representing the type, value, asset cookie,
-     * resource ID,
-     * configuration change mask, and density of the element.
-     *
-     * @param resId The resource ID of an array resource.
-     * @param outData The array to populate with data.
-     * @return The length of the array.
-     *
-     * @see TypedArray#STYLE_TYPE
-     * @see TypedArray#STYLE_DATA
-     * @see TypedArray#STYLE_ASSET_COOKIE
-     * @see TypedArray#STYLE_RESOURCE_ID
-     * @see TypedArray#STYLE_CHANGING_CONFIGURATIONS
-     * @see TypedArray#STYLE_DENSITY
-     */
-    int getResourceArray(@ArrayRes int resId, @NonNull int[] outData) {
-        Preconditions.checkNotNull(outData, "outData");
-        synchronized (this) {
-            ensureValidLocked();
-            return nativeGetResourceArray(mObject, resId, outData);
-        }
-    }
-
     /**
      * Retrieves the string array associated with a particular resource
      * identifier for the current configuration.
@@ -450,10 +202,39 @@
      * @param resId the resource identifier of the string array
      * @return the string array, or {@code null}
      */
-    @Nullable String[] getResourceStringArray(@ArrayRes int resId) {
+    @Nullable
+    final String[] getResourceStringArray(@ArrayRes int resId) {
+        return getArrayStringResource(resId);
+    }
+
+    /**
+     * Populates {@code outValue} with the data associated a particular
+     * resource identifier for the current configuration.
+     *
+     * @param resId the resource identifier to load
+     * @param densityDpi the density bucket for which to load the resource
+     * @param outValue the typed value in which to put the data
+     * @param resolveRefs {@code true} to resolve references, {@code false}
+     *                    to leave them unresolved
+     * @return {@code true} if the data was loaded into {@code outValue},
+     *         {@code false} otherwise
+     */
+    final boolean getResourceValue(@AnyRes int resId, int densityDpi, @NonNull TypedValue outValue,
+            boolean resolveRefs) {
         synchronized (this) {
-            ensureValidLocked();
-            return nativeGetResourceStringArray(mObject, resId);
+            final int block = loadResourceValue(resId, (short) densityDpi, outValue, resolveRefs);
+            if (block < 0) {
+                return false;
+            }
+
+            // Convert the changing configurations flags populated by native code.
+            outValue.changingConfigurations = ActivityInfo.activityInfoConfigNativeToJava(
+                    outValue.changingConfigurations);
+
+            if (outValue.type == TypedValue.TYPE_STRING) {
+                outValue.string = mStringBlocks[block].get(outValue.data);
+            }
+            return true;
         }
     }
 
@@ -463,48 +244,26 @@
      *
      * @param resId the resource id of the string array
      */
-    @Nullable CharSequence[] getResourceTextArray(@ArrayRes int resId) {
+    final @Nullable CharSequence[] getResourceTextArray(@ArrayRes int resId) {
         synchronized (this) {
-            ensureValidLocked();
-            final int[] rawInfoArray = nativeGetResourceStringArrayInfo(mObject, resId);
+            final int[] rawInfoArray = getArrayStringInfo(resId);
             if (rawInfoArray == null) {
                 return null;
             }
-
             final int rawInfoArrayLen = rawInfoArray.length;
             final int infoArrayLen = rawInfoArrayLen / 2;
+            int block;
+            int index;
             final CharSequence[] retArray = new CharSequence[infoArrayLen];
             for (int i = 0, j = 0; i < rawInfoArrayLen; i = i + 2, j++) {
-                int cookie = rawInfoArray[i];
-                int index = rawInfoArray[i + 1];
-                retArray[j] = (index >= 0 && cookie > 0)
-                        ? mApkAssets[cookie - 1].getStringFromPool(index) : null;
+                block = rawInfoArray[i];
+                index = rawInfoArray[i + 1];
+                retArray[j] = index >= 0 ? mStringBlocks[block].get(index) : null;
             }
             return retArray;
         }
     }
 
-    @Nullable int[] getResourceIntArray(@ArrayRes int resId) {
-        synchronized (this) {
-            ensureValidLocked();
-            return nativeGetResourceIntArray(mObject, resId);
-        }
-    }
-
-    /**
-     * Get the attributes for a style resource. These are the &lt;item&gt;
-     * elements in
-     * a &lt;style&gt; resource.
-     * @param resId The resource ID of the style
-     * @return An array of attribute IDs.
-     */
-    @AttrRes int[] getStyleAttributes(@StyleRes int resId) {
-        synchronized (this) {
-            ensureValidLocked();
-            return nativeGetStyleAttributes(mObject, resId);
-        }
-    }
-
     /**
      * Populates {@code outValue} with the data associated with a particular
      * resource identifier for the current configuration. Resolves theme
@@ -518,88 +277,73 @@
      * @return {@code true} if the data was loaded into {@code outValue},
      *         {@code false} otherwise
      */
-    boolean getThemeValue(long theme, @AnyRes int resId, @NonNull TypedValue outValue,
+    final boolean getThemeValue(long theme, @AnyRes int resId, @NonNull TypedValue outValue,
             boolean resolveRefs) {
-        Preconditions.checkNotNull(outValue, "outValue");
+        final int block = loadThemeAttributeValue(theme, resId, outValue, resolveRefs);
+        if (block < 0) {
+            return false;
+        }
+
+        // Convert the changing configurations flags populated by native code.
+        outValue.changingConfigurations = ActivityInfo.activityInfoConfigNativeToJava(
+                outValue.changingConfigurations);
+
+        if (outValue.type == TypedValue.TYPE_STRING) {
+            final StringBlock[] blocks = ensureStringBlocks();
+            outValue.string = blocks[block].get(outValue.data);
+        }
+        return true;
+    }
+
+    /**
+     * Ensures the string blocks are loaded.
+     *
+     * @return the string blocks
+     */
+    @NonNull
+    final StringBlock[] ensureStringBlocks() {
         synchronized (this) {
-            ensureValidLocked();
-            final int cookie = nativeThemeGetAttributeValue(mObject, theme, resId, outValue,
-                    resolveRefs);
-            if (cookie <= 0) {
-                return false;
+            if (mStringBlocks == null) {
+                makeStringBlocks(sSystem.mStringBlocks);
             }
+            return mStringBlocks;
+        }
+    }
 
-            // Convert the changing configurations flags populated by native code.
-            outValue.changingConfigurations = ActivityInfo.activityInfoConfigNativeToJava(
-                    outValue.changingConfigurations);
-
-            if (outValue.type == TypedValue.TYPE_STRING) {
-                outValue.string = mApkAssets[cookie - 1].getStringFromPool(outValue.data);
+    /*package*/ final void makeStringBlocks(StringBlock[] seed) {
+        final int seedNum = (seed != null) ? seed.length : 0;
+        final int num = getStringBlockCount();
+        mStringBlocks = new StringBlock[num];
+        if (localLOGV) Log.v(TAG, "Making string blocks for " + this
+                + ": " + num);
+        for (int i=0; i<num; i++) {
+            if (i < seedNum) {
+                mStringBlocks[i] = seed[i];
+            } else {
+                mStringBlocks[i] = new StringBlock(getNativeStringBlock(i), true);
             }
-            return true;
         }
     }
 
-    void dumpTheme(long theme, int priority, String tag, String prefix) {
+    /*package*/ final CharSequence getPooledStringForCookie(int cookie, int id) {
         synchronized (this) {
-            ensureValidLocked();
-            nativeThemeDump(mObject, theme, priority, tag, prefix);
+            // Cookies map to string blocks starting at 1.
+            return mStringBlocks[cookie - 1].get(id);
         }
     }
 
-    @Nullable String getResourceName(@AnyRes int resId) {
-        synchronized (this) {
-            ensureValidLocked();
-            return nativeGetResourceName(mObject, resId);
-        }
-    }
-
-    @Nullable String getResourcePackageName(@AnyRes int resId) {
-        synchronized (this) {
-            ensureValidLocked();
-            return nativeGetResourcePackageName(mObject, resId);
-        }
-    }
-
-    @Nullable String getResourceTypeName(@AnyRes int resId) {
-        synchronized (this) {
-            ensureValidLocked();
-            return nativeGetResourceTypeName(mObject, resId);
-        }
-    }
-
-    @Nullable String getResourceEntryName(@AnyRes int resId) {
-        synchronized (this) {
-            ensureValidLocked();
-            return nativeGetResourceEntryName(mObject, resId);
-        }
-    }
-
-    @AnyRes int getResourceIdentifier(@NonNull String name, @Nullable String defType,
-            @Nullable String defPackage) {
-        synchronized (this) {
-            ensureValidLocked();
-            // name is checked in JNI.
-            return nativeGetResourceIdentifier(mObject, name, defType, defPackage);
-        }
-    }
-
-    CharSequence getPooledStringForCookie(int cookie, int id) {
-        // Cookies map to ApkAssets starting at 1.
-        return getApkAssets()[cookie - 1].getStringFromPool(id);
-    }
-
     /**
      * Open an asset using ACCESS_STREAMING mode.  This provides access to
      * files that have been bundled with an application as assets -- that is,
      * files placed in to the "assets" directory.
      * 
-     * @param fileName The name of the asset to open.  This name can be hierarchical.
+     * @param fileName The name of the asset to open.  This name can be
+     *                 hierarchical.
      * 
      * @see #open(String, int)
      * @see #list
      */
-    public @NonNull InputStream open(@NonNull String fileName) throws IOException {
+    public final InputStream open(String fileName) throws IOException {
         return open(fileName, ACCESS_STREAMING);
     }
 
@@ -609,7 +353,8 @@
      * with an application as assets -- that is, files placed in to the
      * "assets" directory.
      * 
-     * @param fileName The name of the asset to open.  This name can be hierarchical.
+     * @param fileName The name of the asset to open.  This name can be
+     *                 hierarchical.
      * @param accessMode Desired access mode for retrieving the data.
      * 
      * @see #ACCESS_UNKNOWN
@@ -619,40 +364,34 @@
      * @see #open(String)
      * @see #list
      */
-    public @NonNull InputStream open(@NonNull String fileName, int accessMode) throws IOException {
-        Preconditions.checkNotNull(fileName, "fileName");
+    public final InputStream open(String fileName, int accessMode)
+        throws IOException {
         synchronized (this) {
-            ensureOpenLocked();
-            final long asset = nativeOpenAsset(mObject, fileName, accessMode);
-            if (asset == 0) {
-                throw new FileNotFoundException("Asset file: " + fileName);
+            if (!mOpen) {
+                throw new RuntimeException("Assetmanager has been closed");
             }
-            final AssetInputStream assetInputStream = new AssetInputStream(asset);
-            incRefsLocked(assetInputStream.hashCode());
-            return assetInputStream;
+            long asset = openAsset(fileName, accessMode);
+            if (asset != 0) {
+                AssetInputStream res = new AssetInputStream(asset);
+                incRefsLocked(res.hashCode());
+                return res;
+            }
         }
+        throw new FileNotFoundException("Asset file: " + fileName);
     }
 
-    /**
-     * Open an uncompressed asset by mmapping it and returning an {@link AssetFileDescriptor}.
-     * This provides access to files that have been bundled with an application as assets -- that
-     * is, files placed in to the "assets" directory.
-     *
-     * The asset must be uncompressed, or an exception will be thrown.
-     *
-     * @param fileName The name of the asset to open.  This name can be hierarchical.
-     * @return An open AssetFileDescriptor.
-     */
-    public @NonNull AssetFileDescriptor openFd(@NonNull String fileName) throws IOException {
-        Preconditions.checkNotNull(fileName, "fileName");
+    public final AssetFileDescriptor openFd(String fileName)
+            throws IOException {
         synchronized (this) {
-            ensureOpenLocked();
-            final ParcelFileDescriptor pfd = nativeOpenAssetFd(mObject, fileName, mOffsets);
-            if (pfd == null) {
-                throw new FileNotFoundException("Asset file: " + fileName);
+            if (!mOpen) {
+                throw new RuntimeException("Assetmanager has been closed");
             }
-            return new AssetFileDescriptor(pfd, mOffsets[0], mOffsets[1]);
+            ParcelFileDescriptor pfd = openAssetFd(fileName, mOffsets);
+            if (pfd != null) {
+                return new AssetFileDescriptor(pfd, mOffsets[0], mOffsets[1]);
+            }
         }
+        throw new FileNotFoundException("Asset file: " + fileName);
     }
 
     /**
@@ -667,121 +406,90 @@
      * 
      * @see #open
      */
-    public @Nullable String[] list(@NonNull String path) throws IOException {
-        Preconditions.checkNotNull(path, "path");
-        synchronized (this) {
-            ensureValidLocked();
-            return nativeList(mObject, path);
-        }
-    }
+    public native final String[] list(String path)
+        throws IOException;
 
     /**
+     * {@hide}
      * Open a non-asset file as an asset using ACCESS_STREAMING mode.  This
      * provides direct access to all of the files included in an application
      * package (not only its assets).  Applications should not normally use
      * this.
-     *
-     * @param fileName Name of the asset to retrieve.
-     *
+     * 
      * @see #open(String)
-     * @hide
      */
-    public @NonNull InputStream openNonAsset(@NonNull String fileName) throws IOException {
+    public final InputStream openNonAsset(String fileName) throws IOException {
         return openNonAsset(0, fileName, ACCESS_STREAMING);
     }
 
     /**
+     * {@hide}
      * Open a non-asset file as an asset using a specific access mode.  This
      * provides direct access to all of the files included in an application
      * package (not only its assets).  Applications should not normally use
      * this.
-     *
-     * @param fileName Name of the asset to retrieve.
-     * @param accessMode Desired access mode for retrieving the data.
-     *
-     * @see #ACCESS_UNKNOWN
-     * @see #ACCESS_STREAMING
-     * @see #ACCESS_RANDOM
-     * @see #ACCESS_BUFFER
+     * 
      * @see #open(String, int)
-     * @hide
      */
-    public @NonNull InputStream openNonAsset(@NonNull String fileName, int accessMode)
-            throws IOException {
+    public final InputStream openNonAsset(String fileName, int accessMode)
+        throws IOException {
         return openNonAsset(0, fileName, accessMode);
     }
 
     /**
+     * {@hide}
      * Open a non-asset in a specified package.  Not for use by applications.
-     *
+     * 
      * @param cookie Identifier of the package to be opened.
      * @param fileName Name of the asset to retrieve.
-     * @hide
      */
-    public @NonNull InputStream openNonAsset(int cookie, @NonNull String fileName)
-            throws IOException {
+    public final InputStream openNonAsset(int cookie, String fileName)
+        throws IOException {
         return openNonAsset(cookie, fileName, ACCESS_STREAMING);
     }
 
     /**
+     * {@hide}
      * Open a non-asset in a specified package.  Not for use by applications.
-     *
+     * 
      * @param cookie Identifier of the package to be opened.
      * @param fileName Name of the asset to retrieve.
      * @param accessMode Desired access mode for retrieving the data.
-     * @hide
      */
-    public @NonNull InputStream openNonAsset(int cookie, @NonNull String fileName, int accessMode)
-            throws IOException {
-        Preconditions.checkNotNull(fileName, "fileName");
+    public final InputStream openNonAsset(int cookie, String fileName, int accessMode)
+        throws IOException {
         synchronized (this) {
-            ensureOpenLocked();
-            final long asset = nativeOpenNonAsset(mObject, cookie, fileName, accessMode);
-            if (asset == 0) {
-                throw new FileNotFoundException("Asset absolute file: " + fileName);
+            if (!mOpen) {
+                throw new RuntimeException("Assetmanager has been closed");
             }
-            final AssetInputStream assetInputStream = new AssetInputStream(asset);
-            incRefsLocked(assetInputStream.hashCode());
-            return assetInputStream;
+            long asset = openNonAssetNative(cookie, fileName, accessMode);
+            if (asset != 0) {
+                AssetInputStream res = new AssetInputStream(asset);
+                incRefsLocked(res.hashCode());
+                return res;
+            }
         }
+        throw new FileNotFoundException("Asset absolute file: " + fileName);
     }
 
-    /**
-     * Open a non-asset as an asset by mmapping it and returning an {@link AssetFileDescriptor}.
-     * This provides direct access to all of the files included in an application
-     * package (not only its assets).  Applications should not normally use this.
-     *
-     * The asset must not be compressed, or an exception will be thrown.
-     *
-     * @param fileName Name of the asset to retrieve.
-     */
-    public @NonNull AssetFileDescriptor openNonAssetFd(@NonNull String fileName)
+    public final AssetFileDescriptor openNonAssetFd(String fileName)
             throws IOException {
         return openNonAssetFd(0, fileName);
     }
-
-    /**
-     * Open a non-asset as an asset by mmapping it and returning an {@link AssetFileDescriptor}.
-     * This provides direct access to all of the files included in an application
-     * package (not only its assets).  Applications should not normally use this.
-     *
-     * The asset must not be compressed, or an exception will be thrown.
-     *
-     * @param cookie Identifier of the package to be opened.
-     * @param fileName Name of the asset to retrieve.
-     */
-    public @NonNull AssetFileDescriptor openNonAssetFd(int cookie, @NonNull String fileName)
-            throws IOException {
-        Preconditions.checkNotNull(fileName, "fileName");
+    
+    public final AssetFileDescriptor openNonAssetFd(int cookie,
+            String fileName) throws IOException {
         synchronized (this) {
-            ensureOpenLocked();
-            final ParcelFileDescriptor pfd =
-                    nativeOpenNonAssetFd(mObject, cookie, fileName, mOffsets);
-            if (pfd == null) {
-                throw new FileNotFoundException("Asset absolute file: " + fileName);
+            if (!mOpen) {
+                throw new RuntimeException("Assetmanager has been closed");
             }
-            return new AssetFileDescriptor(pfd, mOffsets[0], mOffsets[1]);
+            ParcelFileDescriptor pfd = openNonAssetFdNative(cookie,
+                    fileName, mOffsets);
+            if (pfd != null) {
+                return new AssetFileDescriptor(pfd, mOffsets[0], mOffsets[1]);
+            }
         }
+        throw new FileNotFoundException("Asset absolute file: " + fileName);
     }
     
     /**
@@ -789,7 +497,7 @@
      * 
      * @param fileName The name of the file to retrieve.
      */
-    public @NonNull XmlResourceParser openXmlResourceParser(@NonNull String fileName)
+    public final XmlResourceParser openXmlResourceParser(String fileName)
             throws IOException {
         return openXmlResourceParser(0, fileName);
     }
@@ -800,265 +508,270 @@
      * @param cookie Identifier of the package to be opened.
      * @param fileName The name of the file to retrieve.
      */
-    public @NonNull XmlResourceParser openXmlResourceParser(int cookie, @NonNull String fileName)
-            throws IOException {
-        try (XmlBlock block = openXmlBlockAsset(cookie, fileName)) {
-            XmlResourceParser parser = block.newParser();
-            // If openXmlBlockAsset doesn't throw, it will always return an XmlBlock object with
-            // a valid native pointer, which makes newParser always return non-null. But let's
-            // be paranoid.
-            if (parser == null) {
-                throw new AssertionError("block.newParser() returned a null parser");
-            }
-            return parser;
-        }
+    public final XmlResourceParser openXmlResourceParser(int cookie,
+            String fileName) throws IOException {
+        XmlBlock block = openXmlBlockAsset(cookie, fileName);
+        XmlResourceParser rp = block.newParser();
+        block.close();
+        return rp;
     }
 
     /**
-     * Retrieve a non-asset as a compiled XML file.  Not for use by applications.
+     * {@hide}
+     * Retrieve a non-asset as a compiled XML file.  Not for use by
+     * applications.
      * 
      * @param fileName The name of the file to retrieve.
-     * @hide
      */
-    @NonNull XmlBlock openXmlBlockAsset(@NonNull String fileName) throws IOException {
+    /*package*/ final XmlBlock openXmlBlockAsset(String fileName)
+            throws IOException {
         return openXmlBlockAsset(0, fileName);
     }
 
     /**
+     * {@hide}
      * Retrieve a non-asset as a compiled XML file.  Not for use by
      * applications.
      * 
      * @param cookie Identifier of the package to be opened.
      * @param fileName Name of the asset to retrieve.
-     * @hide
      */
-    @NonNull XmlBlock openXmlBlockAsset(int cookie, @NonNull String fileName) throws IOException {
-        Preconditions.checkNotNull(fileName, "fileName");
+    /*package*/ final XmlBlock openXmlBlockAsset(int cookie, String fileName)
+        throws IOException {
         synchronized (this) {
-            ensureOpenLocked();
-            final long xmlBlock = nativeOpenXmlAsset(mObject, cookie, fileName);
-            if (xmlBlock == 0) {
-                throw new FileNotFoundException("Asset XML file: " + fileName);
+            if (!mOpen) {
+                throw new RuntimeException("Assetmanager has been closed");
             }
-            final XmlBlock block = new XmlBlock(this, xmlBlock);
-            incRefsLocked(block.hashCode());
-            return block;
+            long xmlBlock = openXmlAssetNative(cookie, fileName);
+            if (xmlBlock != 0) {
+                XmlBlock res = new XmlBlock(this, xmlBlock);
+                incRefsLocked(res.hashCode());
+                return res;
+            }
         }
+        throw new FileNotFoundException("Asset XML file: " + fileName);
     }
 
-    void xmlBlockGone(int id) {
+    /*package*/ void xmlBlockGone(int id) {
         synchronized (this) {
             decRefsLocked(id);
         }
     }
 
-    void applyStyle(long themePtr, @AttrRes int defStyleAttr, @StyleRes int defStyleRes,
-            @Nullable XmlBlock.Parser parser, @NonNull int[] inAttrs, long outValuesAddress,
-            long outIndicesAddress) {
-        Preconditions.checkNotNull(inAttrs, "inAttrs");
+    /*package*/ final long createTheme() {
         synchronized (this) {
-            // Need to synchronize on AssetManager because we will be accessing
-            // the native implementation of AssetManager.
-            ensureValidLocked();
-            nativeApplyStyle(mObject, themePtr, defStyleAttr, defStyleRes,
-                    parser != null ? parser.mParseState : 0, inAttrs, outValuesAddress,
-                    outIndicesAddress);
+            if (!mOpen) {
+                throw new RuntimeException("Assetmanager has been closed");
+            }
+            long res = newTheme();
+            incRefsLocked(res);
+            return res;
         }
     }
 
-    boolean resolveAttrs(long themePtr, @AttrRes int defStyleAttr, @StyleRes int defStyleRes,
-            @Nullable int[] inValues, @NonNull int[] inAttrs, @NonNull int[] outValues,
-            @NonNull int[] outIndices) {
-        Preconditions.checkNotNull(inAttrs, "inAttrs");
-        Preconditions.checkNotNull(outValues, "outValues");
-        Preconditions.checkNotNull(outIndices, "outIndices");
+    /*package*/ final void releaseTheme(long theme) {
         synchronized (this) {
-            // Need to synchronize on AssetManager because we will be accessing
-            // the native implementation of AssetManager.
-            ensureValidLocked();
-            return nativeResolveAttrs(mObject,
-                    themePtr, defStyleAttr, defStyleRes, inValues, inAttrs, outValues, outIndices);
+            deleteTheme(theme);
+            decRefsLocked(theme);
         }
     }
 
-    boolean retrieveAttributes(@NonNull XmlBlock.Parser parser, @NonNull int[] inAttrs,
-            @NonNull int[] outValues, @NonNull int[] outIndices) {
-        Preconditions.checkNotNull(parser, "parser");
-        Preconditions.checkNotNull(inAttrs, "inAttrs");
-        Preconditions.checkNotNull(outValues, "outValues");
-        Preconditions.checkNotNull(outIndices, "outIndices");
-        synchronized (this) {
-            // Need to synchronize on AssetManager because we will be accessing
-            // the native implementation of AssetManager.
-            ensureValidLocked();
-            return nativeRetrieveAttributes(
-                    mObject, parser.mParseState, inAttrs, outValues, outIndices);
-        }
-    }
-
-    long createTheme() {
-        synchronized (this) {
-            ensureValidLocked();
-            long themePtr = nativeThemeCreate(mObject);
-            incRefsLocked(themePtr);
-            return themePtr;
-        }
-    }
-
-    void releaseTheme(long themePtr) {
-        synchronized (this) {
-            nativeThemeDestroy(themePtr);
-            decRefsLocked(themePtr);
-        }
-    }
-
-    void applyStyleToTheme(long themePtr, @StyleRes int resId, boolean force) {
-        synchronized (this) {
-            // Need to synchronize on AssetManager because we will be accessing
-            // the native implementation of AssetManager.
-            ensureValidLocked();
-            nativeThemeApplyStyle(mObject, themePtr, resId, force);
-        }
-    }
-
-    @Override
     protected void finalize() throws Throwable {
-        if (DEBUG_REFS && mNumRefs != 0) {
-            Log.w(TAG, "AssetManager " + this + " finalized with non-zero refs: " + mNumRefs);
-            if (mRefStacks != null) {
-                for (RuntimeException e : mRefStacks.values()) {
-                    Log.w(TAG, "Reference from here", e);
+        try {
+            if (DEBUG_REFS && mNumRefs != 0) {
+                Log.w(TAG, "AssetManager " + this
+                        + " finalized with non-zero refs: " + mNumRefs);
+                if (mRefStacks != null) {
+                    for (RuntimeException e : mRefStacks.values()) {
+                        Log.w(TAG, "Reference from here", e);
+                    }
                 }
             }
-        }
-
-        if (mObject != 0) {
-            nativeDestroy(mObject);
+            destroy();
+        } finally {
+            super.finalize();
         }
     }
-
-    /* No Locking is needed for AssetInputStream because an AssetInputStream is not-thread
-    safe and it does not rely on AssetManager once it has been created. It completely owns the
-    underlying Asset. */
+    
     public final class AssetInputStream extends InputStream {
-        private long mAssetNativePtr;
-        private long mLength;
-        private long mMarkPos;
-
         /**
          * @hide
          */
         public final int getAssetInt() {
             throw new UnsupportedOperationException();
         }
-
         /**
          * @hide
          */
         public final long getNativeAsset() {
-            return mAssetNativePtr;
+            return mAsset;
         }
-
-        private AssetInputStream(long assetNativePtr) {
-            mAssetNativePtr = assetNativePtr;
-            mLength = nativeAssetGetLength(assetNativePtr);
+        private AssetInputStream(long asset)
+        {
+            mAsset = asset;
+            mLength = getAssetLength(asset);
         }
-
-        @Override
         public final int read() throws IOException {
-            ensureOpen();
-            return nativeAssetReadChar(mAssetNativePtr);
+            return readAssetChar(mAsset);
         }
-
-        @Override
-        public final int read(@NonNull byte[] b) throws IOException {
-            ensureOpen();
-            Preconditions.checkNotNull(b, "b");
-            return nativeAssetRead(mAssetNativePtr, b, 0, b.length);
-        }
-
-        @Override
-        public final int read(@NonNull byte[] b, int off, int len) throws IOException {
-            ensureOpen();
-            Preconditions.checkNotNull(b, "b");
-            return nativeAssetRead(mAssetNativePtr, b, off, len);
-        }
-
-        @Override
-        public final long skip(long n) throws IOException {
-            ensureOpen();
-            long pos = nativeAssetSeek(mAssetNativePtr, 0, 0);
-            if ((pos + n) > mLength) {
-                n = mLength - pos;
-            }
-            if (n > 0) {
-                nativeAssetSeek(mAssetNativePtr, n, 0);
-            }
-            return n;
-        }
-
-        @Override
-        public final int available() throws IOException {
-            ensureOpen();
-            final long len = nativeAssetGetRemainingLength(mAssetNativePtr);
-            return len > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) len;
-        }
-
-        @Override
         public final boolean markSupported() {
             return true;
         }
-
-        @Override
-        public final void mark(int readlimit) {
-            ensureOpen();
-            mMarkPos = nativeAssetSeek(mAssetNativePtr, 0, 0);
+        public final int available() throws IOException {
+            long len = getAssetRemainingLength(mAsset);
+            return len > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int)len;
         }
-
-        @Override
-        public final void reset() throws IOException {
-            ensureOpen();
-            nativeAssetSeek(mAssetNativePtr, mMarkPos, -1);
-        }
-
-        @Override
         public final void close() throws IOException {
-            if (mAssetNativePtr != 0) {
-                nativeAssetDestroy(mAssetNativePtr);
-                mAssetNativePtr = 0;
-
-                synchronized (AssetManager.this) {
+            synchronized (AssetManager.this) {
+                if (mAsset != 0) {
+                    destroyAsset(mAsset);
+                    mAsset = 0;
                     decRefsLocked(hashCode());
                 }
             }
         }
+        public final void mark(int readlimit) {
+            mMarkPos = seekAsset(mAsset, 0, 0);
+        }
+        public final void reset() throws IOException {
+            seekAsset(mAsset, mMarkPos, -1);
+        }
+        public final int read(byte[] b) throws IOException {
+            return readAsset(mAsset, b, 0, b.length);
+        }
+        public final int read(byte[] b, int off, int len) throws IOException {
+            return readAsset(mAsset, b, off, len);
+        }
+        public final long skip(long n) throws IOException {
+            long pos = seekAsset(mAsset, 0, 0);
+            if ((pos+n) > mLength) {
+                n = mLength-pos;
+            }
+            if (n > 0) {
+                seekAsset(mAsset, n, 0);
+            }
+            return n;
+        }
 
-        @Override
-        protected void finalize() throws Throwable {
+        protected void finalize() throws Throwable
+        {
             close();
         }
 
-        private void ensureOpen() {
-            if (mAssetNativePtr == 0) {
-                throw new IllegalStateException("AssetInputStream is closed");
-            }
+        private long mAsset;
+        private long mLength;
+        private long mMarkPos;
+    }
+
+    /**
+     * Add an additional set of assets to the asset manager.  This can be
+     * either a directory or ZIP file.  Not for use by applications.  Returns
+     * the cookie of the added asset, or 0 on failure.
+     * {@hide}
+     */
+    public final int addAssetPath(String path) {
+        return  addAssetPathInternal(path, false);
+    }
+
+    /**
+     * Add an application assets to the asset manager and loading it as shared library.
+     * This can be either a directory or ZIP file.  Not for use by applications.  Returns
+     * the cookie of the added asset, or 0 on failure.
+     * {@hide}
+     */
+    public final int addAssetPathAsSharedLibrary(String path) {
+        return addAssetPathInternal(path, true);
+    }
+
+    private final int addAssetPathInternal(String path, boolean appAsLib) {
+        synchronized (this) {
+            int res = addAssetPathNative(path, appAsLib);
+            makeStringBlocks(mStringBlocks);
+            return res;
         }
     }
 
+    private native final int addAssetPathNative(String path, boolean appAsLib);
+
+    /**
+     * Add an additional set of assets to the asset manager from an already open
+     * FileDescriptor.  Not for use by applications.
+     * This does not give full AssetManager functionality for these assets,
+     * since the origin of the file is not known for purposes of sharing,
+     * overlay resolution, and other features.  However it does allow you
+     * to do simple access to the contents of the given fd as an apk file.
+     * Performs a dup of the underlying fd, so you must take care of still closing
+     * the FileDescriptor yourself (and can do that whenever you want).
+     * Returns the cookie of the added asset, or 0 on failure.
+     * {@hide}
+     */
+    public int addAssetFd(FileDescriptor fd, String debugPathName) {
+        return addAssetFdInternal(fd, debugPathName, false);
+    }
+
+    private int addAssetFdInternal(FileDescriptor fd, String debugPathName,
+            boolean appAsLib) {
+        synchronized (this) {
+            int res = addAssetFdNative(fd, debugPathName, appAsLib);
+            makeStringBlocks(mStringBlocks);
+            return res;
+        }
+    }
+
+    private native int addAssetFdNative(FileDescriptor fd, String debugPathName,
+            boolean appAsLib);
+
+    /**
+     * Add a set of assets to overlay an already added set of assets.
+     *
+     * This is only intended for application resources. System wide resources
+     * are handled before any Java code is executed.
+     *
+     * {@hide}
+     */
+
+    public final int addOverlayPath(String idmapPath) {
+        synchronized (this) {
+            int res = addOverlayPathNative(idmapPath);
+            makeStringBlocks(mStringBlocks);
+            return res;
+        }
+    }
+
+    /**
+     * See addOverlayPath.
+     *
+     * {@hide}
+     */
+    public native final int addOverlayPathNative(String idmapPath);
+
+    /**
+     * Add multiple sets of assets to the asset manager at once.  See
+     * {@link #addAssetPath(String)} for more information.  Returns array of
+     * cookies for each added asset with 0 indicating failure, or null if
+     * the input array of paths is null.
+     * {@hide}
+     */
+    public final int[] addAssetPaths(String[] paths) {
+        if (paths == null) {
+            return null;
+        }
+
+        int[] cookies = new int[paths.length];
+        for (int i = 0; i < paths.length; i++) {
+            cookies[i] = addAssetPath(paths[i]);
+        }
+
+        return cookies;
+    }
+
     /**
      * Determine whether the state in this asset manager is up-to-date with
      * the files on the filesystem.  If false is returned, you need to
      * instantiate a new AssetManager class to see the new data.
-     * @hide
+     * {@hide}
      */
-    public boolean isUpToDate() {
-        for (ApkAssets apkAssets : getApkAssets()) {
-            if (!apkAssets.isUpToDate()) {
-                return false;
-            }
-        }
-        return true;
-    }
+    public native final boolean isUpToDate();
 
     /**
      * Get the locales that this asset manager contains data for.
@@ -1071,12 +784,7 @@
      * are of the form {@code ll_CC} where {@code ll} is a two letter language code,
      * and {@code CC} is a two letter country code.
      */
-    public String[] getLocales() {
-        synchronized (this) {
-            ensureValidLocked();
-            return nativeGetLocales(mObject, false /*excludeSystem*/);
-        }
-    }
+    public native final String[] getLocales();
 
     /**
      * Same as getLocales(), except that locales that are only provided by the system (i.e. those
@@ -1086,57 +794,131 @@
      * assets support Cherokee and French, getLocales() would return
      * [Cherokee, English, French, German], while getNonSystemLocales() would return
      * [Cherokee, French].
-     * @hide
+     * {@hide}
      */
-    public String[] getNonSystemLocales() {
-        synchronized (this) {
-            ensureValidLocked();
-            return nativeGetLocales(mObject, true /*excludeSystem*/);
-        }
-    }
+    public native final String[] getNonSystemLocales();
+
+    /** {@hide} */
+    public native final Configuration[] getSizeConfigurations();
 
     /**
-     * @hide
-     */
-    Configuration[] getSizeConfigurations() {
-        synchronized (this) {
-            ensureValidLocked();
-            return nativeGetSizeConfigurations(mObject);
-        }
-    }
-
-    /**
-     * Change the configuration used when retrieving resources.  Not for use by
+     * Change the configuation used when retrieving resources.  Not for use by
      * applications.
-     * @hide
+     * {@hide}
      */
-    public void setConfiguration(int mcc, int mnc, @Nullable String locale, int orientation,
-            int touchscreen, int density, int keyboard, int keyboardHidden, int navigation,
-            int screenWidth, int screenHeight, int smallestScreenWidthDp, int screenWidthDp,
-            int screenHeightDp, int screenLayout, int uiMode, int colorMode, int majorVersion) {
-        synchronized (this) {
-            ensureValidLocked();
-            nativeSetConfiguration(mObject, mcc, mnc, locale, orientation, touchscreen, density,
-                    keyboard, keyboardHidden, navigation, screenWidth, screenHeight,
-                    smallestScreenWidthDp, screenWidthDp, screenHeightDp, screenLayout, uiMode,
-                    colorMode, majorVersion);
-        }
-    }
+    public native final void setConfiguration(int mcc, int mnc, String locale,
+            int orientation, int touchscreen, int density, int keyboard,
+            int keyboardHidden, int navigation, int screenWidth, int screenHeight,
+            int smallestScreenWidthDp, int screenWidthDp, int screenHeightDp,
+            int screenLayout, int uiMode, int colorMode, int majorVersion);
 
     /**
-     * @hide
+     * Retrieve the resource identifier for the given resource name.
      */
-    public SparseArray<String> getAssignedPackageIdentifiers() {
-        synchronized (this) {
-            ensureValidLocked();
-            return nativeGetAssignedPackageIdentifiers(mObject);
-        }
-    }
+    /*package*/ native final int getResourceIdentifier(String name,
+                                                       String defType,
+                                                       String defPackage);
 
-    private void incRefsLocked(long id) {
+    /*package*/ native final String getResourceName(int resid);
+    /*package*/ native final String getResourcePackageName(int resid);
+    /*package*/ native final String getResourceTypeName(int resid);
+    /*package*/ native final String getResourceEntryName(int resid);
+    
+    private native final long openAsset(String fileName, int accessMode);
+    private final native ParcelFileDescriptor openAssetFd(String fileName,
+            long[] outOffsets) throws IOException;
+    private native final long openNonAssetNative(int cookie, String fileName,
+            int accessMode);
+    private native ParcelFileDescriptor openNonAssetFdNative(int cookie,
+            String fileName, long[] outOffsets) throws IOException;
+    private native final void destroyAsset(long asset);
+    private native final int readAssetChar(long asset);
+    private native final int readAsset(long asset, byte[] b, int off, int len);
+    private native final long seekAsset(long asset, long offset, int whence);
+    private native final long getAssetLength(long asset);
+    private native final long getAssetRemainingLength(long asset);
+
+    /** Returns true if the resource was found, filling in mRetStringBlock and
+     *  mRetData. */
+    private native final int loadResourceValue(int ident, short density, TypedValue outValue,
+            boolean resolve);
+    /** Returns true if the resource was found, filling in mRetStringBlock and
+     *  mRetData. */
+    private native final int loadResourceBagValue(int ident, int bagEntryId, TypedValue outValue,
+                                               boolean resolve);
+    /*package*/ static final int STYLE_NUM_ENTRIES = 6;
+    /*package*/ static final int STYLE_TYPE = 0;
+    /*package*/ static final int STYLE_DATA = 1;
+    /*package*/ static final int STYLE_ASSET_COOKIE = 2;
+    /*package*/ static final int STYLE_RESOURCE_ID = 3;
+
+    /* Offset within typed data array for native changingConfigurations. */
+    static final int STYLE_CHANGING_CONFIGURATIONS = 4;
+
+    /*package*/ static final int STYLE_DENSITY = 5;
+    /*package*/ native static final void applyStyle(long theme,
+            int defStyleAttr, int defStyleRes, long xmlParser,
+            int[] inAttrs, int length, long outValuesAddress, long outIndicesAddress);
+    /*package*/ native static final boolean resolveAttrs(long theme,
+            int defStyleAttr, int defStyleRes, int[] inValues,
+            int[] inAttrs, int[] outValues, int[] outIndices);
+    /*package*/ native final boolean retrieveAttributes(
+            long xmlParser, int[] inAttrs, int[] outValues, int[] outIndices);
+    /*package*/ native final int getArraySize(int resource);
+    /*package*/ native final int retrieveArray(int resource, int[] outValues);
+    private native final int getStringBlockCount();
+    private native final long getNativeStringBlock(int block);
+
+    /**
+     * {@hide}
+     */
+    public native final String getCookieName(int cookie);
+
+    /**
+     * {@hide}
+     */
+    public native final SparseArray<String> getAssignedPackageIdentifiers();
+
+    /**
+     * {@hide}
+     */
+    public native static final int getGlobalAssetCount();
+    
+    /**
+     * {@hide}
+     */
+    public native static final String getAssetAllocations();
+    
+    /**
+     * {@hide}
+     */
+    public native static final int getGlobalAssetManagerCount();
+    
+    private native final long newTheme();
+    private native final void deleteTheme(long theme);
+    /*package*/ native static final void applyThemeStyle(long theme, int styleRes, boolean force);
+    /*package*/ native static final void copyTheme(long dest, long source);
+    /*package*/ native static final void clearTheme(long theme);
+    /*package*/ native static final int loadThemeAttributeValue(long theme, int ident,
+                                                                TypedValue outValue,
+                                                                boolean resolve);
+    /*package*/ native static final void dumpTheme(long theme, int priority, String tag, String prefix);
+    /*package*/ native static final @NativeConfig int getThemeChangingConfigurations(long theme);
+
+    private native final long openXmlAssetNative(int cookie, String fileName);
+
+    private native final String[] getArrayStringResource(int arrayRes);
+    private native final int[] getArrayStringInfo(int arrayRes);
+    /*package*/ native final int[] getArrayIntResource(int arrayRes);
+    /*package*/ native final int[] getStyleAttributes(int themeRes);
+
+    private native final void init(boolean isSystem);
+    private native final void destroy();
+
+    private final void incRefsLocked(long id) {
         if (DEBUG_REFS) {
             if (mRefStacks == null) {
-                mRefStacks = new HashMap<>();
+                mRefStacks = new HashMap<Long, RuntimeException>();
             }
             RuntimeException ex = new RuntimeException();
             ex.fillInStackTrace();
@@ -1144,117 +926,16 @@
         }
         mNumRefs++;
     }
-
-    private void decRefsLocked(long id) {
+    
+    private final void decRefsLocked(long id) {
         if (DEBUG_REFS && mRefStacks != null) {
             mRefStacks.remove(id);
         }
         mNumRefs--;
-        if (mNumRefs == 0 && mObject != 0) {
-            nativeDestroy(mObject);
-            mObject = 0;
+        //System.out.println("Dec streams: mNumRefs=" + mNumRefs
+        //                   + " mReleased=" + mReleased);
+        if (mNumRefs == 0) {
+            destroy();
         }
     }
-
-    // AssetManager setup native methods.
-    private static native long nativeCreate();
-    private static native void nativeDestroy(long ptr);
-    private static native void nativeSetApkAssets(long ptr, @NonNull ApkAssets[] apkAssets,
-            boolean invalidateCaches);
-    private static native void nativeSetConfiguration(long ptr, int mcc, int mnc,
-            @Nullable String locale, int orientation, int touchscreen, int density, int keyboard,
-            int keyboardHidden, int navigation, int screenWidth, int screenHeight,
-            int smallestScreenWidthDp, int screenWidthDp, int screenHeightDp, int screenLayout,
-            int uiMode, int colorMode, int majorVersion);
-    private static native @NonNull SparseArray<String> nativeGetAssignedPackageIdentifiers(
-            long ptr);
-
-    // File native methods.
-    private static native @Nullable String[] nativeList(long ptr, @NonNull String path)
-            throws IOException;
-    private static native long nativeOpenAsset(long ptr, @NonNull String fileName, int accessMode);
-    private static native @Nullable ParcelFileDescriptor nativeOpenAssetFd(long ptr,
-            @NonNull String fileName, long[] outOffsets) throws IOException;
-    private static native long nativeOpenNonAsset(long ptr, int cookie, @NonNull String fileName,
-            int accessMode);
-    private static native @Nullable ParcelFileDescriptor nativeOpenNonAssetFd(long ptr, int cookie,
-            @NonNull String fileName, @NonNull long[] outOffsets) throws IOException;
-    private static native long nativeOpenXmlAsset(long ptr, int cookie, @NonNull String fileName);
-
-    // Primitive resource native methods.
-    private static native int nativeGetResourceValue(long ptr, @AnyRes int resId, short density,
-            @NonNull TypedValue outValue, boolean resolveReferences);
-    private static native int nativeGetResourceBagValue(long ptr, @AnyRes int resId, int bagEntryId,
-            @NonNull TypedValue outValue);
-
-    private static native @Nullable @AttrRes int[] nativeGetStyleAttributes(long ptr,
-            @StyleRes int resId);
-    private static native @Nullable String[] nativeGetResourceStringArray(long ptr,
-            @ArrayRes int resId);
-    private static native @Nullable int[] nativeGetResourceStringArrayInfo(long ptr,
-            @ArrayRes int resId);
-    private static native @Nullable int[] nativeGetResourceIntArray(long ptr, @ArrayRes int resId);
-    private static native int nativeGetResourceArraySize(long ptr, @ArrayRes int resId);
-    private static native int nativeGetResourceArray(long ptr, @ArrayRes int resId,
-            @NonNull int[] outValues);
-
-    // Resource name/ID native methods.
-    private static native @AnyRes int nativeGetResourceIdentifier(long ptr, @NonNull String name,
-            @Nullable String defType, @Nullable String defPackage);
-    private static native @Nullable String nativeGetResourceName(long ptr, @AnyRes int resid);
-    private static native @Nullable String nativeGetResourcePackageName(long ptr,
-            @AnyRes int resid);
-    private static native @Nullable String nativeGetResourceTypeName(long ptr, @AnyRes int resid);
-    private static native @Nullable String nativeGetResourceEntryName(long ptr, @AnyRes int resid);
-    private static native @Nullable String[] nativeGetLocales(long ptr, boolean excludeSystem);
-    private static native @Nullable Configuration[] nativeGetSizeConfigurations(long ptr);
-
-    // Style attribute retrieval native methods.
-    private static native void nativeApplyStyle(long ptr, long themePtr, @AttrRes int defStyleAttr,
-            @StyleRes int defStyleRes, long xmlParserPtr, @NonNull int[] inAttrs,
-            long outValuesAddress, long outIndicesAddress);
-    private static native boolean nativeResolveAttrs(long ptr, long themePtr,
-            @AttrRes int defStyleAttr, @StyleRes int defStyleRes, @Nullable int[] inValues,
-            @NonNull int[] inAttrs, @NonNull int[] outValues, @NonNull int[] outIndices);
-    private static native boolean nativeRetrieveAttributes(long ptr, long xmlParserPtr,
-            @NonNull int[] inAttrs, @NonNull int[] outValues, @NonNull int[] outIndices);
-
-    // Theme related native methods
-    private static native long nativeThemeCreate(long ptr);
-    private static native void nativeThemeDestroy(long themePtr);
-    private static native void nativeThemeApplyStyle(long ptr, long themePtr, @StyleRes int resId,
-            boolean force);
-    static native void nativeThemeCopy(long destThemePtr, long sourceThemePtr);
-    static native void nativeThemeClear(long themePtr);
-    private static native int nativeThemeGetAttributeValue(long ptr, long themePtr,
-            @AttrRes int resId, @NonNull TypedValue outValue, boolean resolve);
-    private static native void nativeThemeDump(long ptr, long themePtr, int priority, String tag,
-            String prefix);
-    static native @NativeConfig int nativeThemeGetChangingConfigurations(long themePtr);
-
-    // AssetInputStream related native methods.
-    private static native void nativeAssetDestroy(long assetPtr);
-    private static native int nativeAssetReadChar(long assetPtr);
-    private static native int nativeAssetRead(long assetPtr, byte[] b, int off, int len);
-    private static native long nativeAssetSeek(long assetPtr, long offset, int whence);
-    private static native long nativeAssetGetLength(long assetPtr);
-    private static native long nativeAssetGetRemainingLength(long assetPtr);
-
-    private static native void nativeVerifySystemIdmaps();
-
-    // Global debug native methods.
-    /**
-     * @hide
-     */
-    public static native int getGlobalAssetCount();
-
-    /**
-     * @hide
-     */
-    public static native String getAssetAllocations();
-
-    /**
-     * @hide
-     */
-    public static native int getGlobalAssetManagerCount();
 }
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 8f58891..e173653c 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -590,7 +590,7 @@
      */
     @NonNull
     public int[] getIntArray(@ArrayRes int id) throws NotFoundException {
-        int[] res = mResourcesImpl.getAssets().getResourceIntArray(id);
+        int[] res = mResourcesImpl.getAssets().getArrayIntResource(id);
         if (res != null) {
             return res;
         }
@@ -613,13 +613,13 @@
     @NonNull
     public TypedArray obtainTypedArray(@ArrayRes int id) throws NotFoundException {
         final ResourcesImpl impl = mResourcesImpl;
-        int len = impl.getAssets().getResourceArraySize(id);
+        int len = impl.getAssets().getArraySize(id);
         if (len < 0) {
             throw new NotFoundException("Array resource ID #0x" + Integer.toHexString(id));
         }
         
         TypedArray array = TypedArray.obtain(this, len);
-        array.mLength = impl.getAssets().getResourceArray(id, array.mData);
+        array.mLength = impl.getAssets().retrieveArray(id, array.mData);
         array.mIndices[0] = 0;
         
         return array;
@@ -1789,7 +1789,8 @@
         // out the attributes from the XML file (applying type information
         // contained in the resources and such).
         XmlBlock.Parser parser = (XmlBlock.Parser)set;
-        mResourcesImpl.getAssets().retrieveAttributes(parser, attrs, array.mData, array.mIndices);
+        mResourcesImpl.getAssets().retrieveAttributes(parser.mParseState, attrs,
+                array.mData, array.mIndices);
 
         array.mXml = parser;
 
diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java
index 2a4b278..97cb78b 100644
--- a/core/java/android/content/res/ResourcesImpl.java
+++ b/core/java/android/content/res/ResourcesImpl.java
@@ -168,6 +168,7 @@
         mDisplayAdjustments = displayAdjustments;
         mConfiguration.setToDefaults();
         updateConfiguration(config, metrics, displayAdjustments.getCompatibilityInfo());
+        mAssets.ensureStringBlocks();
     }
 
     public DisplayAdjustments getDisplayAdjustments() {
@@ -1273,7 +1274,8 @@
 
         void applyStyle(int resId, boolean force) {
             synchronized (mKey) {
-                mAssets.applyStyleToTheme(mTheme, resId, force);
+                AssetManager.applyThemeStyle(mTheme, resId, force);
+
                 mThemeResId = resId;
                 mKey.append(resId, force);
             }
@@ -1282,7 +1284,7 @@
         void setTo(ThemeImpl other) {
             synchronized (mKey) {
                 synchronized (other.mKey) {
-                    AssetManager.nativeThemeCopy(mTheme, other.mTheme);
+                    AssetManager.copyTheme(mTheme, other.mTheme);
 
                     mThemeResId = other.mThemeResId;
                     mKey.setTo(other.getKey());
@@ -1305,10 +1307,12 @@
                 // out the attributes from the XML file (applying type information
                 // contained in the resources and such).
                 final XmlBlock.Parser parser = (XmlBlock.Parser) set;
-                mAssets.applyStyle(mTheme, defStyleAttr, defStyleRes, parser, attrs,
-                        array.mDataAddress, array.mIndicesAddress);
+                AssetManager.applyStyle(mTheme, defStyleAttr, defStyleRes,
+                        parser != null ? parser.mParseState : 0,
+                        attrs, attrs.length, array.mDataAddress, array.mIndicesAddress);
                 array.mTheme = wrapper;
                 array.mXml = parser;
+
                 return array;
             }
         }
@@ -1325,7 +1329,7 @@
                 }
 
                 final TypedArray array = TypedArray.obtain(wrapper.getResources(), len);
-                mAssets.resolveAttrs(mTheme, 0, 0, values, attrs, array.mData, array.mIndices);
+                AssetManager.resolveAttrs(mTheme, 0, 0, values, attrs, array.mData, array.mIndices);
                 array.mTheme = wrapper;
                 array.mXml = null;
                 return array;
@@ -1345,14 +1349,14 @@
         @Config int getChangingConfigurations() {
             synchronized (mKey) {
                 final @NativeConfig int nativeChangingConfig =
-                        AssetManager.nativeThemeGetChangingConfigurations(mTheme);
+                        AssetManager.getThemeChangingConfigurations(mTheme);
                 return ActivityInfo.activityInfoConfigNativeToJava(nativeChangingConfig);
             }
         }
 
         public void dump(int priority, String tag, String prefix) {
             synchronized (mKey) {
-                mAssets.dumpTheme(mTheme, priority, tag, prefix);
+                AssetManager.dumpTheme(mTheme, priority, tag, prefix);
             }
         }
 
@@ -1381,13 +1385,13 @@
          */
         void rebase() {
             synchronized (mKey) {
-                AssetManager.nativeThemeClear(mTheme);
+                AssetManager.clearTheme(mTheme);
 
                 // Reapply the same styles in the same order.
                 for (int i = 0; i < mKey.mCount; i++) {
                     final int resId = mKey.mResId[i];
                     final boolean force = mKey.mForce[i];
-                    mAssets.applyStyleToTheme(mTheme, resId, force);
+                    AssetManager.applyThemeStyle(mTheme, resId, force);
                 }
             }
         }
diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java
index cbb3c6d..f33c751 100644
--- a/core/java/android/content/res/TypedArray.java
+++ b/core/java/android/content/res/TypedArray.java
@@ -61,15 +61,6 @@
         return attrs;
     }
 
-    // STYLE_ prefixed constants are offsets within the typed data array.
-    static final int STYLE_NUM_ENTRIES = 6;
-    static final int STYLE_TYPE = 0;
-    static final int STYLE_DATA = 1;
-    static final int STYLE_ASSET_COOKIE = 2;
-    static final int STYLE_RESOURCE_ID = 3;
-    static final int STYLE_CHANGING_CONFIGURATIONS = 4;
-    static final int STYLE_DENSITY = 5;
-
     private final Resources mResources;
     private DisplayMetrics mMetrics;
     private AssetManager mAssets;
@@ -87,7 +78,7 @@
 
     private void resize(int len) {
         mLength = len;
-        final int dataLen = len * STYLE_NUM_ENTRIES;
+        final int dataLen = len * AssetManager.STYLE_NUM_ENTRIES;
         final int indicesLen = len + 1;
         final VMRuntime runtime = VMRuntime.getRuntime();
         if (mDataAddress == 0 || mData.length < dataLen) {
@@ -175,9 +166,9 @@
             throw new RuntimeException("Cannot make calls to a recycled instance!");
         }
 
-        index *= STYLE_NUM_ENTRIES;
+        index *= AssetManager.STYLE_NUM_ENTRIES;
         final int[] data = mData;
-        final int type = data[index + STYLE_TYPE];
+        final int type = data[index+AssetManager.STYLE_TYPE];
         if (type == TypedValue.TYPE_NULL) {
             return null;
         } else if (type == TypedValue.TYPE_STRING) {
@@ -212,9 +203,9 @@
             throw new RuntimeException("Cannot make calls to a recycled instance!");
         }
 
-        index *= STYLE_NUM_ENTRIES;
+        index *= AssetManager.STYLE_NUM_ENTRIES;
         final int[] data = mData;
-        final int type = data[index + STYLE_TYPE];
+        final int type = data[index+AssetManager.STYLE_TYPE];
         if (type == TypedValue.TYPE_NULL) {
             return null;
         } else if (type == TypedValue.TYPE_STRING) {
@@ -251,13 +242,14 @@
             throw new RuntimeException("Cannot make calls to a recycled instance!");
         }
 
-        index *= STYLE_NUM_ENTRIES;
+        index *= AssetManager.STYLE_NUM_ENTRIES;
         final int[] data = mData;
-        final int type = data[index + STYLE_TYPE];
+        final int type = data[index+AssetManager.STYLE_TYPE];
         if (type == TypedValue.TYPE_STRING) {
-            final int cookie = data[index + STYLE_ASSET_COOKIE];
+            final int cookie = data[index+AssetManager.STYLE_ASSET_COOKIE];
             if (cookie < 0) {
-                return mXml.getPooledString(data[index + STYLE_DATA]).toString();
+                return mXml.getPooledString(
+                    data[index+AssetManager.STYLE_DATA]).toString();
             }
         }
         return null;
@@ -282,11 +274,11 @@
             throw new RuntimeException("Cannot make calls to a recycled instance!");
         }
 
-        index *= STYLE_NUM_ENTRIES;
+        index *= AssetManager.STYLE_NUM_ENTRIES;
         final int[] data = mData;
-        final int type = data[index + STYLE_TYPE];
+        final int type = data[index+AssetManager.STYLE_TYPE];
         final @Config int changingConfigs = ActivityInfo.activityInfoConfigNativeToJava(
-                data[index + STYLE_CHANGING_CONFIGURATIONS]);
+                data[index + AssetManager.STYLE_CHANGING_CONFIGURATIONS]);
         if ((changingConfigs & ~allowedChangingConfigs) != 0) {
             return null;
         }
@@ -328,14 +320,14 @@
             throw new RuntimeException("Cannot make calls to a recycled instance!");
         }
 
-        index *= STYLE_NUM_ENTRIES;
+        index *= AssetManager.STYLE_NUM_ENTRIES;
         final int[] data = mData;
-        final int type = data[index + STYLE_TYPE];
+        final int type = data[index+AssetManager.STYLE_TYPE];
         if (type == TypedValue.TYPE_NULL) {
             return defValue;
         } else if (type >= TypedValue.TYPE_FIRST_INT
                 && type <= TypedValue.TYPE_LAST_INT) {
-            return data[index + STYLE_DATA] != 0;
+            return data[index+AssetManager.STYLE_DATA] != 0;
         }
 
         final TypedValue v = mValue;
@@ -367,14 +359,14 @@
             throw new RuntimeException("Cannot make calls to a recycled instance!");
         }
 
-        index *= STYLE_NUM_ENTRIES;
+        index *= AssetManager.STYLE_NUM_ENTRIES;
         final int[] data = mData;
-        final int type = data[index + STYLE_TYPE];
+        final int type = data[index+AssetManager.STYLE_TYPE];
         if (type == TypedValue.TYPE_NULL) {
             return defValue;
         } else if (type >= TypedValue.TYPE_FIRST_INT
                 && type <= TypedValue.TYPE_LAST_INT) {
-            return data[index + STYLE_DATA];
+            return data[index+AssetManager.STYLE_DATA];
         }
 
         final TypedValue v = mValue;
@@ -404,16 +396,16 @@
             throw new RuntimeException("Cannot make calls to a recycled instance!");
         }
 
-        index *= STYLE_NUM_ENTRIES;
+        index *= AssetManager.STYLE_NUM_ENTRIES;
         final int[] data = mData;
-        final int type = data[index + STYLE_TYPE];
+        final int type = data[index+AssetManager.STYLE_TYPE];
         if (type == TypedValue.TYPE_NULL) {
             return defValue;
         } else if (type == TypedValue.TYPE_FLOAT) {
-            return Float.intBitsToFloat(data[index + STYLE_DATA]);
+            return Float.intBitsToFloat(data[index+AssetManager.STYLE_DATA]);
         } else if (type >= TypedValue.TYPE_FIRST_INT
                 && type <= TypedValue.TYPE_LAST_INT) {
-            return data[index + STYLE_DATA];
+            return data[index+AssetManager.STYLE_DATA];
         }
 
         final TypedValue v = mValue;
@@ -454,15 +446,15 @@
         }
 
         final int attrIndex = index;
-        index *= STYLE_NUM_ENTRIES;
+        index *= AssetManager.STYLE_NUM_ENTRIES;
 
         final int[] data = mData;
-        final int type = data[index + STYLE_TYPE];
+        final int type = data[index+AssetManager.STYLE_TYPE];
         if (type == TypedValue.TYPE_NULL) {
             return defValue;
         } else if (type >= TypedValue.TYPE_FIRST_INT
                 && type <= TypedValue.TYPE_LAST_INT) {
-            return data[index + STYLE_DATA];
+            return data[index+AssetManager.STYLE_DATA];
         } else if (type == TypedValue.TYPE_STRING) {
             final TypedValue value = mValue;
             if (getValueAt(index, value)) {
@@ -506,7 +498,7 @@
         }
 
         final TypedValue value = mValue;
-        if (getValueAt(index * STYLE_NUM_ENTRIES, value)) {
+        if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
             if (value.type == TypedValue.TYPE_ATTRIBUTE) {
                 throw new UnsupportedOperationException(
                         "Failed to resolve attribute at index " + index + ": " + value);
@@ -541,7 +533,7 @@
         }
 
         final TypedValue value = mValue;
-        if (getValueAt(index * STYLE_NUM_ENTRIES, value)) {
+        if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
             if (value.type == TypedValue.TYPE_ATTRIBUTE) {
                 throw new UnsupportedOperationException(
                         "Failed to resolve attribute at index " + index + ": " + value);
@@ -572,15 +564,15 @@
         }
 
         final int attrIndex = index;
-        index *= STYLE_NUM_ENTRIES;
+        index *= AssetManager.STYLE_NUM_ENTRIES;
 
         final int[] data = mData;
-        final int type = data[index + STYLE_TYPE];
+        final int type = data[index+AssetManager.STYLE_TYPE];
         if (type == TypedValue.TYPE_NULL) {
             return defValue;
         } else if (type >= TypedValue.TYPE_FIRST_INT
                 && type <= TypedValue.TYPE_LAST_INT) {
-            return data[index + STYLE_DATA];
+            return data[index+AssetManager.STYLE_DATA];
         } else if (type == TypedValue.TYPE_ATTRIBUTE) {
             final TypedValue value = mValue;
             getValueAt(index, value);
@@ -620,14 +612,15 @@
         }
 
         final int attrIndex = index;
-        index *= STYLE_NUM_ENTRIES;
+        index *= AssetManager.STYLE_NUM_ENTRIES;
 
         final int[] data = mData;
-        final int type = data[index + STYLE_TYPE];
+        final int type = data[index+AssetManager.STYLE_TYPE];
         if (type == TypedValue.TYPE_NULL) {
             return defValue;
         } else if (type == TypedValue.TYPE_DIMENSION) {
-            return TypedValue.complexToDimension(data[index + STYLE_DATA], mMetrics);
+            return TypedValue.complexToDimension(
+                    data[index + AssetManager.STYLE_DATA], mMetrics);
         } else if (type == TypedValue.TYPE_ATTRIBUTE) {
             final TypedValue value = mValue;
             getValueAt(index, value);
@@ -668,14 +661,15 @@
         }
 
         final int attrIndex = index;
-        index *= STYLE_NUM_ENTRIES;
+        index *= AssetManager.STYLE_NUM_ENTRIES;
 
         final int[] data = mData;
-        final int type = data[index + STYLE_TYPE];
+        final int type = data[index+AssetManager.STYLE_TYPE];
         if (type == TypedValue.TYPE_NULL) {
             return defValue;
         } else if (type == TypedValue.TYPE_DIMENSION) {
-            return TypedValue.complexToDimensionPixelOffset(data[index + STYLE_DATA], mMetrics);
+            return TypedValue.complexToDimensionPixelOffset(
+                    data[index + AssetManager.STYLE_DATA], mMetrics);
         } else if (type == TypedValue.TYPE_ATTRIBUTE) {
             final TypedValue value = mValue;
             getValueAt(index, value);
@@ -717,14 +711,15 @@
         }
 
         final int attrIndex = index;
-        index *= STYLE_NUM_ENTRIES;
+        index *= AssetManager.STYLE_NUM_ENTRIES;
 
         final int[] data = mData;
-        final int type = data[index + STYLE_TYPE];
+        final int type = data[index+AssetManager.STYLE_TYPE];
         if (type == TypedValue.TYPE_NULL) {
             return defValue;
         } else if (type == TypedValue.TYPE_DIMENSION) {
-            return TypedValue.complexToDimensionPixelSize(data[index + STYLE_DATA], mMetrics);
+            return TypedValue.complexToDimensionPixelSize(
+                data[index+AssetManager.STYLE_DATA], mMetrics);
         } else if (type == TypedValue.TYPE_ATTRIBUTE) {
             final TypedValue value = mValue;
             getValueAt(index, value);
@@ -760,15 +755,16 @@
         }
 
         final int attrIndex = index;
-        index *= STYLE_NUM_ENTRIES;
+        index *= AssetManager.STYLE_NUM_ENTRIES;
 
         final int[] data = mData;
-        final int type = data[index + STYLE_TYPE];
+        final int type = data[index+AssetManager.STYLE_TYPE];
         if (type >= TypedValue.TYPE_FIRST_INT
                 && type <= TypedValue.TYPE_LAST_INT) {
-            return data[index + STYLE_DATA];
+            return data[index+AssetManager.STYLE_DATA];
         } else if (type == TypedValue.TYPE_DIMENSION) {
-            return TypedValue.complexToDimensionPixelSize(data[index + STYLE_DATA], mMetrics);
+            return TypedValue.complexToDimensionPixelSize(
+                data[index+AssetManager.STYLE_DATA], mMetrics);
         } else if (type == TypedValue.TYPE_ATTRIBUTE) {
             final TypedValue value = mValue;
             getValueAt(index, value);
@@ -799,14 +795,15 @@
             throw new RuntimeException("Cannot make calls to a recycled instance!");
         }
 
-        index *= STYLE_NUM_ENTRIES;
+        index *= AssetManager.STYLE_NUM_ENTRIES;
         final int[] data = mData;
-        final int type = data[index + STYLE_TYPE];
+        final int type = data[index+AssetManager.STYLE_TYPE];
         if (type >= TypedValue.TYPE_FIRST_INT
                 && type <= TypedValue.TYPE_LAST_INT) {
-            return data[index + STYLE_DATA];
+            return data[index+AssetManager.STYLE_DATA];
         } else if (type == TypedValue.TYPE_DIMENSION) {
-            return TypedValue.complexToDimensionPixelSize(data[index + STYLE_DATA], mMetrics);
+            return TypedValue.complexToDimensionPixelSize(
+                    data[index + AssetManager.STYLE_DATA], mMetrics);
         }
 
         return defValue;
@@ -836,14 +833,15 @@
         }
 
         final int attrIndex = index;
-        index *= STYLE_NUM_ENTRIES;
+        index *= AssetManager.STYLE_NUM_ENTRIES;
 
         final int[] data = mData;
-        final int type = data[index + STYLE_TYPE];
+        final int type = data[index+AssetManager.STYLE_TYPE];
         if (type == TypedValue.TYPE_NULL) {
             return defValue;
         } else if (type == TypedValue.TYPE_FRACTION) {
-            return TypedValue.complexToFraction(data[index + STYLE_DATA], base, pbase);
+            return TypedValue.complexToFraction(
+                data[index+AssetManager.STYLE_DATA], base, pbase);
         } else if (type == TypedValue.TYPE_ATTRIBUTE) {
             final TypedValue value = mValue;
             getValueAt(index, value);
@@ -876,10 +874,10 @@
             throw new RuntimeException("Cannot make calls to a recycled instance!");
         }
 
-        index *= STYLE_NUM_ENTRIES;
+        index *= AssetManager.STYLE_NUM_ENTRIES;
         final int[] data = mData;
-        if (data[index + STYLE_TYPE] != TypedValue.TYPE_NULL) {
-            final int resid = data[index + STYLE_RESOURCE_ID];
+        if (data[index+AssetManager.STYLE_TYPE] != TypedValue.TYPE_NULL) {
+            final int resid = data[index+AssetManager.STYLE_RESOURCE_ID];
             if (resid != 0) {
                 return resid;
             }
@@ -904,10 +902,10 @@
             throw new RuntimeException("Cannot make calls to a recycled instance!");
         }
 
-        index *= STYLE_NUM_ENTRIES;
+        index *= AssetManager.STYLE_NUM_ENTRIES;
         final int[] data = mData;
-        if (data[index + STYLE_TYPE] == TypedValue.TYPE_ATTRIBUTE) {
-            return data[index + STYLE_DATA];
+        if (data[index + AssetManager.STYLE_TYPE] == TypedValue.TYPE_ATTRIBUTE) {
+            return data[index + AssetManager.STYLE_DATA];
         }
         return defValue;
     }
@@ -941,7 +939,7 @@
         }
 
         final TypedValue value = mValue;
-        if (getValueAt(index * STYLE_NUM_ENTRIES, value)) {
+        if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
             if (value.type == TypedValue.TYPE_ATTRIBUTE) {
                 throw new UnsupportedOperationException(
                         "Failed to resolve attribute at index " + index + ": " + value);
@@ -977,7 +975,7 @@
         }
 
         final TypedValue value = mValue;
-        if (getValueAt(index * STYLE_NUM_ENTRIES, value)) {
+        if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
             if (value.type == TypedValue.TYPE_ATTRIBUTE) {
                 throw new UnsupportedOperationException(
                         "Failed to resolve attribute at index " + index + ": " + value);
@@ -1008,7 +1006,7 @@
         }
 
         final TypedValue value = mValue;
-        if (getValueAt(index * STYLE_NUM_ENTRIES, value)) {
+        if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
             return mResources.getTextArray(value.resourceId);
         }
         return null;
@@ -1029,7 +1027,7 @@
             throw new RuntimeException("Cannot make calls to a recycled instance!");
         }
 
-        return getValueAt(index * STYLE_NUM_ENTRIES, outValue);
+        return getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, outValue);
     }
 
     /**
@@ -1045,8 +1043,8 @@
             throw new RuntimeException("Cannot make calls to a recycled instance!");
         }
 
-        index *= STYLE_NUM_ENTRIES;
-        return mData[index + STYLE_TYPE];
+        index *= AssetManager.STYLE_NUM_ENTRIES;
+        return mData[index + AssetManager.STYLE_TYPE];
     }
 
     /**
@@ -1065,9 +1063,9 @@
             throw new RuntimeException("Cannot make calls to a recycled instance!");
         }
 
-        index *= STYLE_NUM_ENTRIES;
+        index *= AssetManager.STYLE_NUM_ENTRIES;
         final int[] data = mData;
-        final int type = data[index + STYLE_TYPE];
+        final int type = data[index+AssetManager.STYLE_TYPE];
         return type != TypedValue.TYPE_NULL;
     }
 
@@ -1086,11 +1084,11 @@
             throw new RuntimeException("Cannot make calls to a recycled instance!");
         }
 
-        index *= STYLE_NUM_ENTRIES;
+        index *= AssetManager.STYLE_NUM_ENTRIES;
         final int[] data = mData;
-        final int type = data[index + STYLE_TYPE];
+        final int type = data[index+AssetManager.STYLE_TYPE];
         return type != TypedValue.TYPE_NULL
-                || data[index + STYLE_DATA] == TypedValue.DATA_NULL_EMPTY;
+                || data[index+AssetManager.STYLE_DATA] == TypedValue.DATA_NULL_EMPTY;
     }
 
     /**
@@ -1111,7 +1109,7 @@
         }
 
         final TypedValue value = mValue;
-        if (getValueAt(index * STYLE_NUM_ENTRIES, value)) {
+        if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
             return value;
         }
         return null;
@@ -1183,16 +1181,16 @@
         final int[] data = mData;
         final int N = length();
         for (int i = 0; i < N; i++) {
-            final int index = i * STYLE_NUM_ENTRIES;
-            if (data[index + STYLE_TYPE] != TypedValue.TYPE_ATTRIBUTE) {
+            final int index = i * AssetManager.STYLE_NUM_ENTRIES;
+            if (data[index + AssetManager.STYLE_TYPE] != TypedValue.TYPE_ATTRIBUTE) {
                 // Not an attribute, ignore.
                 continue;
             }
 
             // Null the entry so that we can safely call getZzz().
-            data[index + STYLE_TYPE] = TypedValue.TYPE_NULL;
+            data[index + AssetManager.STYLE_TYPE] = TypedValue.TYPE_NULL;
 
-            final int attr = data[index + STYLE_DATA];
+            final int attr = data[index + AssetManager.STYLE_DATA];
             if (attr == 0) {
                 // Useless data, ignore.
                 continue;
@@ -1233,44 +1231,45 @@
         final int[] data = mData;
         final int N = length();
         for (int i = 0; i < N; i++) {
-            final int index = i * STYLE_NUM_ENTRIES;
-            final int type = data[index + STYLE_TYPE];
+            final int index = i * AssetManager.STYLE_NUM_ENTRIES;
+            final int type = data[index + AssetManager.STYLE_TYPE];
             if (type == TypedValue.TYPE_NULL) {
                 continue;
             }
             changingConfig |= ActivityInfo.activityInfoConfigNativeToJava(
-                    data[index + STYLE_CHANGING_CONFIGURATIONS]);
+                    data[index + AssetManager.STYLE_CHANGING_CONFIGURATIONS]);
         }
         return changingConfig;
     }
 
     private boolean getValueAt(int index, TypedValue outValue) {
         final int[] data = mData;
-        final int type = data[index + STYLE_TYPE];
+        final int type = data[index+AssetManager.STYLE_TYPE];
         if (type == TypedValue.TYPE_NULL) {
             return false;
         }
         outValue.type = type;
-        outValue.data = data[index + STYLE_DATA];
-        outValue.assetCookie = data[index + STYLE_ASSET_COOKIE];
-        outValue.resourceId = data[index + STYLE_RESOURCE_ID];
+        outValue.data = data[index+AssetManager.STYLE_DATA];
+        outValue.assetCookie = data[index+AssetManager.STYLE_ASSET_COOKIE];
+        outValue.resourceId = data[index+AssetManager.STYLE_RESOURCE_ID];
         outValue.changingConfigurations = ActivityInfo.activityInfoConfigNativeToJava(
-                data[index + STYLE_CHANGING_CONFIGURATIONS]);
-        outValue.density = data[index + STYLE_DENSITY];
+                data[index + AssetManager.STYLE_CHANGING_CONFIGURATIONS]);
+        outValue.density = data[index+AssetManager.STYLE_DENSITY];
         outValue.string = (type == TypedValue.TYPE_STRING) ? loadStringValueAt(index) : null;
         return true;
     }
 
     private CharSequence loadStringValueAt(int index) {
         final int[] data = mData;
-        final int cookie = data[index + STYLE_ASSET_COOKIE];
+        final int cookie = data[index+AssetManager.STYLE_ASSET_COOKIE];
         if (cookie < 0) {
             if (mXml != null) {
-                return mXml.getPooledString(data[index + STYLE_DATA]);
+                return mXml.getPooledString(
+                    data[index+AssetManager.STYLE_DATA]);
             }
             return null;
         }
-        return mAssets.getPooledStringForCookie(cookie, data[index + STYLE_DATA]);
+        return mAssets.getPooledStringForCookie(cookie, data[index+AssetManager.STYLE_DATA]);
     }
 
     /** @hide */
diff --git a/core/java/android/content/res/XmlBlock.java b/core/java/android/content/res/XmlBlock.java
index d4ccffb..e6b95741 100644
--- a/core/java/android/content/res/XmlBlock.java
+++ b/core/java/android/content/res/XmlBlock.java
@@ -16,7 +16,6 @@
 
 package android.content.res;
 
-import android.annotation.Nullable;
 import android.util.TypedValue;
 
 import com.android.internal.util.XmlUtils;
@@ -34,7 +33,7 @@
  * 
  * {@hide}
  */
-final class XmlBlock implements AutoCloseable {
+final class XmlBlock {
     private static final boolean DEBUG=false;
 
     public XmlBlock(byte[] data) {
@@ -49,7 +48,6 @@
         mStrings = new StringBlock(nativeGetStringBlock(mNative), false);
     }
 
-    @Override
     public void close() {
         synchronized (this) {
             if (mOpen) {
@@ -480,13 +478,13 @@
      *  are doing!  The given native object must exist for the entire lifetime
      *  of this newly creating XmlBlock.
      */
-    XmlBlock(@Nullable AssetManager assets, long xmlBlock) {
+    XmlBlock(AssetManager assets, long xmlBlock) {
         mAssets = assets;
         mNative = xmlBlock;
         mStrings = new StringBlock(nativeGetStringBlock(xmlBlock), false);
     }
 
-    private @Nullable final AssetManager mAssets;
+    private final AssetManager mAssets;
     private final long mNative;
     /*package*/ final StringBlock mStrings;
     private boolean mOpen = true;
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index 1de8882..fdea5a2 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -1246,7 +1246,7 @@
             int repeat;
             if (effect instanceof VibrationEffect.OneShot) {
                 VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) effect;
-                pattern = new long[] { 0, oneShot.getTiming() };
+                pattern = new long[] { 0, oneShot.getDuration() };
                 repeat = -1;
             } else if (effect instanceof VibrationEffect.Waveform) {
                 VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) effect;
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 7528bc3..a817f33 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -265,6 +265,10 @@
      */
     public static final int IME_VISIBLE = 0x2;
 
+    // Min and max values for back disposition.
+    private static final int BACK_DISPOSITION_MIN = BACK_DISPOSITION_DEFAULT;
+    private static final int BACK_DISPOSITION_MAX = BACK_DISPOSITION_WILL_DISMISS;
+
     InputMethodManager mImm;
     
     int mTheme = 0;
@@ -501,9 +505,8 @@
             }
             clearInsetOfPreviousIme();
             // If user uses hard keyboard, IME button should always be shown.
-            boolean showing = isInputViewShown();
             mImm.setImeWindowStatus(mToken, mStartInputToken,
-                    IME_ACTIVE | (showing ? IME_VISIBLE : 0), mBackDisposition);
+                    mapToImeWindowStatus(isInputViewShown()), mBackDisposition);
             if (resultReceiver != null) {
                 resultReceiver.send(wasVis != isInputViewShown()
                         ? InputMethodManager.RESULT_SHOWN
@@ -1014,7 +1017,16 @@
     }
     
     public void setBackDisposition(int disposition) {
+        if (disposition == mBackDisposition) {
+            return;
+        }
+        if (disposition > BACK_DISPOSITION_MAX || disposition < BACK_DISPOSITION_MIN) {
+            Log.e(TAG, "Invalid back disposition value (" + disposition + ") specified.");
+            return;
+        }
         mBackDisposition = disposition;
+        mImm.setImeWindowStatus(mToken, mStartInputToken, mapToImeWindowStatus(isInputViewShown()),
+                mBackDisposition);
     }
 
     public int getBackDisposition() {
@@ -1762,7 +1774,7 @@
             startExtractingText(false);
         }
 
-        final int nextImeWindowStatus = IME_ACTIVE | (isInputViewShown() ? IME_VISIBLE : 0);
+        final int nextImeWindowStatus = mapToImeWindowStatus(isInputViewShown());
         if (previousImeWindowStatus != nextImeWindowStatus) {
             mImm.setImeWindowStatus(mToken, mStartInputToken, nextImeWindowStatus,
                     mBackDisposition);
@@ -1889,6 +1901,7 @@
         mInputStarted = false;
         mStartedInputConnection = null;
         mCurCompletions = null;
+        mBackDisposition = BACK_DISPOSITION_DEFAULT;
     }
 
     void doStartInput(InputConnection ic, EditorInfo attribute, boolean restarting) {
@@ -2104,7 +2117,11 @@
      * them to perform navigation in the underlying application.
      */
     public boolean onKeyDown(int keyCode, KeyEvent event) {
+
         if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
+            if (mBackDisposition == BACK_DISPOSITION_WILL_NOT_DISMISS) {
+                return false;
+            }
             final ExtractEditText eet = getExtractEditTextIfVisible();
             if (eet != null && eet.handleBackInTextActionModeIfNeeded(event)) {
                 return true;
@@ -2738,6 +2755,10 @@
         mImm.exposeContent(mToken, inputContentInfo, getCurrentInputEditorInfo());
     }
 
+    private static int mapToImeWindowStatus(boolean isInputViewShown) {
+        return IME_ACTIVE | (isInputViewShown ? IME_VISIBLE : 0);
+    }
+
     /**
      * Performs a dump of the InputMethodService's internal state.  Override
      * to add your own information to the dump.
diff --git a/core/java/android/net/metrics/NetworkMetrics.java b/core/java/android/net/metrics/NetworkMetrics.java
index 2b662a0..2425bba 100644
--- a/core/java/android/net/metrics/NetworkMetrics.java
+++ b/core/java/android/net/metrics/NetworkMetrics.java
@@ -96,6 +96,13 @@
         }
     }
 
+    /** Accumulate a single netd sock_diag poll result reported by netd. */
+    public void addTcpStatsResult(int sent, int lost, int rttUs, int sentAckDiffMs) {
+        pendingSummary.tcpLossRate.count(lost, sent);
+        pendingSummary.roundTripTimeUs.count(rttUs);
+        pendingSummary.sentAckTimeDiffenceMs.count(sentAckDiffMs);
+    }
+
     /** Represents running sums for dns and connect average error counts and average latencies. */
     public static class Summary {
 
@@ -109,6 +116,13 @@
         public final Metrics connectLatencies = new Metrics();
         // Blocking and non blocking connect error rate measured in percentage points.
         public final Metrics connectErrorRate = new Metrics();
+        // TCP socket packet loss stats collected from Netlink sock_diag.
+        public final Metrics tcpLossRate = new Metrics();
+        // TCP averaged microsecond round-trip-time stats collected from Netlink sock_diag.
+        public final Metrics roundTripTimeUs = new Metrics();
+        // TCP stats collected from Netlink sock_diag that averages millisecond per-socket
+        // differences between last packet sent timestamp and last ack received timestamp.
+        public final Metrics sentAckTimeDiffenceMs = new Metrics();
 
         public Summary(int netId, long transports) {
             this.netId = netId;
@@ -120,6 +134,7 @@
             dnsErrorRate.merge(that.dnsErrorRate);
             connectLatencies.merge(that.connectLatencies);
             connectErrorRate.merge(that.connectErrorRate);
+            tcpLossRate.merge(that.tcpLossRate);
         }
 
         @Override
@@ -135,6 +150,10 @@
             j.add(String.format("connect avg=%dms max=%dms err=%.1f%% tot=%d",
                     (int) connectLatencies.average(), (int) connectLatencies.max,
                     100 * connectErrorRate.average(), connectErrorRate.count));
+            j.add(String.format("tcp avg_loss=%.1f%% total_sent=%d total_lost=%d",
+                    100 * tcpLossRate.average(), tcpLossRate.count, (int) tcpLossRate.sum));
+            j.add(String.format("tcp rtt=%dms", (int) (roundTripTimeUs.average() / 1000)));
+            j.add(String.format("tcp sent-ack_diff=%dms", (int) sentAckTimeDiffenceMs.average()));
             return j.toString();
         }
     }
@@ -152,7 +171,11 @@
         }
 
         void count(double value) {
-            count++;
+            count(value, 1);
+        }
+
+        void count(double value, int subcount) {
+            count += subcount;
             sum += value;
             max = Math.max(max, value);
         }
diff --git a/core/java/android/os/BatteryManager.java b/core/java/android/os/BatteryManager.java
index 843bdb5..a734719 100644
--- a/core/java/android/os/BatteryManager.java
+++ b/core/java/android/os/BatteryManager.java
@@ -157,11 +157,11 @@
     // values of the "plugged" field in the ACTION_BATTERY_CHANGED intent.
     // These must be powers of 2.
     /** Power source is an AC charger. */
-    public static final int BATTERY_PLUGGED_AC = 1;
+    public static final int BATTERY_PLUGGED_AC = OsProtoEnums.BATTERY_PLUGGED_AC; // = 1
     /** Power source is a USB port. */
-    public static final int BATTERY_PLUGGED_USB = 2;
+    public static final int BATTERY_PLUGGED_USB = OsProtoEnums.BATTERY_PLUGGED_USB; // = 2
     /** Power source is wireless. */
-    public static final int BATTERY_PLUGGED_WIRELESS = 4;
+    public static final int BATTERY_PLUGGED_WIRELESS = OsProtoEnums.BATTERY_PLUGGED_WIRELESS; // = 4
 
     /** @hide */
     public static final int BATTERY_PLUGGED_ANY =
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index fc78861..48f5684 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -894,14 +894,6 @@
 
         /**
          * P.
-         *
-         * <p>Applications targeting this or a later release will get these
-         * new changes in behavior:</p>
-         * <ul>
-         * <li>{@link android.app.Service#startForeground Service.startForeground} requires
-         * that apps hold the permission
-         * {@link android.Manifest.permission#FOREGROUND_SERVICE}.</li>
-         * </ul>
          */
         public static final int P = CUR_DEVELOPMENT; // STOPSHIP Replace with the real version.
     }
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 158041d..03203d0 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -41,6 +41,7 @@
     private static final String ENV_OEM_ROOT = "OEM_ROOT";
     private static final String ENV_ODM_ROOT = "ODM_ROOT";
     private static final String ENV_VENDOR_ROOT = "VENDOR_ROOT";
+    private static final String ENV_PRODUCT_ROOT = "PRODUCT_ROOT";
 
     /** {@hide} */
     public static final String DIR_ANDROID = "Android";
@@ -62,6 +63,7 @@
     private static final File DIR_OEM_ROOT = getDirectory(ENV_OEM_ROOT, "/oem");
     private static final File DIR_ODM_ROOT = getDirectory(ENV_ODM_ROOT, "/odm");
     private static final File DIR_VENDOR_ROOT = getDirectory(ENV_VENDOR_ROOT, "/vendor");
+    private static final File DIR_PRODUCT_ROOT = getDirectory(ENV_PRODUCT_ROOT, "/product");
 
     private static UserEnvironment sCurrentUser;
     private static boolean sUserRequired;
@@ -180,6 +182,16 @@
     }
 
     /**
+     * Return root directory of the "product" partition holding product-specific
+     * customizations if any. If present, the partition is mounted read-only.
+     *
+     * @hide
+     */
+    public static File getProductDirectory() {
+        return DIR_PRODUCT_ROOT;
+    }
+
+    /**
      * Return the system directory for a user. This is for use by system
      * services to store files relating to the user. This directory will be
      * automatically deleted when the user is removed.
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 3d17ffb..811cc5e 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -110,7 +110,7 @@
     /* NOTE: Wake lock levels were previously defined as a bit field, except that only a few
      * combinations were actually supported so the bit field was removed.  This explains
      * why the numbering scheme is so odd.  If adding a new wake lock level, any unused
-     * value can be used.
+     * value (in frameworks/base/core/proto/android/os/enums.proto) can be used.
      */
 
     /**
@@ -121,7 +121,7 @@
      * but the CPU will be kept on until all partial wake locks have been released.
      * </p>
      */
-    public static final int PARTIAL_WAKE_LOCK = 0x00000001;
+    public static final int PARTIAL_WAKE_LOCK = OsProtoEnums.PARTIAL_WAKE_LOCK; // 0x00000001
 
     /**
      * Wake lock level: Ensures that the screen is on (but may be dimmed);
@@ -138,7 +138,7 @@
      * as the user moves between applications and doesn't require a special permission.
      */
     @Deprecated
-    public static final int SCREEN_DIM_WAKE_LOCK = 0x00000006;
+    public static final int SCREEN_DIM_WAKE_LOCK = OsProtoEnums.SCREEN_DIM_WAKE_LOCK; // 0x00000006
 
     /**
      * Wake lock level: Ensures that the screen is on at full brightness;
@@ -155,7 +155,8 @@
      * as the user moves between applications and doesn't require a special permission.
      */
     @Deprecated
-    public static final int SCREEN_BRIGHT_WAKE_LOCK = 0x0000000a;
+    public static final int SCREEN_BRIGHT_WAKE_LOCK =
+            OsProtoEnums.SCREEN_BRIGHT_WAKE_LOCK; // 0x0000000a
 
     /**
      * Wake lock level: Ensures that the screen and keyboard backlight are on at
@@ -172,7 +173,7 @@
      * as the user moves between applications and doesn't require a special permission.
      */
     @Deprecated
-    public static final int FULL_WAKE_LOCK = 0x0000001a;
+    public static final int FULL_WAKE_LOCK = OsProtoEnums.FULL_WAKE_LOCK; // 0x0000001a
 
     /**
      * Wake lock level: Turns the screen off when the proximity sensor activates.
@@ -193,7 +194,8 @@
      * Cannot be used with {@link #ACQUIRE_CAUSES_WAKEUP}.
      * </p>
      */
-    public static final int PROXIMITY_SCREEN_OFF_WAKE_LOCK = 0x00000020;
+    public static final int PROXIMITY_SCREEN_OFF_WAKE_LOCK =
+            OsProtoEnums.PROXIMITY_SCREEN_OFF_WAKE_LOCK; // 0x00000020
 
     /**
      * Wake lock level: Put the screen in a low power state and allow the CPU to suspend
@@ -207,7 +209,7 @@
      *
      * {@hide}
      */
-    public static final int DOZE_WAKE_LOCK = 0x00000040;
+    public static final int DOZE_WAKE_LOCK = OsProtoEnums.DOZE_WAKE_LOCK; // 0x00000040
 
     /**
      * Wake lock level: Keep the device awake enough to allow drawing to occur.
@@ -221,7 +223,7 @@
      *
      * {@hide}
      */
-    public static final int DRAW_WAKE_LOCK = 0x00000080;
+    public static final int DRAW_WAKE_LOCK = OsProtoEnums.DRAW_WAKE_LOCK; // 0x00000080
 
     /**
      * Mask for the wake lock level component of a combined wake lock level and flags integer.
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 13b5b5c9..b2b43cf 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -2259,12 +2259,6 @@
         }
     }
 
-    /** @removed */
-    @Deprecated
-    public boolean trySetQuietModeEnabled(boolean enableQuietMode, @NonNull UserHandle userHandle) {
-        return requestQuietModeEnabled(enableQuietMode, userHandle);
-    }
-
     /**
      * Enables or disables quiet mode for a managed profile. If quiet mode is enabled, apps in a
      * managed profile don't run, generate notifications, or consume data or battery.
diff --git a/core/java/android/os/VibrationEffect.java b/core/java/android/os/VibrationEffect.java
index da0ed54..b6f16a7 100644
--- a/core/java/android/os/VibrationEffect.java
+++ b/core/java/android/os/VibrationEffect.java
@@ -16,7 +16,9 @@
 
 package android.os;
 
+import android.hardware.vibrator.V1_0.Constants.EffectStrength;
 import android.hardware.vibrator.V1_1.Constants.Effect_1_1;
+import android.util.MathUtils;
 
 import java.util.Arrays;
 
@@ -36,6 +38,12 @@
     public static final int DEFAULT_AMPLITUDE = -1;
 
     /**
+     * The maximum amplitude value
+     * @hide
+     */
+    public static final int MAX_AMPLITUDE = 255;
+
+    /**
      * A click effect.
      *
      * @see #get(int)
@@ -198,38 +206,75 @@
     /** @hide */
     public abstract void validate();
 
+    /**
+     * Gets the estimated duration of the vibration in milliseconds.
+     *
+     * For effects without a defined end (e.g. a Waveform with a non-negative repeat index), this
+     * returns Long.MAX_VALUE. For effects with an unknown duration (e.g. Prebaked effects where
+     * the length is device and potentially run-time dependent), this returns -1.
+     *
+     * @hide
+     */
+    public abstract long getDuration();
+
+    /**
+     * Scale the amplitude with the given constraints.
+     *
+     * This assumes that the previous value was in the range [0, MAX_AMPLITUDE]
+     * @hide
+     */
+    protected static int scale(int amplitude, float gamma, int maxAmplitude) {
+        float val = MathUtils.pow(amplitude / (float) MAX_AMPLITUDE, gamma);
+        return (int) (val * maxAmplitude);
+    }
+
     /** @hide */
     public static class OneShot extends VibrationEffect implements Parcelable {
-        private long mTiming;
-        private int mAmplitude;
+        private final long mDuration;
+        private final int mAmplitude;
 
         public OneShot(Parcel in) {
-            this(in.readLong(), in.readInt());
+            mDuration = in.readLong();
+            mAmplitude = in.readInt();
         }
 
         public OneShot(long milliseconds, int amplitude) {
-            mTiming = milliseconds;
+            mDuration = milliseconds;
             mAmplitude = amplitude;
         }
 
-        public long getTiming() {
-            return mTiming;
+        @Override
+        public long getDuration() {
+            return mDuration;
         }
 
         public int getAmplitude() {
             return mAmplitude;
         }
 
+        /**
+         * Scale the amplitude of this effect.
+         *
+         * @param gamma the gamma adjustment to apply
+         * @param maxAmplitude the new maximum amplitude of the effect
+         *
+         * @return A {@link OneShot} effect with the same timing but scaled amplitude.
+         */
+        public VibrationEffect scale(float gamma, int maxAmplitude) {
+            int newAmplitude = scale(mAmplitude, gamma, maxAmplitude);
+            return new OneShot(mDuration, newAmplitude);
+        }
+
         @Override
         public void validate() {
             if (mAmplitude < -1 || mAmplitude == 0 || mAmplitude > 255) {
                 throw new IllegalArgumentException(
-                        "amplitude must either be DEFAULT_AMPLITUDE, " +
-                        "or between 1 and 255 inclusive (amplitude=" + mAmplitude + ")");
+                        "amplitude must either be DEFAULT_AMPLITUDE, "
+                        + "or between 1 and 255 inclusive (amplitude=" + mAmplitude + ")");
             }
-            if (mTiming <= 0) {
+            if (mDuration <= 0) {
                 throw new IllegalArgumentException(
-                        "timing must be positive (timing=" + mTiming + ")");
+                        "duration must be positive (duration=" + mDuration + ")");
             }
         }
 
@@ -239,26 +284,26 @@
                 return false;
             }
             VibrationEffect.OneShot other = (VibrationEffect.OneShot) o;
-            return other.mTiming == mTiming && other.mAmplitude == mAmplitude;
+            return other.mDuration == mDuration && other.mAmplitude == mAmplitude;
         }
 
         @Override
         public int hashCode() {
             int result = 17;
-            result = 37 * (int) mTiming;
-            result = 37 * mAmplitude;
+            result += 37 * (int) mDuration;
+            result += 37 * mAmplitude;
             return result;
         }
 
         @Override
         public String toString() {
-            return "OneShot{mTiming=" + mTiming +", mAmplitude=" + mAmplitude + "}";
+            return "OneShot{mDuration=" + mDuration + ", mAmplitude=" + mAmplitude + "}";
         }
 
         @Override
         public void writeToParcel(Parcel out, int flags) {
             out.writeInt(PARCEL_TOKEN_ONE_SHOT);
-            out.writeLong(mTiming);
+            out.writeLong(mDuration);
             out.writeInt(mAmplitude);
         }
 
@@ -279,9 +324,9 @@
 
     /** @hide */
     public static class Waveform extends VibrationEffect implements Parcelable {
-        private long[] mTimings;
-        private int[] mAmplitudes;
-        private int mRepeat;
+        private final long[] mTimings;
+        private final int[] mAmplitudes;
+        private final int mRepeat;
 
         public Waveform(Parcel in) {
             this(in.createLongArray(), in.createIntArray(), in.readInt());
@@ -308,34 +353,68 @@
         }
 
         @Override
+        public long getDuration() {
+            if (mRepeat >= 0) {
+                return Long.MAX_VALUE;
+            }
+            long duration = 0;
+            for (long d : mTimings) {
+                duration += d;
+            }
+            return duration;
+        }
+
+        /**
+         * Scale the Waveform with the given gamma and new max amplitude.
+         *
+         * @param gamma the gamma adjustment to apply
+         * @param maxAmplitude the new maximum amplitude of the effect
+         *
+         * @return A {@link Waveform} effect with the same timings and repeat index
+         *         but scaled amplitude.
+         */
+        public VibrationEffect scale(float gamma, int maxAmplitude) {
+            if (gamma == 1.0f && maxAmplitude == MAX_AMPLITUDE) {
+                // Just return a copy of the original if there's no scaling to be done.
+                return new Waveform(mTimings, mAmplitudes, mRepeat);
+            }
+
+            int[] scaledAmplitudes = Arrays.copyOf(mAmplitudes, mAmplitudes.length);
+            for (int i = 0; i < scaledAmplitudes.length; i++) {
+                scaledAmplitudes[i] = scale(scaledAmplitudes[i], gamma, maxAmplitude);
+            }
+            return new Waveform(mTimings, scaledAmplitudes, mRepeat);
+        }
+
+        @Override
         public void validate() {
             if (mTimings.length != mAmplitudes.length) {
                 throw new IllegalArgumentException(
-                        "timing and amplitude arrays must be of equal length" +
-                        " (timings.length=" + mTimings.length +
-                        ", amplitudes.length=" + mAmplitudes.length + ")");
+                        "timing and amplitude arrays must be of equal length"
+                        + " (timings.length=" + mTimings.length
+                        + ", amplitudes.length=" + mAmplitudes.length + ")");
             }
             if (!hasNonZeroEntry(mTimings)) {
-                throw new IllegalArgumentException("at least one timing must be non-zero" +
-                        " (timings=" + Arrays.toString(mTimings) + ")");
+                throw new IllegalArgumentException("at least one timing must be non-zero"
+                        + " (timings=" + Arrays.toString(mTimings) + ")");
             }
             for (long timing : mTimings) {
                 if (timing < 0) {
-                    throw new IllegalArgumentException("timings must all be >= 0" +
-                            " (timings=" + Arrays.toString(mTimings) + ")");
+                    throw new IllegalArgumentException("timings must all be >= 0"
+                            + " (timings=" + Arrays.toString(mTimings) + ")");
                 }
             }
             for (int amplitude : mAmplitudes) {
                 if (amplitude < -1 || amplitude > 255) {
                     throw new IllegalArgumentException(
-                            "amplitudes must all be DEFAULT_AMPLITUDE or between 0 and 255" +
-                            " (amplitudes=" + Arrays.toString(mAmplitudes) + ")");
+                            "amplitudes must all be DEFAULT_AMPLITUDE or between 0 and 255"
+                            + " (amplitudes=" + Arrays.toString(mAmplitudes) + ")");
                 }
             }
             if (mRepeat < -1 || mRepeat >= mTimings.length) {
                 throw new IllegalArgumentException(
-                        "repeat index must be within the bounds of the timings array" +
-                        " (timings.length=" + mTimings.length + ", index=" + mRepeat +")");
+                        "repeat index must be within the bounds of the timings array"
+                        + " (timings.length=" + mTimings.length + ", index=" + mRepeat + ")");
             }
         }
 
@@ -345,26 +424,26 @@
                 return false;
             }
             VibrationEffect.Waveform other = (VibrationEffect.Waveform) o;
-            return Arrays.equals(mTimings, other.mTimings) &&
-                Arrays.equals(mAmplitudes, other.mAmplitudes) &&
-                mRepeat == other.mRepeat;
+            return Arrays.equals(mTimings, other.mTimings)
+                && Arrays.equals(mAmplitudes, other.mAmplitudes)
+                && mRepeat == other.mRepeat;
         }
 
         @Override
         public int hashCode() {
             int result = 17;
-            result = 37 * Arrays.hashCode(mTimings);
-            result = 37 * Arrays.hashCode(mAmplitudes);
-            result = 37 * mRepeat;
+            result += 37 * Arrays.hashCode(mTimings);
+            result += 37 * Arrays.hashCode(mAmplitudes);
+            result += 37 * mRepeat;
             return result;
         }
 
         @Override
         public String toString() {
-            return "Waveform{mTimings=" + Arrays.toString(mTimings) +
-                ", mAmplitudes=" + Arrays.toString(mAmplitudes) +
-                ", mRepeat=" + mRepeat +
-                "}";
+            return "Waveform{mTimings=" + Arrays.toString(mTimings)
+                + ", mAmplitudes=" + Arrays.toString(mAmplitudes)
+                + ", mRepeat=" + mRepeat
+                + "}";
         }
 
         @Override
@@ -402,16 +481,20 @@
 
     /** @hide */
     public static class Prebaked extends VibrationEffect implements Parcelable {
-        private int mEffectId;
-        private boolean mFallback;
+        private final int mEffectId;
+        private final boolean mFallback;
+
+        private int mEffectStrength;
 
         public Prebaked(Parcel in) {
             this(in.readInt(), in.readByte() != 0);
+            mEffectStrength = in.readInt();
         }
 
         public Prebaked(int effectId, boolean fallback) {
             mEffectId = effectId;
             mFallback = fallback;
+            mEffectStrength = EffectStrength.MEDIUM;
         }
 
         public int getId() {
@@ -427,6 +510,39 @@
         }
 
         @Override
+        public long getDuration() {
+            return -1;
+        }
+
+        /**
+         * Set the effect strength of the prebaked effect.
+         */
+        public void setEffectStrength(int strength) {
+            if (!isValidEffectStrength(strength)) {
+                throw new IllegalArgumentException("Invalid effect strength: " + strength);
+            }
+            mEffectStrength = strength;
+        }
+
+        /**
+         * Set the effect strength.
+         */
+        public int getEffectStrength() {
+            return mEffectStrength;
+        }
+
+        private static boolean isValidEffectStrength(int strength) {
+            switch (strength) {
+                case EffectStrength.LIGHT:
+                case EffectStrength.MEDIUM:
+                case EffectStrength.STRONG:
+                    return true;
+                default:
+                    return false;
+            }
+        }
+
+        @Override
         public void validate() {
             switch (mEffectId) {
                 case EFFECT_CLICK:
@@ -437,6 +553,10 @@
                     throw new IllegalArgumentException(
                             "Unknown prebaked effect type (value=" + mEffectId + ")");
             }
+            if (!isValidEffectStrength(mEffectStrength)) {
+                throw new IllegalArgumentException(
+                        "Unknown prebaked effect strength (value=" + mEffectStrength + ")");
+            }
         }
 
         @Override
@@ -445,17 +565,25 @@
                 return false;
             }
             VibrationEffect.Prebaked other = (VibrationEffect.Prebaked) o;
-            return mEffectId == other.mEffectId && mFallback == other.mFallback;
+            return mEffectId == other.mEffectId
+                && mFallback == other.mFallback
+                && mEffectStrength == other.mEffectStrength;
         }
 
         @Override
         public int hashCode() {
-            return mEffectId;
+            int result = 17;
+            result += 37 * mEffectId;
+            result += 37 * mEffectStrength;
+            return result;
         }
 
         @Override
         public String toString() {
-            return "Prebaked{mEffectId=" + mEffectId + ", mFallback=" + mFallback + "}";
+            return "Prebaked{mEffectId=" + mEffectId
+                + ", mEffectStrength=" + mEffectStrength
+                + ", mFallback=" + mFallback
+                + "}";
         }
 
 
@@ -464,6 +592,7 @@
             out.writeInt(PARCEL_TOKEN_EFFECT);
             out.writeInt(mEffectId);
             out.writeByte((byte) (mFallback ? 1 : 0));
+            out.writeInt(mEffectStrength);
         }
 
         public static final Parcelable.Creator<Prebaked> CREATOR =
diff --git a/core/java/android/os/Vibrator.java b/core/java/android/os/Vibrator.java
index 8078fb8..f1f6f41 100644
--- a/core/java/android/os/Vibrator.java
+++ b/core/java/android/os/Vibrator.java
@@ -16,6 +16,7 @@
 
 package android.os;
 
+import android.annotation.IntDef;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemService;
 import android.app.ActivityThread;
@@ -23,6 +24,9 @@
 import android.media.AudioAttributes;
 import android.util.Log;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * Class that operates the vibrator on the device.
  * <p>
@@ -33,6 +37,40 @@
 public abstract class Vibrator {
     private static final String TAG = "Vibrator";
 
+    /**
+     * Vibration intensity: no vibrations.
+     * @hide
+     */
+    public static final int VIBRATION_INTENSITY_OFF = 0;
+
+    /**
+     * Vibration intensity: low.
+     * @hide
+     */
+    public static final int VIBRATION_INTENSITY_LOW = 1;
+
+    /**
+     * Vibration intensity: medium.
+     * @hide
+     */
+    public static final int VIBRATION_INTENSITY_MEDIUM = 2;
+
+    /**
+     * Vibration intensity: high.
+     * @hide
+     */
+    public static final int VIBRATION_INTENSITY_HIGH = 3;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = { "VIBRATION_INTENSITY_" }, value = {
+        VIBRATION_INTENSITY_OFF,
+        VIBRATION_INTENSITY_LOW,
+        VIBRATION_INTENSITY_MEDIUM,
+        VIBRATION_INTENSITY_HIGH
+    })
+    public @interface VibrationIntensity{}
+
     private final String mPackageName;
 
     /**
@@ -50,6 +88,22 @@
     }
 
     /**
+     * Get the default vibration intensity for haptic feedback.
+     * @hide
+     */
+    public int getDefaultHapticFeedbackIntensity() {
+        return VIBRATION_INTENSITY_MEDIUM;
+    }
+
+    /**
+     * Get the default vibration intensity for notifications and ringtones.
+     * @hide
+     */
+    public int getDefaultNotificationVibrationIntensity() {
+        return VIBRATION_INTENSITY_HIGH;
+    }
+
+    /**
      * Check whether the hardware has a vibrator.
      *
      * @return True if the hardware has a vibrator, else false.
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index e7fd59e..d96316a 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -738,7 +738,9 @@
     private static final String PATH_DOCUMENT = "document";
     private static final String PATH_CHILDREN = "children";
     private static final String PATH_SEARCH = "search";
-    private static final String PATH_TREE = "tree";
+    // TODO(b/72055774): make private again once ScopedAccessProvider is refactored
+    /** {@hide} */
+    public static final String PATH_TREE = "tree";
 
     private static final String PARAM_QUERY = "query";
     private static final String PARAM_MANAGE = "manage";
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index e957842..26495cd 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3175,6 +3175,43 @@
         private static final Validator VIBRATE_INPUT_DEVICES_VALIDATOR = BOOLEAN_VALIDATOR;
 
         /**
+         * The intensity of notification vibrations, if configurable.
+         *
+         * Not all devices are capable of changing their vibration intensity; on these devices
+         * there will likely be no difference between the various vibration intensities except for
+         * intensity 0 (off) and the rest.
+         *
+         * <b>Values:</b><br/>
+         * 0 - Vibration is disabled<br/>
+         * 1 - Weak vibrations<br/>
+         * 2 - Medium vibrations<br/>
+         * 3 - Strong vibrations
+         * @hide
+         */
+        public static final String NOTIFICATION_VIBRATION_INTENSITY =
+                "notification_vibration_intensity";
+
+        /**
+         * The intensity of haptic feedback vibrations, if configurable.
+         *
+         * Not all devices are capable of changing their feedback intensity; on these devices
+         * there will likely be no difference between the various vibration intensities except for
+         * intensity 0 (off) and the rest.
+         *
+         * <b>Values:</b><br/>
+         * 0 - Vibration is disabled<br/>
+         * 1 - Weak vibrations<br/>
+         * 2 - Medium vibrations<br/>
+         * 3 - Strong vibrations
+         * @hide
+         */
+        public static final String HAPTIC_FEEDBACK_INTENSITY =
+                "haptic_feedback_intensity";
+
+        private static final Validator VIBRATION_INTENSITY_VALIDATOR =
+                new SettingsValidators.InclusiveIntegerRangeValidator(0, 3);
+
+        /**
          * Ringer volume. This is used internally, changing this value will not
          * change the volume. See AudioManager.
          *
@@ -3995,7 +4032,9 @@
             LOCK_TO_APP_ENABLED,
             NOTIFICATION_SOUND,
             ACCELEROMETER_ROTATION,
-            SHOW_BATTERY_PERCENT
+            SHOW_BATTERY_PERCENT,
+            NOTIFICATION_VIBRATION_INTENSITY,
+            HAPTIC_FEEDBACK_INTENSITY,
         };
 
         /**
@@ -4136,6 +4175,8 @@
             VALIDATORS.put(MODE_RINGER_STREAMS_AFFECTED, MODE_RINGER_STREAMS_AFFECTED_VALIDATOR);
             VALIDATORS.put(MUTE_STREAMS_AFFECTED, MUTE_STREAMS_AFFECTED_VALIDATOR);
             VALIDATORS.put(VIBRATE_ON, VIBRATE_ON_VALIDATOR);
+            VALIDATORS.put(NOTIFICATION_VIBRATION_INTENSITY, VIBRATION_INTENSITY_VALIDATOR);
+            VALIDATORS.put(HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_VALIDATOR);
             VALIDATORS.put(RINGTONE, RINGTONE_VALIDATOR);
             VALIDATORS.put(NOTIFICATION_SOUND, NOTIFICATION_SOUND_VALIDATOR);
             VALIDATORS.put(ALARM_ALERT, ALARM_ALERT_VALIDATOR);
diff --git a/core/java/android/provider/SettingsSlicesContract.java b/core/java/android/provider/SettingsSlicesContract.java
new file mode 100644
index 0000000..f79d852
--- /dev/null
+++ b/core/java/android/provider/SettingsSlicesContract.java
@@ -0,0 +1,106 @@
+/*
+ * 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.provider;
+
+import android.content.ContentResolver;
+import android.net.Uri;
+
+/**
+ * Provides a contract for platform-supported Settings {@link android.app.slice.Slice Slices}.
+ * <p>
+ * Contains definitions for the supported {@link android.app.slice.SliceProvider SliceProvider}
+ * authority, authority {@link Uri}, and key constants.
+ * <p>
+ * {@link android.app.slice.Slice Slice} presenters interested in learning meta-data about the
+ * {@link android.app.slice.Slice Slice} should read the {@link android.app.slice.Slice Slice}
+ * object at runtime.
+ * <p>
+ * {@link Uri} builder example:
+ * <pre>
+ * Uri wifiActionUri = AUTHORITY_URI
+ *         .buildUpon()
+ *         .appendPath(PATH_SETTING_ACTION)
+ *         .appendPath(KEY_WIFI)
+ *         .build();
+ * Uri bluetoothIntentUri = AUTHORITY_URI
+ *         .buildUpon()
+ *         .appendPath(PATH_SETTING_INTENT)
+ *         .appendPath(KEY_BLUETOOTH)
+ *         .build();
+ * </pre>
+ */
+public class SettingsSlicesContract {
+    private SettingsSlicesContract() {
+    }
+
+    /**
+     * Authority for platform Settings Slices.
+     */
+    public static final String AUTHORITY = "android.settings.slices";
+
+    /**
+     * A content:// style uri to the Settings Slices authority, {@link #AUTHORITY}.
+     */
+    public static final Uri BASE_URI = new Uri.Builder()
+            .scheme(ContentResolver.SCHEME_CONTENT)
+            .authority(AUTHORITY)
+            .build();
+
+    /**
+     * {@link Uri} path indicating that the requested {@link android.app.slice.Slice Slice} should
+     * have inline controls for the corresponding setting.
+     * <p>
+     * This path will only contain Slices defined by keys in this class.
+     */
+    public static final String PATH_SETTING_ACTION = "action";
+
+    /**
+     * {@link Uri} path indicating that the requested {@link android.app.slice.Slice Slice} should
+     * be {@link android.content.Intent Intent}-only.
+     * <p>
+     * {@link android.app.slice.Slice Slices} with actions should use the {@link
+     * #PATH_SETTING_ACTION} path.
+     * <p>
+     * This path will only contain Slices defined by keys in this class
+     */
+    public static final String PATH_SETTING_INTENT = "intent";
+
+    /**
+     * {@link Uri} key for the Airplane Mode setting.
+     */
+    public static final String KEY_AIRPLANE_MODE = "airplane_mode";
+
+    /**
+     * {@link Uri} key for the Battery Saver setting.
+     */
+    public static final String KEY_BATTERY_SAVER = "battery_saver";
+
+    /**
+     * {@link Uri} key for the Bluetooth setting.
+     */
+    public static final String KEY_BLUETOOTH = "bluetooth";
+
+    /**
+     * {@link Uri} key for the Location setting.
+     */
+    public static final String KEY_LOCATION = "location";
+
+    /**
+     * {@link Uri} key for the Wi-fi setting.
+     */
+    public static final String KEY_WIFI = "wifi";
+}
diff --git a/core/java/android/se/omapi/Channel.java b/core/java/android/se/omapi/Channel.java
new file mode 100644
index 0000000..f0b9fa2d
--- /dev/null
+++ b/core/java/android/se/omapi/Channel.java
@@ -0,0 +1,251 @@
+/*
+ * 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.
+ */
+/*
+ * Copyright (c) 2015-2017, The Linux Foundation.
+ */
+/*
+ * Contributed by: Giesecke & Devrient GmbH.
+ */
+
+package android.se.omapi;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.io.IOException;
+
+/**
+ * Instances of this class represent an ISO/IEC 7816-4 channel opened to a
+ * Secure Element. It can be either a logical channel or the basic channel. They
+ * can be used to send APDUs to the secure element. Channels are opened by
+ * calling the Session.openBasicChannel(byte[]) or
+ * Session.openLogicalChannel(byte[]) methods.
+ *
+ * @see <a href="http://globalplatform.org">GlobalPlatform Open Mobile API</a>
+ */
+public class Channel {
+
+    private static final String TAG = "OMAPI.Channel";
+    private Session mSession;
+    private final ISecureElementChannel mChannel;
+    private final SEService mService;
+    private final Object mLock = new Object();
+
+    Channel(SEService service, Session session, ISecureElementChannel channel) {
+        if (service == null || session == null || channel == null) {
+            throw new IllegalArgumentException("Parameters cannot be null");
+        }
+        mService = service;
+        mSession = session;
+        mChannel = channel;
+    }
+
+    /**
+     * Closes this channel to the Secure Element. If the method is called when
+     * the channel is already closed, this method will be ignored. The close()
+     * method shall wait for completion of any pending transmit(byte[] command)
+     * before closing the channel.
+     */
+    public void close() {
+        if (!isClosed()) {
+            synchronized (mLock) {
+                try {
+                    mChannel.close();
+                } catch (Exception e) {
+                    Log.e(TAG, "Error closing channel", e);
+                }
+            }
+        }
+    }
+
+    /**
+     * Tells if this channel is closed.
+     *
+     * @return <code>true</code> if the channel is closed or in case of an error.
+     *         <code>false</code> otherwise.
+     */
+    public boolean isClosed() {
+        if (!mService.isConnected()) {
+            Log.e(TAG, "service not connected to system");
+            return true;
+        }
+        try {
+            return mChannel.isClosed();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Exception in isClosed()");
+            return true;
+        }
+    }
+
+    /**
+     * Returns a boolean telling if this channel is the basic channel.
+     *
+     * @return <code>true</code> if this channel is a basic channel. <code>false</code> if
+     *         this channel is a logical channel.
+     */
+    public boolean isBasicChannel() {
+        if (!mService.isConnected()) {
+            throw new IllegalStateException("service not connected to system");
+        }
+        try {
+            return mChannel.isBasicChannel();
+        } catch (RemoteException e) {
+            throw new IllegalStateException(e.getMessage());
+        }
+    }
+
+    /**
+     * Transmit an APDU command (as per ISO/IEC 7816-4) to the Secure Element. The
+     * underlying layers generate as many TPDUs as necessary to transport this APDU. The
+     * API shall ensure that all available data returned from Secure Element, including
+     * concatenated responses, are retrieved and made available to the calling application. If a
+     * warning status code is received the API wont check for further response data but will
+     * return all data received so far and the warning status code.<br>
+     * The transport part is invisible from the application. The generated response is the
+     * response of the APDU which means that all protocols related responses are handled
+     * inside the API or the underlying implementation.<br>
+     * The transmit method shall support extended length APDU commands independently of
+     * the coding within the ATR.<br>
+     * For status word '61 XX' the API or underlying implementation shall issue a GET
+     * RESPONSE command as specified by ISO 7816-4 standard with LE=XX; for the status
+     * word '6C XX', the API or underlying implementation shall reissue the input command
+     * with LE=XX. For other status words, the API (or underlying implementation) shall return
+     * the complete response including data and status word to the device application. The API
+     * (or underlying implementation) shall not handle internally the received status words. The
+     * channel shall not be closed even if the Secure Element answered with an error code.
+     * The system ensures the synchronization between all the concurrent calls to this method,
+     * and that only one APDU will be sent at a time, irrespective of the number of TPDUs that
+     * might be required to transport it to the SE. The entire APDU communication to this SE is
+     * locked to the APDU.<br>
+     * The channel information in the class byte in the APDU will be ignored. The system will
+     * add any required information to ensure the APDU is transported on this channel.
+     * The only restrictions on the set of commands that can be sent is defined below, the API
+     * implementation shall be able to send all other commands: <br>
+     * <ul>
+     * <li>MANAGE_CHANNEL commands are not allowed.</li>
+     * <li>SELECT by DF Name (p1=04) are not allowed.</li>
+     * <li>CLA bytes with channel numbers are de-masked.</li>
+     * </ul>
+     *
+     * @param command the APDU command to be transmitted, as a byte array.
+     *
+     * @return the response received, as a byte array. The returned byte array contains the data
+     * bytes in the following order:
+     * [&lt;first data byte&gt;, ..., &lt;last data byte&gt;, &lt;sw1&gt;, &lt;sw2&gt;]
+     *
+     * @throws IOException if there is a communication problem to the reader or the Secure Element.
+     * @throws IllegalStateException if the channel is used after being closed.
+     * @throws IllegalArgumentException if the command byte array is less than 4 bytes long.
+     * @throws IllegalArgumentException if Lc byte is inconsistent with length of the byte array.
+     * @throws IllegalArgumentException if CLA byte is invalid according to [2] (0xff).
+     * @throws IllegalArgumentException if INS byte is invalid according to [2] (0x6x or 0x9x).
+     * @throws SecurityException if the command is filtered by the security policy.
+     * @throws NullPointerException if command is NULL.
+     */
+    public @NonNull byte[] transmit(byte[] command) throws IOException {
+        if (!mService.isConnected()) {
+            throw new IllegalStateException("service not connected to system");
+        }
+        synchronized (mLock) {
+            try {
+                byte[] response = mChannel.transmit(command);
+                if (response == null) {
+                    throw new IOException("Error in communicating with Secure Element");
+                }
+                return response;
+            } catch (RemoteException e) {
+                throw new IOException(e.getMessage());
+            }
+        }
+    }
+
+    /**
+     * Get the session that has opened this channel.
+     *
+     * @return the session object this channel is bound to.
+     */
+    public @NonNull Session getSession() {
+        return mSession;
+    }
+
+    /**
+     * Returns the data as received from the application select command inclusively the status word
+     * received at applet selection.
+     * The returned byte array contains the data bytes in the following order:
+     * [&lt;first data byte&gt;, ..., &lt;last data byte&gt;, &lt;sw1&gt;, &lt;sw2&gt;]
+     * @return The data as returned by the application select command inclusively the status word.
+     * Only the status word if the application select command has no returned data.
+     * Returns null if an application select command has not been performed or the selection
+     * response can not be retrieved by the reader implementation.
+     */
+    public @Nullable byte[] getSelectResponse() {
+        if (!mService.isConnected()) {
+            throw new IllegalStateException("service not connected to system");
+        }
+
+        byte[] response;
+        try {
+            response = mChannel.getSelectResponse();
+        } catch (RemoteException e) {
+            throw new IllegalStateException(e.getMessage());
+        }
+
+        if (response != null && response.length == 0) {
+            response = null;
+        }
+        return response;
+    }
+
+    /**
+     * Performs a selection of the next Applet on this channel that matches to the partial AID
+     * specified in the openBasicChannel(byte[] aid) or openLogicalChannel(byte[] aid) method.
+     * This mechanism can be used by a device application to iterate through all Applets
+     * matching to the same partial AID.
+     * If selectNext() returns true a new Applet was successfully selected on this channel.
+     * If no further Applet exists with matches to the partial AID this method returns false
+     * and the already selected Applet stays selected. <br>
+     *
+     * Since the API cannot distinguish between a partial and full AID the API shall rely on the
+     * response of the Secure Element for the return value of this method. <br>
+     * The implementation of the underlying SELECT command within this method shall use
+     * the same values as the corresponding openBasicChannel(byte[] aid) or
+     * openLogicalChannel(byte[] aid) command with the option: <br>
+     * P2='02' (Next occurrence) <br>
+     * The select response stored in the Channel object shall be updated with the APDU
+     * response of the SELECT command.
+
+     * @return <code>true</code> if new Applet was selected on this channel.
+               <code>false</code> he already selected Applet stays selected on this channel.
+     *
+     * @throws IOException if there is a communication problem to the reader or the Secure Element.
+     * @throws IllegalStateException if the channel is used after being closed.
+     * @throws UnsupportedOperationException if this operation is not supported by the card.
+     */
+    public boolean selectNext() throws IOException {
+        if (!mService.isConnected()) {
+            throw new IllegalStateException("service not connected to system");
+        }
+        try {
+            synchronized (mLock) {
+                return mChannel.selectNext();
+            }
+        } catch (RemoteException e) {
+            throw new IOException(e.getMessage());
+        }
+    }
+}
diff --git a/core/java/android/se/omapi/ISecureElementChannel.aidl b/core/java/android/se/omapi/ISecureElementChannel.aidl
new file mode 100644
index 0000000..4ae57ab
--- /dev/null
+++ b/core/java/android/se/omapi/ISecureElementChannel.aidl
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+/*
+ * Contributed by: Giesecke & Devrient GmbH.
+ */
+
+package android.se.omapi;
+
+import android.se.omapi.ISecureElementSession;
+
+/** @hide */
+interface ISecureElementChannel {
+
+    /**
+     * Closes the specified connection and frees internal resources.
+     * A logical channel will be closed.
+     */
+    void close();
+
+    /**
+     * Tells if this channel is closed.
+     *
+     * @return <code>true</code> if the channel is closed,
+     *         <code>false</code> otherwise.
+     */
+    boolean isClosed();
+
+    /**
+     * Returns a boolean telling if this channel is the basic channel.
+     *
+     * @return <code>true</code> if this channel is a basic channel.
+     *         <code>false</code> if this channel is a logical channel.
+     */
+    boolean isBasicChannel();
+
+     /**
+     * Returns the data as received from the application select command
+     * inclusively the status word. The returned byte array contains the data
+     * bytes in the following order:
+     * [<first data byte>, ..., <last data byte>, <sw1>, <sw2>]
+     */
+    byte[] getSelectResponse();
+
+    /**
+     * Transmits the specified command APDU and returns the response APDU.
+     * MANAGE channel commands are not supported.
+     * Selection of applets is not supported in logical channels.
+     */
+    byte[] transmit(in byte[] command);
+
+    /**
+     * Performs a selection of the next Applet on this channel that matches to
+     * the partial AID specified in the openBasicChannel(byte[] aid) or
+     * openLogicalChannel(byte[] aid) method. This mechanism can be used by a
+     * device application to iterate through all Applets matching to the same
+     * partial AID.
+     * If selectNext() returns true a new Applet was successfully selected on
+     * this channel.
+     * If no further Applet exists with matches to the partial AID this method
+     * returns false and the already selected Applet stays selected.
+     *
+     * @return <code>true</code> if new Applet was successfully selected.
+     *         <code>false</code> if no further Applet exists which matches the
+     *         partial AID.
+     */
+    boolean selectNext();
+}
diff --git a/core/proto/android/os/batterymanager.proto b/core/java/android/se/omapi/ISecureElementListener.aidl
similarity index 61%
copy from core/proto/android/os/batterymanager.proto
copy to core/java/android/se/omapi/ISecureElementListener.aidl
index 669bf2d..3a99d63 100644
--- a/core/proto/android/os/batterymanager.proto
+++ b/core/java/android/se/omapi/ISecureElementListener.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * 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.
@@ -13,17 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+/*
+ * Contributed by: Giesecke & Devrient GmbH.
+ */
 
-syntax = "proto2";
-package android.os;
+package android.se.omapi;
 
-option java_multiple_files = true;
-
-message BatteryManagerProto {
-    enum PlugType {
-        PLUG_TYPE_NONE = 0;
-        PLUG_TYPE_AC = 1;
-        PLUG_TYPE_USB = 2;
-        PLUG_TYPE_WIRELESS = 4;
-    }
+/**
+ * Interface to receive call-backs when the service is connected.
+ */
+interface ISecureElementListener {
+  /**
+   * Called by the framework when the service is connected.
+   */
+  void serviceConnected();
 }
diff --git a/core/java/android/se/omapi/ISecureElementReader.aidl b/core/java/android/se/omapi/ISecureElementReader.aidl
new file mode 100644
index 0000000..a312c44
--- /dev/null
+++ b/core/java/android/se/omapi/ISecureElementReader.aidl
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+/*
+ * Contributed by: Giesecke & Devrient GmbH.
+ */
+
+package android.se.omapi;
+
+import android.se.omapi.ISecureElementSession;
+
+/** @hide */
+interface ISecureElementReader {
+
+    /**
+     * Returns true if a card is present in the specified reader.
+     * Returns false if a card is not present in the specified reader.
+     */
+    boolean isSecureElementPresent();
+
+    /**
+     * Connects to a secure element in this reader. <br>
+     * This method prepares (initialises) the Secure Element for communication
+     * before the Session object is returned (e.g. powers the Secure Element by
+     * ICC ON if its not already on). There might be multiple sessions opened at
+     * the same time on the same reader. The system ensures the interleaving of
+     * APDUs between the respective sessions.
+     *
+     * @return a Session object to be used to create Channels.
+     */
+    ISecureElementSession openSession();
+
+    /**
+     * Close all the sessions opened on this reader. All the channels opened by
+     * all these sessions will be closed.
+     */
+    void closeSessions();
+
+}
diff --git a/core/java/android/se/omapi/ISecureElementService.aidl b/core/java/android/se/omapi/ISecureElementService.aidl
new file mode 100644
index 0000000..4fa799e
--- /dev/null
+++ b/core/java/android/se/omapi/ISecureElementService.aidl
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+/*
+ * Copyright (c) 2015-2017, The Linux Foundation.
+ */
+/*
+ * Contributed by: Giesecke & Devrient GmbH.
+ */
+
+package android.se.omapi;
+
+import android.se.omapi.ISecureElementReader;
+
+/**
+ * SecureElement service interface.
+ * @hide
+ */
+interface ISecureElementService {
+
+    /**
+     * Returns the friendly names of available Secure Element readers.
+     */
+    String[] getReaders();
+
+    /**
+     * Returns SecureElement Service reader object to the given name.
+     */
+    ISecureElementReader getReader(String reader);
+
+    /**
+     * Checks if the application defined by the package name is allowed to
+     * receive NFC transaction events for the defined AID.
+     */
+    boolean[] isNFCEventAllowed(String reader, in byte[] aid,
+            in String[] packageNames);
+
+}
diff --git a/core/java/android/se/omapi/ISecureElementSession.aidl b/core/java/android/se/omapi/ISecureElementSession.aidl
new file mode 100644
index 0000000..8ea599f
--- /dev/null
+++ b/core/java/android/se/omapi/ISecureElementSession.aidl
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+/*
+ * Copyright (c) 2015-2017, The Linux Foundation.
+ */
+/*
+ * Contributed by: Giesecke & Devrient GmbH.
+ */
+
+package android.se.omapi;
+
+import android.se.omapi.ISecureElementChannel;
+import android.se.omapi.ISecureElementReader;
+import android.se.omapi.ISecureElementListener;
+
+/** @hide */
+interface ISecureElementSession {
+
+    /**
+     * Returns the ATR of the connected card or null if the ATR is not available
+     */
+    byte[] getAtr();
+
+    /**
+     * Close the connection with the Secure Element. This will close any
+     * channels opened by this application with this Secure Element.
+     */
+    void close();
+
+    /**
+     * Close any channel opened on this session.
+     */
+    void closeChannels();
+
+
+    /**
+     * Tells if this session is closed.
+     *
+     * @return <code>true</code> if the session is closed, false otherwise.
+     */
+    boolean isClosed();
+
+    /**
+     * Opens a connection using the basic channel of the card in the
+     * specified reader and returns a channel handle. Selects the specified
+     * applet if aid != null.
+     * Logical channels cannot be opened with this connection.
+     * Use interface method openLogicalChannel() to open a logical channel.
+     */
+    ISecureElementChannel openBasicChannel(in byte[] aid, in byte p2,
+            ISecureElementListener listener);
+
+    /**
+     * Opens a connection using the next free logical channel of the card in the
+     * specified reader. Selects the specified applet.
+     * Selection of other applets with this connection is not supported.
+     */
+    ISecureElementChannel openLogicalChannel(in byte[] aid, in byte p2,
+            ISecureElementListener listener);
+}
diff --git a/core/java/android/se/omapi/Reader.java b/core/java/android/se/omapi/Reader.java
new file mode 100644
index 0000000..9f15739
--- /dev/null
+++ b/core/java/android/se/omapi/Reader.java
@@ -0,0 +1,151 @@
+/*
+ * 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.
+ */
+/*
+ * Copyright (c) 2015-2017, The Linux Foundation.
+ */
+/*
+ * Contributed by: Giesecke & Devrient GmbH.
+ */
+
+package android.se.omapi;
+
+import android.annotation.NonNull;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.io.IOException;
+
+/**
+ * Instances of this class represent Secure Element Readers supported to this
+ * device. These Readers can be physical devices or virtual devices. They can be
+ * removable or not. They can contain Secure Element that can or cannot be
+ * removed.
+ *
+ * @see <a href="http://globalplatform.org">GlobalPlatform Open Mobile API</a>
+ */
+public class Reader {
+
+    private static final String TAG = "OMAPI.Reader";
+    private final String mName;
+    private final SEService mService;
+    private ISecureElementReader mReader;
+    private final Object mLock = new Object();
+
+
+    Reader(SEService service, String name, ISecureElementReader reader) throws
+            IOException {
+        if (reader == null || service == null || name == null) {
+            throw new IllegalArgumentException("Parameters cannot be null");
+        }
+        mName = name;
+        mService = service;
+        mReader = reader;
+    }
+
+    /**
+     * Return the name of this reader.
+     * <ul>
+     * <li>If this reader is a SIM reader, then its name must be "SIM[Slot]".</li>
+     * <li>If the reader is a SD or micro SD reader, then its name must be "SD[Slot]"</li>
+     * <li>If the reader is a embedded SE reader, then its name must be "eSE[Slot]"</li>
+     * </ul>
+     * Slot is a decimal number without leading zeros. The Numbering must start with 1
+     * (e.g. SIM1, SIM2, ... or SD1, SD2, ... or eSE1, eSE2, ...).
+     * The slot number “1” for a reader is optional
+     * (SIM and SIM1 are both valid for the first SIM-reader,
+     * but if there are two readers then the second reader must be named SIM2).
+     * This applies also for other SD or SE readers.
+     *
+     * @return the reader name, as a String.
+     */
+    public @NonNull String getName() {
+        return mName;
+    }
+
+    /**
+     * Connects to a Secure Element in this reader. <br>
+     * This method prepares (initialises) the Secure Element for communication
+     * before the Session object is returned (e.g. powers the Secure Element by
+     * ICC ON if its not already on). There might be multiple sessions opened at
+     * the same time on the same reader. The system ensures the interleaving of
+     * APDUs between the respective sessions.
+     *
+     * @throws IOException if something went wrong with the communicating to the
+     *             Secure Element or the reader.
+     * @return a Session object to be used to create Channels.
+     */
+    public @NonNull Session openSession() throws IOException {
+        if (!mService.isConnected()) {
+            throw new IllegalStateException("service is not connected");
+        }
+
+        synchronized (mLock) {
+            ISecureElementSession session;
+            try {
+                session = mReader.openSession();
+            } catch (RemoteException e) {
+                throw new IOException(e.getMessage());
+            }
+            if (session == null) {
+                throw new IOException("service session is null.");
+            }
+            return new Session(mService, session, this);
+        }
+    }
+
+    /**
+     * Check if a Secure Element is present in this reader.
+     *
+     * @throws IllegalStateException if the service is not connected
+     * @return <code>true</code> if the SE is present, <code>false</code> otherwise.
+     */
+    public boolean isSecureElementPresent() {
+        if (!mService.isConnected()) {
+            throw new IllegalStateException("service is not connected");
+        }
+
+        try {
+            return mReader.isSecureElementPresent();
+        } catch (RemoteException e) {
+            throw new IllegalStateException("Error in isSecureElementPresent()");
+        }
+    }
+
+    /**
+     * Return the Secure Element service this reader is bound to.
+     *
+     * @return the SEService object.
+     */
+    public @NonNull SEService getSEService() {
+        return mService;
+    }
+
+    /**
+     * Close all the sessions opened on this reader.
+     * All the channels opened by all these sessions will be closed.
+     */
+    public void closeSessions() {
+        if (!mService.isConnected()) {
+            Log.e(TAG, "service is not connected");
+            return;
+        }
+        synchronized (mLock) {
+            try {
+                mReader.closeSessions();
+            } catch (RemoteException ignore) { }
+        }
+    }
+}
diff --git a/core/java/android/se/omapi/SEService.java b/core/java/android/se/omapi/SEService.java
new file mode 100644
index 0000000..1e37277d
--- /dev/null
+++ b/core/java/android/se/omapi/SEService.java
@@ -0,0 +1,222 @@
+/*
+ * 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.
+ */
+/*
+ * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ */
+/*
+ * Contributed by: Giesecke & Devrient GmbH.
+ */
+
+package android.se.omapi;
+
+import android.annotation.NonNull;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.HashMap;
+
+/**
+ * The SEService realises the communication to available Secure Elements on the
+ * device. This is the entry point of this API. It is used to connect to the
+ * infrastructure and get access to a list of Secure Element Readers.
+ *
+ * @see <a href="http://simalliance.org">SIMalliance Open Mobile API  v3.0</a>
+ */
+public class SEService {
+
+    private static final String TAG = "OMAPI.SEService";
+
+    private final Object mLock = new Object();
+
+    /** The client context (e.g. activity). */
+    private final Context mContext;
+
+    /** The backend system. */
+    private volatile ISecureElementService mSecureElementService;
+
+    /**
+     * Class for interacting with the main interface of the backend.
+     */
+    private ServiceConnection mConnection;
+
+    /**
+     * Collection of available readers
+     */
+    private final HashMap<String, Reader> mReaders = new HashMap<String, Reader>();
+
+    /**
+     * Listener object that allows the notification of the caller if this
+     * SEService could be bound to the backend.
+     */
+    private ISecureElementListener mSEListener;
+
+    /**
+     * Establishes a new connection that can be used to connect to all the
+     * Secure Elements available in the system. The connection process can be
+     * quite long, so it happens in an asynchronous way. It is usable only if
+     * the specified listener is called or if isConnected() returns
+     * <code>true</code>. <br>
+     * The call-back object passed as a parameter will have its
+     * serviceConnected() method called when the connection actually happen.
+     *
+     * @param context
+     *            the context of the calling application. Cannot be
+     *            <code>null</code>.
+     * @param listener
+     *            a ISecureElementListener object. Can be <code>null</code>.
+     */
+    public SEService(Context context, ISecureElementListener listener) {
+
+        if (context == null) {
+            throw new NullPointerException("context must not be null");
+        }
+
+        mContext = context;
+        mSEListener = listener;
+
+        mConnection = new ServiceConnection() {
+
+            public synchronized void onServiceConnected(
+                    ComponentName className, IBinder service) {
+
+                mSecureElementService = ISecureElementService.Stub.asInterface(service);
+                if (mSEListener != null) {
+                    try {
+                        mSEListener.serviceConnected();
+                    } catch (RemoteException ignore) { }
+                }
+                Log.i(TAG, "Service onServiceConnected");
+            }
+
+            public void onServiceDisconnected(ComponentName className) {
+                mSecureElementService = null;
+                Log.i(TAG, "Service onServiceDisconnected");
+            }
+        };
+
+        Intent intent = new Intent(ISecureElementService.class.getName());
+        intent.setClassName("com.android.se",
+                            "com.android.se.SecureElementService");
+        boolean bindingSuccessful =
+                mContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
+        if (bindingSuccessful) {
+            Log.i(TAG, "bindService successful");
+        }
+    }
+
+    /**
+     * Tells whether or not the service is connected.
+     *
+     * @return <code>true</code> if the service is connected.
+     */
+    public boolean isConnected() {
+        return mSecureElementService != null;
+    }
+
+    /**
+     * Returns the list of available Secure Element readers.
+     * There must be no duplicated objects in the returned list.
+     * All available readers shall be listed even if no card is inserted.
+     *
+     * @return The readers list, as an array of Readers. If there are no
+     * readers the returned array is of length 0.
+     */
+    public @NonNull Reader[] getReaders() {
+        if (mSecureElementService == null) {
+            throw new IllegalStateException("service not connected to system");
+        }
+        String[] readerNames;
+        try {
+            readerNames = mSecureElementService.getReaders();
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+
+        Reader[] readers = new Reader[readerNames.length];
+        int i = 0;
+        for (String readerName : readerNames) {
+            if (mReaders.get(readerName) == null) {
+                try {
+                    mReaders.put(readerName, new Reader(this, readerName,
+                            getReader(readerName)));
+                    readers[i++] = mReaders.get(readerName);
+                } catch (Exception e) {
+                    Log.e(TAG, "Error adding Reader: " + readerName, e);
+                }
+            } else {
+                readers[i++] = mReaders.get(readerName);
+            }
+        }
+        return readers;
+    }
+
+    /**
+     * Releases all Secure Elements resources allocated by this SEService
+     * (including any binding to an underlying service).
+     * As a result isConnected() will return false after shutdown() was called.
+     * After this method call, the SEService object is not connected.
+     * It is recommended to call this method in the termination method of the calling application
+     * (or part of this application) which is bound to this SEService.
+     */
+    public void shutdown() {
+        synchronized (mLock) {
+            if (mSecureElementService != null) {
+                for (Reader reader : mReaders.values()) {
+                    try {
+                        reader.closeSessions();
+                    } catch (Exception ignore) { }
+                }
+            }
+            try {
+                mContext.unbindService(mConnection);
+            } catch (IllegalArgumentException e) {
+                // Do nothing and fail silently since an error here indicates
+                // that binding never succeeded in the first place.
+            }
+            mSecureElementService = null;
+        }
+    }
+
+    /**
+     * Returns the version of the OpenMobile API specification this
+     * implementation is based on.
+     *
+     * @return String containing the OpenMobile API version (e.g. "3.0").
+     */
+    public String getVersion() {
+        return "3.2";
+    }
+
+    @NonNull ISecureElementListener getListener() {
+        return mSEListener;
+    }
+
+    /**
+     * Obtain a Reader instance from the SecureElementService
+     */
+    private @NonNull ISecureElementReader getReader(String name) {
+        try {
+            return mSecureElementService.getReader(name);
+        } catch (RemoteException e) {
+            throw new IllegalStateException(e.getMessage());
+        }
+    }
+}
diff --git a/core/java/android/se/omapi/Session.java b/core/java/android/se/omapi/Session.java
new file mode 100644
index 0000000..bb2a032
--- /dev/null
+++ b/core/java/android/se/omapi/Session.java
@@ -0,0 +1,347 @@
+/*
+ * 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.
+ */
+/*
+ * Copyright (c) 2017, The Linux Foundation.
+ */
+/*
+ * Contributed by: Giesecke & Devrient GmbH.
+ */
+
+package android.se.omapi;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.io.IOException;
+import java.util.NoSuchElementException;
+
+/**
+ * Instances of this class represent a connection session to one of the Secure
+ * Elements available on the device. These objects can be used to get a
+ * communication channel with an Applet in the Secure Element.
+ * This channel can be the basic channel or a logical channel.
+ *
+ * @see <a href="http://simalliance.org">SIMalliance Open Mobile API  v3.0</a>
+ */
+public class Session {
+
+    private final Object mLock = new Object();
+    private final SEService mService;
+    private final Reader mReader;
+    private final ISecureElementSession mSession;
+    private static final String TAG = "OMAPI.Session";
+
+    Session(SEService service, ISecureElementSession session, Reader reader) {
+        if (service == null || reader == null || session == null) {
+            throw new IllegalArgumentException("Parameters cannot be null");
+        }
+        mService = service;
+        mReader = reader;
+        mSession = session;
+    }
+
+    /**
+     * Get the reader that provides this session.
+     *
+     * @return The Reader object.
+     */
+    public @NonNull Reader getReader() {
+        return mReader;
+    }
+
+    /**
+     * Get the Answer to Reset of this Secure Element. <br>
+     * The returned byte array can be null if the ATR for this Secure Element is
+     * not available.
+     *
+     * @throws IllegalStateException if there was an error connecting to SE or
+     *                               if the service was not connected.
+     * @return the ATR as a byte array or null.
+     */
+    public @Nullable byte[] getATR() {
+        if (!mService.isConnected()) {
+            throw new IllegalStateException("service not connected to system");
+        }
+        try {
+            return mSession.getAtr();
+        } catch (RemoteException e) {
+            throw new IllegalStateException(e.getMessage());
+        }
+    }
+
+    /**
+     * Close the connection with the Secure Element. This will close any
+     * channels opened by this application with this Secure Element.
+     */
+    public void close() {
+        if (!mService.isConnected()) {
+            Log.e(TAG, "service not connected to system");
+            return;
+        }
+        synchronized (mLock) {
+            try {
+                mSession.close();
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error closing session", e);
+            }
+        }
+    }
+
+    /**
+     * Tells if this session is closed.
+     *
+     * @return <code>true</code> if the session is closed, false otherwise.
+     */
+    public boolean isClosed() {
+        try {
+            return mSession.isClosed();
+        } catch (RemoteException e) {
+            // If there was an error here, then the session is considered close
+            return true;
+        }
+    }
+
+    /**
+     * Close any channel opened on this session.
+     */
+    public void closeChannels() {
+        if (!mService.isConnected()) {
+            Log.e(TAG, "service not connected to system");
+            return;
+        }
+
+        synchronized (mLock) {
+            try {
+                mSession.closeChannels();
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error closing channels", e);
+            }
+        }
+    }
+
+    /**
+     * Get an access to the basic channel, as defined in the ISO/IEC 7816-4 specification (the
+     * one that has number 0). The obtained object is an instance of the Channel class.
+     * If the AID is null, it means no Applet is to be selected on this channel and the default
+     * Applet is used. If the AID is defined then the corresponding Applet is selected.
+     * Once this channel has been opened by a device application, it is considered as "locked"
+     * by this device application, and other calls to this method will return null, until the
+     * channel is closed. Some Secure Elements (like the UICC) might always keep the basic channel
+     * locked (i.e. return null to applications), to prevent access to the basic channel, while
+     * some other might return a channel object implementing some kind of filtering on the
+     * commands, restricting the set of accepted command to a smaller set.
+     * It is recommended for the UICC to reject the opening of the basic channel to a specific
+     * applet, by always answering null to such a request.
+     * For other Secure Elements, the recommendation is to accept opening the basic channel
+     * on the default applet until another applet is selected on the basic channel. As there is no
+     * other way than a reset to select again the default applet, the implementation of the
+     * transport API should guarantee that the openBasicChannel(null) command will return
+     * null until a reset occurs.
+     * With previous release (V2.05) it was not possible to set P2 value, this value was always
+     * set to '00'.Except for specific needs it is recommended to keep P2 to '00'. It is
+     * recommended that the device allows all values for P2, however only the following values
+     * are mandatory: '00', '04', '08', '0C'(as defined in [2])
+     * The implementation of the underlying SELECT command within this method shall be
+     * based on ISO 7816-4 with following options:
+     * <ul>
+     * <li>CLA = '00'</li>
+     * <li>INS = 'A4'</li>
+     * <li>P1 = '04' (Select by DF name/application identifier)</li>
+     * </ul>
+     *
+     * The select response data can be retrieved with byte[] getSelectResponse().
+     * The API shall handle received status word as follow. If the status word indicates that the
+     * Secure Element was able to open a channel (e.g. status word '90 00' or status words
+     * referencing a warning in ISO-7816-4: '62 XX' or '63 XX') the API shall keep the
+     * channel opened and the next getSelectResponse() shall return the received status
+     * word.
+     * Other received status codes indicating that the Secure Element was able not to open a
+     * channel shall be considered as an error and the corresponding channel shall not be
+     * opened.
+     * The function without P2 as parameter is provided for backwards compatibility and will
+     * fall back to a select command with P2='00'.
+     *
+     * @param aid the AID of the Applet to be selected on this channel, as a
+     *            byte array, or null if no Applet is to be selected.
+     * @param p2 the P2 parameter of the SELECT APDU executed on this channel.
+     * @throws IOException if there is a communication problem to the reader or
+     *             the Secure Element.
+     * @throws IllegalStateException if the Secure Element session is used after
+     *             being closed.
+     * @throws IllegalArgumentException if the aid's length is not within 5 to
+     *             16 (inclusive).
+     * @throws SecurityException if the calling application cannot be granted
+     *             access to this AID or the default Applet on this
+     *             session.
+     * @throws NoSuchElementException if the AID on the Secure Element is not available or cannot be
+     *             selected.
+     * @throws UnsupportedOperationException if the given P2 parameter is not
+     *             supported by the device
+     * @return an instance of Channel if available or null.
+     */
+    public @Nullable Channel openBasicChannel(byte[] aid, byte p2) throws IOException {
+        if (!mService.isConnected()) {
+            throw new IllegalStateException("service not connected to system");
+        }
+
+        synchronized (mLock) {
+            try {
+                ISecureElementChannel channel = mSession.openBasicChannel(aid, p2,
+                        mReader.getSEService().getListener());
+                if (channel == null) {
+                    return null;
+                }
+                return new Channel(mService, this, channel);
+            } catch (RemoteException e) {
+                throw new IOException(e.getMessage());
+            }
+        }
+    }
+
+    /**
+     * This method is provided to ease the development of mobile application and for compliancy
+     * with existing applications.
+     * This method is equivalent to openBasicChannel(aid, P2=0x00)
+     *
+     * @param aid the AID of the Applet to be selected on this channel, as a
+     *            byte array, or null if no Applet is to be selected.
+     * @throws IOException if there is a communication problem to the reader or
+     *             the Secure Element.
+     * @throws IllegalStateException if the Secure Element session is used after
+     *             being closed.
+     * @throws IllegalArgumentException if the aid's length is not within 5 to
+     *             16 (inclusive).
+     * @throws SecurityException if the calling application cannot be granted
+     *             access to this AID or the default Applet on this
+     *             session.
+     * @throws NoSuchElementException if the AID on the Secure Element is not available or cannot be
+     *             selected.
+     * @throws UnsupportedOperationException if the given P2 parameter is not
+     *             supported by the device
+     * @return an instance of Channel if available or null.
+     */
+    public @Nullable Channel openBasicChannel(byte[] aid) throws IOException {
+        return openBasicChannel(aid, (byte) 0x00);
+    }
+
+    /**
+     * Open a logical channel with the Secure Element, selecting the Applet represented by
+     * the given AID. If the AID is null, which means no Applet is to be selected on this
+     * channel, the default Applet is used. It's up to the Secure Element to choose which
+     * logical channel will be used.
+     * With previous release (V2.05) it was not possible to set P2 value, this value was always
+     * set to '00'.Except for specific needs it is recommended to keep P2 to '00'. It is
+     * recommended that the device allows all values for P2, however only the following values
+     * are mandatory: '00', '04', '08', '0C'(as defined in [2])
+     * The implementation of the underlying SELECT command within this method shall be
+     * based on ISO 7816-4 with following options:
+     *
+     * <ul>
+     * <li>CLA = '01' to '03', '40 to 4F'</li>
+     * <li>INS = 'A4'</li>
+     * <li>P1 = '04' (Select by DF name/application identifier)</li>
+     * </ul>
+     *
+     * The select response data can be retrieved with byte[] getSelectResponse().
+     * The API shall handle received status word as follow. If the status word indicates that the
+     * Secure Element was able to open a channel (e.g. status word '90 00' or status words
+     * referencing a warning in ISO-7816-4: '62 XX' or '63 XX') the API shall keep the
+     * channel opened and the next getSelectResponse() shall return the received status
+     * word.
+     * Other received status codes indicating that the Secure Element was able not to open a
+     * channel shall be considered as an error and the corresponding channel shall not be
+     * opened.
+     * In case of UICC it is recommended for the API to reject the opening of the logical
+     * channel without a specific AID, by always answering null to such a request.
+     * The function without P2 as parameter is provided for backwards compatibility and will
+     * fall back to a select command with P2=00.
+     *
+     * @param aid the AID of the Applet to be selected on this channel, as a
+     *            byte array.
+     * @param p2 the P2 parameter of the SELECT APDU executed on this channel.
+     * @throws IOException if there is a communication problem to the reader or
+     *             the Secure Element.
+     * @throws IllegalStateException if the Secure Element is used after being
+     *             closed.
+     * @throws IllegalArgumentException if the aid's length is not within 5 to
+     *             16 (inclusive).
+     * @throws SecurityException if the calling application cannot be granted
+     *             access to this AID or the default Applet on this
+     *             session.
+     * @throws NoSuchElementException if the AID on the Secure Element is not
+     *             available or cannot be selected or a logical channel is already
+     *             open to a non-multiselectable Applet.
+     * @throws UnsupportedOperationException if the given P2 parameter is not
+     *             supported by the device.
+     * @return an instance of Channel. Null if the Secure Element is unable to
+     *         provide a new logical channel.
+     */
+    public @Nullable Channel openLogicalChannel(byte[] aid, byte p2) throws IOException {
+
+        if ((mReader.getName().startsWith("SIM")) && (aid == null)) {
+            Log.e(TAG, "NULL AID not supported on " + mReader.getName());
+            return null;
+        }
+
+        if (!mService.isConnected()) {
+            throw new IllegalStateException("service not connected to system");
+        }
+        synchronized (mLock) {
+            try {
+                ISecureElementChannel channel = mSession.openLogicalChannel(
+                        aid,
+                        p2,
+                        mReader.getSEService().getListener());
+                if (channel == null) {
+                    return null;
+                }
+                return new Channel(mService, this, channel);
+            } catch (RemoteException e) {
+                throw new IOException(e.getMessage());
+            }
+        }
+    }
+
+    /**
+     * This method is provided to ease the development of mobile application and for compliancy
+     * with existing applications.
+     * This method is equivalent to openLogicalChannel(aid, P2=0x00)
+     *
+     * @param aid the AID of the Applet to be selected on this channel, as a
+     *            byte array.
+     * @throws IOException if there is a communication problem to the reader or
+     *             the Secure Element.
+     * @throws IllegalStateException if the Secure Element is used after being
+     *             closed.
+     * @throws IllegalArgumentException if the aid's length is not within 5 to
+     *             16 (inclusive).
+     * @throws SecurityException if the calling application cannot be granted
+     *             access to this AID or the default Applet on this
+     *             session.
+     * @throws NoSuchElementException if the AID on the Secure Element is not
+     *             available or cannot be selected or a logical channel is already
+     *             open to a non-multiselectable Applet.
+     * @throws UnsupportedOperationException if the given P2 parameter is not
+     *             supported by the device.
+     * @return an instance of Channel. Null if the Secure Element is unable to
+     *         provide a new logical channel.
+     */
+    public @Nullable Channel openLogicalChannel(byte[] aid) throws IOException {
+        return openLogicalChannel(aid, (byte) 0x00);
+    }
+}
diff --git a/core/java/android/text/style/AlignmentSpan.java b/core/java/android/text/style/AlignmentSpan.java
index 6158309..18c3e16 100644
--- a/core/java/android/text/style/AlignmentSpan.java
+++ b/core/java/android/text/style/AlignmentSpan.java
@@ -16,49 +16,90 @@
 
 package android.text.style;
 
+import android.annotation.NonNull;
 import android.os.Parcel;
 import android.text.Layout;
 import android.text.ParcelableSpan;
 import android.text.TextUtils;
 
+/**
+ * Span that allows defining the alignment of text at the paragraph level.
+ */
 public interface AlignmentSpan extends ParagraphStyle {
+
+    /**
+     * Returns the alignment of the text.
+     *
+     * @return the text alignment
+     */
     Layout.Alignment getAlignment();
 
+    /**
+     * Default implementation of the {@link AlignmentSpan}.
+     * <p>
+     * For example, a text written in a left to right language, like English, which is by default
+     * aligned to the left, can be aligned opposite to the layout direction like this:
+     * <pre>{@code SpannableString string = new SpannableString("Text with opposite alignment");
+     *string.setSpan(new AlignmentSpan.Standard(Layout.Alignment.ALIGN_OPPOSITE), 0,
+     *string.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);}</pre>
+     * <img src="{@docRoot}reference/android/images/text/style/ltralignmentspan.png" />
+     * <figcaption>Align left to right text opposite to the layout direction.</figcaption>
+     * <p>
+     * A text written in a right to left language, like Hebrew, which is by default aligned to the
+     * right, can be aligned opposite to the layout direction like this:
+     * <pre>{@code SpannableString string = new SpannableString("טקסט עם יישור הפוך");
+     *string.setSpan(new AlignmentSpan.Standard(Layout.Alignment.ALIGN_OPPOSITE), 0,
+     *string.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);}</pre>
+     * <img src="{@docRoot}reference/android/images/text/style/rtlalignmentspan.png" />
+     * <figcaption>Align right to left text opposite to the layout direction.</figcaption>
+     */
     class Standard implements AlignmentSpan, ParcelableSpan {
-        public Standard(Layout.Alignment align) {
+        private final Layout.Alignment mAlignment;
+
+        /**
+         * Constructs a {@link Standard} from an alignment.
+         */
+        public Standard(@NonNull Layout.Alignment align) {
             mAlignment = align;
         }
 
-        public Standard(Parcel src) {
+        /**
+         * Constructs a {@link Standard} from a parcel.
+         */
+        public Standard(@NonNull Parcel src) {
             mAlignment = Layout.Alignment.valueOf(src.readString());
         }
-        
-        public int getSpanTypeId() {
-        return getSpanTypeIdInternal();
-    }
 
-    /** @hide */
-    public int getSpanTypeIdInternal() {
+        @Override
+        public int getSpanTypeId() {
+            return getSpanTypeIdInternal();
+        }
+
+        /** @hide */
+        @Override
+        public int getSpanTypeIdInternal() {
             return TextUtils.ALIGNMENT_SPAN;
         }
-        
+
+        @Override
         public int describeContents() {
             return 0;
         }
 
-        public void writeToParcel(Parcel dest, int flags) {
+        @Override
+        public void writeToParcel(@NonNull Parcel dest, int flags) {
             writeToParcelInternal(dest, flags);
         }
 
         /** @hide */
-        public void writeToParcelInternal(Parcel dest, int flags) {
+        @Override
+        public void writeToParcelInternal(@NonNull Parcel dest, int flags) {
             dest.writeString(mAlignment.name());
         }
 
+        @Override
         public Layout.Alignment getAlignment() {
             return mAlignment;
         }
-
-        private final Layout.Alignment mAlignment;
     }
 }
diff --git a/core/java/android/text/style/ClickableSpan.java b/core/java/android/text/style/ClickableSpan.java
index b098f16..60aed2a 100644
--- a/core/java/android/text/style/ClickableSpan.java
+++ b/core/java/android/text/style/ClickableSpan.java
@@ -16,6 +16,7 @@
 
 package android.text.style;
 
+import android.annotation.NonNull;
 import android.text.TextPaint;
 import android.view.View;
 
@@ -24,6 +25,16 @@
  * with a movement method of LinkMovementMethod, the affected spans of
  * text can be selected. If selected and clicked, the {@link #onClick} method will
  * be called.
+ * <p>
+ * The text with a <code>ClickableSpan</code> attached will be underlined and the link color will be
+ * used as a text color. The default link color is the theme's accent color or
+ * <code>android:textColorLink</code> if this attribute is defined in the theme.
+ * For example, considering that we have a <code>CustomClickableSpan</code> that extends
+ * <code>ClickableSpan</code>, it can be used like this:
+ * <pre>{@code SpannableString string = new SpannableString("Text with clickable text");
+ *string.setSpan(new CustomClickableSpan(), 10, 19, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);}</pre>
+ * <img src="{@docRoot}reference/android/images/text/style/clickablespan.png" />
+ * <figcaption>Text with <code>ClickableSpan</code>.</figcaption>
  */
 public abstract class ClickableSpan extends CharacterStyle implements UpdateAppearance {
     private static int sIdCounter = 0;
@@ -33,13 +44,13 @@
     /**
      * Performs the click action associated with this span.
      */
-    public abstract void onClick(View widget);
+    public abstract void onClick(@NonNull View widget);
 
     /**
      * Makes the text underlined and in the link color.
      */
     @Override
-    public void updateDrawState(TextPaint ds) {
+    public void updateDrawState(@NonNull TextPaint ds) {
         ds.setColor(ds.linkColor);
         ds.setUnderlineText(true);
     }
diff --git a/core/java/android/text/style/EasyEditSpan.java b/core/java/android/text/style/EasyEditSpan.java
index 7af1c2c..9ee0b07 100644
--- a/core/java/android/text/style/EasyEditSpan.java
+++ b/core/java/android/text/style/EasyEditSpan.java
@@ -16,6 +16,7 @@
 
 package android.text.style;
 
+import android.annotation.NonNull;
 import android.app.PendingIntent;
 import android.os.Parcel;
 import android.text.ParcelableSpan;
@@ -79,7 +80,7 @@
     /**
      * Constructor called from {@link TextUtils} to restore the span.
      */
-    public EasyEditSpan(Parcel source) {
+    public EasyEditSpan(@NonNull Parcel source) {
         mPendingIntent = source.readParcelable(null);
         mDeleteEnabled = (source.readByte() == 1);
     }
@@ -90,12 +91,12 @@
     }
 
     @Override
-    public void writeToParcel(Parcel dest, int flags) {
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
         writeToParcelInternal(dest, flags);
     }
 
     /** @hide */
-    public void writeToParcelInternal(Parcel dest, int flags) {
+    public void writeToParcelInternal(@NonNull Parcel dest, int flags) {
         dest.writeParcelable(mPendingIntent, 0);
         dest.writeByte((byte) (mDeleteEnabled ? 1 : 0));
     }
diff --git a/core/java/android/text/style/MetricAffectingSpan.java b/core/java/android/text/style/MetricAffectingSpan.java
index 853ecc6..61b7947 100644
--- a/core/java/android/text/style/MetricAffectingSpan.java
+++ b/core/java/android/text/style/MetricAffectingSpan.java
@@ -16,6 +16,7 @@
 
 package android.text.style;
 
+import android.annotation.NonNull;
 import android.text.TextPaint;
 
 /**
@@ -23,13 +24,19 @@
  * changes the width or height of characters extend this class.
  */
 public abstract class MetricAffectingSpan
-extends CharacterStyle
-implements UpdateLayout {
-
-    public abstract void updateMeasureState(TextPaint p);
+        extends CharacterStyle
+        implements UpdateLayout {
 
     /**
-     * Returns "this" for most MetricAffectingSpans, but for 
+     * Classes that extend MetricAffectingSpan implement this method to update the text formatting
+     * in a way that can change the width or height of characters.
+     *
+     * @param textPaint the paint used for drawing the text
+     */
+    public abstract void updateMeasureState(@NonNull TextPaint textPaint);
+
+    /**
+     * Returns "this" for most MetricAffectingSpans, but for
      * MetricAffectingSpans that were generated by {@link #wrap},
      * returns the underlying MetricAffectingSpan.
      */
@@ -41,18 +48,18 @@
     /**
      * A Passthrough MetricAffectingSpan is one that
      * passes {@link #updateDrawState} and {@link #updateMeasureState}
-     * calls through to the specified MetricAffectingSpan 
+     * calls through to the specified MetricAffectingSpan
      * while still being a distinct object,
      * and is therefore able to be attached to the same Spannable
      * to which the specified MetricAffectingSpan is already attached.
      */
     /* package */ static class Passthrough extends MetricAffectingSpan {
         private MetricAffectingSpan mStyle;
-        
+
         /**
          * Creates a new Passthrough of the specfied MetricAffectingSpan.
          */
-        public Passthrough(MetricAffectingSpan cs) {
+        Passthrough(@NonNull MetricAffectingSpan cs) {
             mStyle = cs;
         }
 
@@ -60,7 +67,7 @@
          * Passes updateDrawState through to the underlying MetricAffectingSpan.
          */
         @Override
-        public void updateDrawState(TextPaint tp) {
+        public void updateDrawState(@NonNull TextPaint tp) {
             mStyle.updateDrawState(tp);
         }
 
@@ -68,10 +75,10 @@
          * Passes updateMeasureState through to the underlying MetricAffectingSpan.
          */
         @Override
-        public void updateMeasureState(TextPaint tp) {
+        public void updateMeasureState(@NonNull TextPaint tp) {
             mStyle.updateMeasureState(tp);
         }
-    
+
         /**
          * Returns the MetricAffectingSpan underlying this one, or the one
          * underlying it if it too is a Passthrough.
diff --git a/core/java/android/text/style/QuoteSpan.java b/core/java/android/text/style/QuoteSpan.java
index 7217e1e..a1c12c2 100644
--- a/core/java/android/text/style/QuoteSpan.java
+++ b/core/java/android/text/style/QuoteSpan.java
@@ -17,6 +17,9 @@
 package android.text.style;
 
 import android.annotation.ColorInt;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Px;
 import android.graphics.Canvas;
 import android.graphics.Paint;
 import android.os.Parcel;
@@ -24,68 +27,178 @@
 import android.text.ParcelableSpan;
 import android.text.TextUtils;
 
+/**
+ * A span which styles paragraphs by adding a vertical stripe at the beginning of the text
+ * (respecting layout direction).
+ * <p>
+ * A <code>QuoteSpan</code> must be attached from the first character to the last character of a
+ * single paragraph, otherwise the span will not be displayed.
+ * <p>
+ * <code>QuoteSpans</code> allow configuring the following elements:
+ * <ul>
+ * <li><b>color</b> - the vertical stripe color. By default, the stripe color is 0xff0000ff</li>
+ * <li><b>gap width</b> - the distance, in pixels, between the stripe and the paragraph.
+ * Default value is 2px.</li>
+ * <li><b>stripe width</b> - the width, in pixels, of the stripe. Default value is
+ * 2px.</li>
+ * </ul>
+ * For example, a <code>QuoteSpan</code> using the default values can be constructed like this:
+ * <pre>{@code SpannableString string = new SpannableString("Text with quote span on a long line");
+ *string.setSpan(new QuoteSpan(), 0, string.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);}</pre>
+ * <img src="{@docRoot}reference/android/images/text/style/defaultquotespan.png" />
+ * <figcaption><code>QuoteSpan</code> constructed with default values.</figcaption>
+ * <p>
+ * <p>
+ * To construct a <code>QuoteSpan</code> with a green stripe, of 20px in width and a gap width of
+ * 40px:
+ * <pre>{@code SpannableString string = new SpannableString("Text with quote span on a long line");
+ *string.setSpan(new QuoteSpan(Color.GREEN, 20, 40), 0, string.length(),
+ *Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);}</pre>
+ * <img src="{@docRoot}reference/android/images/text/style/customquotespan.png" />
+ * <figcaption>Customized <code>QuoteSpan</code>.</figcaption>
+ */
 public class QuoteSpan implements LeadingMarginSpan, ParcelableSpan {
-    private static final int STRIPE_WIDTH = 2;
-    private static final int GAP_WIDTH = 2;
+    /**
+     * Default stripe width in pixels.
+     */
+    public static final int STANDARD_STRIPE_WIDTH_PX = 2;
 
+    /**
+     * Default gap width in pixels.
+     */
+    public static final int STANDARD_GAP_WIDTH_PX = 2;
+
+    /**
+     * Default color for the quote stripe.
+     */
+    @ColorInt
+    public static final int STANDARD_COLOR = 0xff0000ff;
+
+    @ColorInt
     private final int mColor;
+    @Px
+    private final int mStripeWidth;
+    @Px
+    private final int mGapWidth;
 
+    /**
+     * Creates a {@link QuoteSpan} with the default values.
+     */
     public QuoteSpan() {
-        super();
-        mColor = 0xff0000ff;
+        this(STANDARD_COLOR, STANDARD_STRIPE_WIDTH_PX, STANDARD_GAP_WIDTH_PX);
     }
 
+    /**
+     * Creates a {@link QuoteSpan} based on a color.
+     *
+     * @param color the color of the quote stripe.
+     */
     public QuoteSpan(@ColorInt int color) {
-        super();
+        this(color, STANDARD_STRIPE_WIDTH_PX, STANDARD_GAP_WIDTH_PX);
+    }
+
+    /**
+     * Creates a {@link QuoteSpan} based on a color, a stripe width and the width of the gap
+     * between the stripe and the text.
+     *
+     * @param color       the color of the quote stripe.
+     * @param stripeWidth the width of the stripe.
+     * @param gapWidth    the width of the gap between the stripe and the text.
+     */
+    public QuoteSpan(@ColorInt int color, @IntRange(from = 0) int stripeWidth,
+            @IntRange(from = 0) int gapWidth) {
         mColor = color;
+        mStripeWidth = stripeWidth;
+        mGapWidth = gapWidth;
     }
 
-    public QuoteSpan(Parcel src) {
+    /**
+     * Create a {@link QuoteSpan} from a parcel.
+     */
+    public QuoteSpan(@NonNull Parcel src) {
         mColor = src.readInt();
+        mStripeWidth = src.readInt();
+        mGapWidth = src.readInt();
     }
 
+    @Override
     public int getSpanTypeId() {
         return getSpanTypeIdInternal();
     }
 
-    /** @hide */
+    /**
+     * @hide
+     */
+    @Override
     public int getSpanTypeIdInternal() {
         return TextUtils.QUOTE_SPAN;
     }
 
+    @Override
     public int describeContents() {
         return 0;
     }
 
+    @Override
     public void writeToParcel(Parcel dest, int flags) {
         writeToParcelInternal(dest, flags);
     }
 
-    /** @hide */
+    /**
+     * @hide
+     */
+    @Override
     public void writeToParcelInternal(Parcel dest, int flags) {
         dest.writeInt(mColor);
+        dest.writeInt(mStripeWidth);
+        dest.writeInt(mGapWidth);
     }
 
+    /**
+     * Get the color of the quote stripe.
+     *
+     * @return the color of the quote stripe.
+     */
     @ColorInt
     public int getColor() {
         return mColor;
     }
 
-    public int getLeadingMargin(boolean first) {
-        return STRIPE_WIDTH + GAP_WIDTH;
+    /**
+     * Get the width of the quote stripe.
+     *
+     * @return the width of the quote stripe.
+     */
+    public int getStripeWidth() {
+        return mStripeWidth;
     }
 
-    public void drawLeadingMargin(Canvas c, Paint p, int x, int dir,
-                                  int top, int baseline, int bottom,
-                                  CharSequence text, int start, int end,
-                                  boolean first, Layout layout) {
+    /**
+     * Get the width of the gap between the stripe and the text.
+     *
+     * @return the width of the gap between the stripe and the text.
+     */
+    public int getGapWidth() {
+        return mGapWidth;
+    }
+
+    @Override
+    public int getLeadingMargin(boolean first) {
+        return mStripeWidth + mGapWidth;
+    }
+
+    @Override
+    public void drawLeadingMargin(@NonNull Canvas c, @NonNull Paint p, int x, int dir,
+            int top, int baseline, int bottom,
+            @NonNull CharSequence text, int start, int end,
+            boolean first, @NonNull Layout layout) {
         Paint.Style style = p.getStyle();
         int color = p.getColor();
 
         p.setStyle(Paint.Style.FILL);
         p.setColor(mColor);
 
-        c.drawRect(x, top, x + dir * STRIPE_WIDTH, bottom, p);
+        c.drawRect(x, top, x + dir * mStripeWidth, bottom, p);
 
         p.setStyle(style);
         p.setColor(color);
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 5bd7446..31cfebc 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -267,21 +267,21 @@
      *
      * @see #getState
      */
-    public static final int STATE_UNKNOWN = 0;
+    public static final int STATE_UNKNOWN = ViewProtoEnums.DISPLAY_STATE_UNKNOWN; // 0
 
     /**
      * Display state: The display is off.
      *
      * @see #getState
      */
-    public static final int STATE_OFF = 1;
+    public static final int STATE_OFF = ViewProtoEnums.DISPLAY_STATE_OFF; // 1
 
     /**
      * Display state: The display is on.
      *
      * @see #getState
      */
-    public static final int STATE_ON = 2;
+    public static final int STATE_ON = ViewProtoEnums.DISPLAY_STATE_ON; // 2
 
     /**
      * Display state: The display is dozing in a low power state; it is still
@@ -291,7 +291,7 @@
      * @see #getState
      * @see android.os.PowerManager#isInteractive
      */
-    public static final int STATE_DOZE = 3;
+    public static final int STATE_DOZE = ViewProtoEnums.DISPLAY_STATE_DOZE; // 3
 
     /**
      * Display state: The display is dozing in a suspended low power state; it is still
@@ -303,7 +303,7 @@
      * @see #getState
      * @see android.os.PowerManager#isInteractive
      */
-    public static final int STATE_DOZE_SUSPEND = 4;
+    public static final int STATE_DOZE_SUSPEND = ViewProtoEnums.DISPLAY_STATE_DOZE_SUSPEND; // 4
 
     /**
      * Display state: The display is on and optimized for VR mode.
@@ -311,7 +311,7 @@
      * @see #getState
      * @see android.os.PowerManager#isInteractive
      */
-    public static final int STATE_VR = 5;
+    public static final int STATE_VR = ViewProtoEnums.DISPLAY_STATE_VR; // 5
 
     /**
      * Display state: The display is in a suspended full power state; it is still
@@ -323,7 +323,7 @@
      * @see #getState
      * @see android.os.PowerManager#isInteractive
      */
-    public static final int STATE_ON_SUSPEND = 6;
+    public static final int STATE_ON_SUSPEND = ViewProtoEnums.DISPLAY_STATE_ON_SUSPEND; // 6
 
     /* The color mode constants defined below must be kept in sync with the ones in
      * system/core/include/system/graphics-base.h */
diff --git a/core/java/android/view/IRecentsAnimationController.aidl b/core/java/android/view/IRecentsAnimationController.aidl
new file mode 100644
index 0000000..5607b11
--- /dev/null
+++ b/core/java/android/view/IRecentsAnimationController.aidl
@@ -0,0 +1,54 @@
+/*
+ * 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.view;
+
+import android.app.ActivityManager;
+import android.view.IRemoteAnimationFinishedCallback;
+import android.graphics.GraphicBuffer;
+
+/**
+ * Passed to the {@link IRecentsAnimationRunner} in order for the runner to control to let the
+ * runner control certain aspects of the recents animation, and to notify window manager when the
+ * animation has completed.
+ *
+ * {@hide}
+ */
+interface IRecentsAnimationController {
+
+    /**
+     * Takes a screenshot of the task associated with the given {@param taskId}. Only valid for the
+     * current set of task ids provided to the handler.
+     */
+    ActivityManager.TaskSnapshot screenshotTask(int taskId);
+
+    /**
+     * Notifies to the system that the animation into Recents should end, and all leashes associated
+     * with remote animation targets should be relinquished. If {@param moveHomeToTop} is true, then
+     * the home activity should be moved to the top. Otherwise, the home activity is hidden and the
+     * user is returned to the app.
+     */
+    void finish(boolean moveHomeToTop);
+
+    /**
+     * Called by the handler to indicate that the recents animation input consumer should be
+     * enabled. This is currently used to work around an issue where registering an input consumer
+     * mid-animation causes the existing motion event chain to be canceled. Instead, the caller
+     * may register the recents animation input consumer prior to starting the recents animation
+     * and then enable it mid-animation to start receiving touch events.
+     */
+    void setInputConsumerEnabled(boolean enabled);
+}
diff --git a/core/java/android/view/IRecentsAnimationRunner.aidl b/core/java/android/view/IRecentsAnimationRunner.aidl
new file mode 100644
index 0000000..ea6226b
--- /dev/null
+++ b/core/java/android/view/IRecentsAnimationRunner.aidl
@@ -0,0 +1,42 @@
+/*
+ * 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.view;
+
+import android.view.RemoteAnimationTarget;
+import android.view.IRecentsAnimationController;
+
+/**
+ * Interface that is used to callback from window manager to the process that runs a recents
+ * animation to start or cancel it.
+ *
+ * {@hide}
+ */
+oneway interface IRecentsAnimationRunner {
+
+    /**
+     * Called when the system is ready for the handler to start animating all the visible tasks.
+     */
+    void onAnimationStart(in IRecentsAnimationController controller,
+            in RemoteAnimationTarget[] apps);
+
+    /**
+     * Called when the system needs to cancel the current animation. This can be due to the
+     * wallpaper not drawing in time, or the handler not finishing the animation within a predefined
+     * amount of time.
+     */
+    void onAnimationCanceled();
+}
diff --git a/core/java/android/view/RemoteAnimationTarget.java b/core/java/android/view/RemoteAnimationTarget.java
index f39e618..c28c389 100644
--- a/core/java/android/view/RemoteAnimationTarget.java
+++ b/core/java/android/view/RemoteAnimationTarget.java
@@ -17,6 +17,7 @@
 package android.view;
 
 import android.annotation.IntDef;
+import android.app.WindowConfiguration;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.Parcel;
@@ -98,8 +99,14 @@
      */
     public final Rect sourceContainerBounds;
 
+    /**
+     * The window configuration for the target.
+     */
+    public final WindowConfiguration windowConfiguration;
+
     public RemoteAnimationTarget(int taskId, int mode, SurfaceControl leash, boolean isTranslucent,
-            Rect clipRect, int prefixOrderIndex, Point position, Rect sourceContainerBounds) {
+            Rect clipRect, int prefixOrderIndex, Point position, Rect sourceContainerBounds,
+            WindowConfiguration windowConfig) {
         this.mode = mode;
         this.taskId = taskId;
         this.leash = leash;
@@ -108,6 +115,7 @@
         this.prefixOrderIndex = prefixOrderIndex;
         this.position = new Point(position);
         this.sourceContainerBounds = new Rect(sourceContainerBounds);
+        this.windowConfiguration = windowConfig;
     }
 
     public RemoteAnimationTarget(Parcel in) {
@@ -119,6 +127,7 @@
         prefixOrderIndex = in.readInt();
         position = in.readParcelable(null);
         sourceContainerBounds = in.readParcelable(null);
+        windowConfiguration = in.readParcelable(null);
     }
 
     @Override
@@ -136,6 +145,7 @@
         dest.writeInt(prefixOrderIndex);
         dest.writeParcelable(position, 0 /* flags */);
         dest.writeParcelable(sourceContainerBounds, 0 /* flags */);
+        dest.writeParcelable(windowConfiguration, 0 /* flags */);
     }
 
     public static final Creator<RemoteAnimationTarget> CREATOR
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 3bb3a4c..1c5e871 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -98,11 +98,13 @@
     int DOCKED_BOTTOM = 4;
 
     /** @hide */
-    final static String INPUT_CONSUMER_PIP = "pip_input_consumer";
+    String INPUT_CONSUMER_PIP = "pip_input_consumer";
     /** @hide */
-    final static String INPUT_CONSUMER_NAVIGATION = "nav_input_consumer";
+    String INPUT_CONSUMER_NAVIGATION = "nav_input_consumer";
     /** @hide */
-    final static String INPUT_CONSUMER_WALLPAPER = "wallpaper_input_consumer";
+    String INPUT_CONSUMER_WALLPAPER = "wallpaper_input_consumer";
+    /** @hide */
+    String INPUT_CONSUMER_RECENTS_ANIMATION = "recents_animation_input_consumer";
 
     /**
      * Not set up for a transition.
diff --git a/core/java/android/webkit/WebViewProviderInfo.java b/core/java/android/webkit/WebViewProviderInfo.java
index 5d091c9..b0e9f01 100644
--- a/core/java/android/webkit/WebViewProviderInfo.java
+++ b/core/java/android/webkit/WebViewProviderInfo.java
@@ -17,10 +17,10 @@
 package android.webkit;
 
 import android.annotation.SystemApi;
+import android.content.pm.Signature;
 import android.os.Parcel;
 import android.os.Parcelable;
-
-import java.util.Arrays;
+import android.util.Base64;
 
 /**
  * @hide
@@ -34,7 +34,14 @@
         this.description = description;
         this.availableByDefault = availableByDefault;
         this.isFallback = isFallback;
-        this.signatures = signatures;
+        if (signatures == null) {
+            this.signatures = new Signature[0];
+        } else {
+            this.signatures = new Signature[signatures.length];
+            for (int n = 0; n < signatures.length; n++) {
+                this.signatures[n] = new Signature(Base64.decode(signatures[n], Base64.DEFAULT));
+            }
+        }
     }
 
     // aidl stuff
@@ -54,7 +61,7 @@
         description = in.readString();
         availableByDefault = (in.readInt() > 0);
         isFallback = (in.readInt() > 0);
-        signatures = in.createStringArray();
+        signatures = in.createTypedArray(Signature.CREATOR);
     }
 
     @Override
@@ -68,7 +75,7 @@
         out.writeString(description);
         out.writeInt(availableByDefault ? 1 : 0);
         out.writeInt(isFallback ? 1 : 0);
-        out.writeStringArray(signatures);
+        out.writeTypedArray(signatures, 0);
     }
 
     // fields read from framework resource
@@ -76,5 +83,5 @@
     public final String description;
     public final boolean availableByDefault;
     public final boolean isFallback;
-    public final String[] signatures;
+    public final Signature[] signatures;
 }
diff --git a/core/java/android/widget/MediaControlView2.java b/core/java/android/widget/MediaControlView2.java
index f1d633a..84d1850 100644
--- a/core/java/android/widget/MediaControlView2.java
+++ b/core/java/android/widget/MediaControlView2.java
@@ -25,7 +25,6 @@
 import android.media.update.MediaControlView2Provider;
 import android.media.update.ViewProvider;
 import android.util.AttributeSet;
-import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.View;
 
@@ -211,21 +210,11 @@
     }
 
     @Override
-    public boolean onKeyDown(int keyCode, KeyEvent event) {
-        return mProvider.onKeyDown_impl(keyCode, event);
-    }
-
-    @Override
     public void onFinishInflate() {
         mProvider.onFinishInflate_impl();
     }
 
     @Override
-    public boolean dispatchKeyEvent(KeyEvent event) {
-        return mProvider.dispatchKeyEvent_impl(event);
-    }
-
-    @Override
     public void setEnabled(boolean enabled) {
         mProvider.setEnabled_impl(enabled);
     }
@@ -257,21 +246,11 @@
         }
 
         @Override
-        public boolean onKeyDown_impl(int keyCode, KeyEvent event) {
-            return MediaControlView2.super.onKeyDown(keyCode, event);
-        }
-
-        @Override
         public void onFinishInflate_impl() {
             MediaControlView2.super.onFinishInflate();
         }
 
         @Override
-        public boolean dispatchKeyEvent_impl(KeyEvent event) {
-            return MediaControlView2.super.dispatchKeyEvent(event);
-        }
-
-        @Override
         public void setEnabled_impl(boolean enabled) {
             MediaControlView2.super.setEnabled(enabled);
         }
diff --git a/core/java/android/widget/VideoView2.java b/core/java/android/widget/VideoView2.java
index 8650c0a..3f94130 100644
--- a/core/java/android/widget/VideoView2.java
+++ b/core/java/android/widget/VideoView2.java
@@ -22,14 +22,17 @@
 import android.content.Context;
 import android.media.AudioAttributes;
 import android.media.AudioManager;
-import android.media.MediaPlayerBase;
+import android.media.MediaPlayerInterface;
+import android.media.session.MediaController;
+import android.media.session.PlaybackState;
 import android.media.update.ApiLoader;
 import android.media.update.VideoView2Provider;
 import android.media.update.ViewProvider;
 import android.net.Uri;
+import android.os.Bundle;
 import android.util.AttributeSet;
-import android.view.KeyEvent;
 import android.view.MotionEvent;
+import android.view.View;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -45,7 +48,7 @@
  *
  * <p>
  * <em> Data sources that VideoView2 supports : </em>
- * VideoView2 can play video files and audio-only fiels as
+ * VideoView2 can play video files and audio-only files as
  * well. It can load from various sources such as resources or content providers. The supported
  * media file formats are the same as MediaPlayer2.
  *
@@ -76,8 +79,8 @@
  * If a developer wants to attach a customed MediaControlView2, then set enableControlView attribute
  * to false and assign the customed media control widget using {@link #setMediaControlView2}.
  * <li> VideoView2 is integrated with MediaPlayer2 while VideoView is integrated with MediaPlayer.
- * <li> VideoView2 is integrated with MediaSession2 and so it responses with media key events.
- * A VideoView2 keeps a MediaSession2 instance internally and connects it to a corresponding
+ * <li> VideoView2 is integrated with MediaSession and so it responses with media key events.
+ * A VideoView2 keeps a MediaSession instance internally and connects it to a corresponding
  * MediaControlView2 instance.
  * </p>
  * </ul>
@@ -108,7 +111,18 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface ViewType {}
 
+    /**
+     * Indicates video is rendering on SurfaceView
+     *
+     * @see #setViewType
+     */
     public static final int VIEW_TYPE_SURFACEVIEW = 1;
+
+    /**
+     * Indicates video is rendering on TextureView
+     *
+     * @see #setViewType
+     */
     public static final int VIEW_TYPE_TEXTUREVIEW = 2;
 
     private final VideoView2Provider mProvider;
@@ -159,67 +173,18 @@
         return mProvider.getMediaControlView2_impl();
     }
 
-    /**
-     * Starts playback with the media contents specified by {@link #setVideoURI} and
-     * {@link #setVideoPath}.
-     * If it has been paused, this method will resume playback from the current position.
-     */
-    public void start() {
-        mProvider.start_impl();
-    }
 
     /**
-     * Pauses playback.
+     * Returns MediaController instance which is connected with MediaSession that VideoView2 is
+     * using. This method should be called when VideoView2 is attached to window, or it throws
+     * IllegalStateException, since internal MediaSession instance is not available until
+     * this view is attached to window. Please check {@link android.view.View#isAttachedToWindow}
+     * before calling this method.
+     *
+     * @throws IllegalStateException if interal MediaSession is not created yet.
      */
-    public void pause() {
-        mProvider.pause_impl();
-    }
-
-    /**
-     * Gets the duration of the media content specified by #setVideoURI and #setVideoPath
-     * in milliseconds.
-     */
-    public int getDuration() {
-        return mProvider.getDuration_impl();
-    }
-
-    /**
-     * Gets current playback position in milliseconds.
-     */
-    public int getCurrentPosition() {
-        return mProvider.getCurrentPosition_impl();
-    }
-
-    // TODO: mention about key-frame related behavior.
-    /**
-     * Moves the media by specified time position.
-     * @param msec the offset in milliseconds from the start to seek to.
-     */
-    public void seekTo(int msec) {
-        mProvider.seekTo_impl(msec);
-    }
-
-    /**
-     * Says if the media is currently playing.
-     * @return true if the media is playing, false if it is not (eg. paused or stopped).
-     */
-    public boolean isPlaying() {
-        return mProvider.isPlaying_impl();
-    }
-
-    // TODO: check what will return if it is a local media.
-    /**
-     * Gets the percentage (0-100) of the content that has been buffered or played so far.
-     */
-    public int getBufferPercentage() {
-        return mProvider.getBufferPercentage_impl();
-    }
-
-    /**
-     * Returns the audio session ID.
-     */
-    public int getAudioSessionId() {
-        return mProvider.getAudioSessionId_impl();
+    public MediaController getMediaController() {
+        return mProvider.getMediaController_impl();
     }
 
     /**
@@ -244,7 +209,6 @@
         mProvider.setFullScreen_impl(fullScreen);
     }
 
-    // TODO: This should be revised after integration with MediaPlayer2.
     /**
      * Sets playback speed.
      *
@@ -254,21 +218,12 @@
      * be reset to the normal speed 1.0f.
      * @param speed the playback speed. It should be positive.
      */
+    // TODO: Support this via MediaController2.
     public void setSpeed(float speed) {
         mProvider.setSpeed_impl(speed);
     }
 
     /**
-     * Returns current speed setting.
-     *
-     * If setSpeed() has never been called, returns the default value 1.0f.
-     * @return current speed setting
-     */
-    public float getSpeed() {
-        return mProvider.getSpeed_impl();
-    }
-
-    /**
      * Sets which type of audio focus will be requested during the playback, or configures playback
      * to not request audio focus. Valid values for focus requests are
      * {@link AudioManager#AUDIOFOCUS_GAIN}, {@link AudioManager#AUDIOFOCUS_GAIN_TRANSIENT},
@@ -307,7 +262,7 @@
      * @throws IllegalStateException if MediaControlView2 is not set.
      */
     public void setRouteAttributes(@NonNull List<String> routeCategories,
-            @Nullable MediaPlayerBase player) {
+            @Nullable MediaPlayerInterface player) {
         mProvider.setRouteAttributes_impl(routeCategories, player);
     }
 
@@ -325,8 +280,8 @@
      *
      * @param uri the URI of the video.
      */
-    public void setVideoURI(Uri uri) {
-        mProvider.setVideoURI_impl(uri);
+    public void setVideoUri(Uri uri) {
+        mProvider.setVideoUri_impl(uri);
     }
 
     /**
@@ -339,8 +294,8 @@
      *                "android-allow-cross-domain-redirect" as the key and "0" or "1" as the value
      *                to disallow or allow cross domain redirection.
      */
-    public void setVideoURI(Uri uri, Map<String, String> headers) {
-        mProvider.setVideoURI_impl(uri, headers);
+    public void setVideoUri(Uri uri, Map<String, String> headers) {
+        mProvider.setVideoUri_impl(uri, headers);
     }
 
     /**
@@ -367,11 +322,16 @@
     }
 
     /**
-     * Stops playback and release all the resources. This should be called whenever a VideoView2
-     * instance is no longer to be used.
+     * Sets custom actions which will be shown as custom buttons in {@link MediaControlView2}.
+     *
+     * @param actionList A list of {@link PlaybackState.CustomAction}. The return value of
+     *                   {@link PlaybackState.CustomAction#getIcon()} will be used to draw buttons
+     *                   in {@link MediaControlView2}.
+     * @param listener A listener to be called when a custom button is clicked.
      */
-    public void stopPlayback() {
-        mProvider.stopPlayback_impl();
+    public void setCustomActions(List<PlaybackState.CustomAction> actionList,
+            OnCustomActionListener listener) {
+        mProvider.setCustomActions_impl(actionList, listener);
     }
 
     /**
@@ -431,19 +391,20 @@
     }
 
     /**
-     * Interface definition of a callback to be invoked when the viw type has been changed.
+     * Interface definition of a callback to be invoked when the view type has been changed.
      */
     public interface OnViewTypeChangedListener {
         /**
          * Called when the view type has been changed.
          * @see #setViewType(int)
+         * @param view the View whose view type is changed
          * @param viewType
          * <ul>
          * <li>{@link #VIEW_TYPE_SURFACEVIEW}
          * <li>{@link #VIEW_TYPE_TEXTUREVIEW}
          * </ul>
          */
-        void onViewTypeChanged(@ViewType int viewType);
+        void onViewTypeChanged(View view, @ViewType int viewType);
     }
 
     /**
@@ -453,7 +414,7 @@
         /**
          * Called when the media file is ready for playback.
          */
-        void onPrepared();
+        void onPrepared(View view);
     }
 
     /**
@@ -464,7 +425,7 @@
         /**
          * Called when the end of a media source is reached during playback.
          */
-        void onCompletion();
+        void onCompletion(View view);
     }
 
     /**
@@ -480,7 +441,7 @@
          * @return true if the method handled the error, false if it didn't.
          * @see MediaPlayer#OnErrorListener
          */
-        boolean onError(int what, int extra);
+        boolean onError(View view, int what, int extra);
     }
 
     /**
@@ -495,7 +456,7 @@
          *
          * @see MediaPlayer#OnInfoListener
          */
-        void onInfo(int what, int extra);
+        void onInfo(View view, int what, int extra);
     }
 
     /**
@@ -505,7 +466,23 @@
         /**
          * Called to indicate a fullscreen mode change.
          */
-        void onFullScreenChanged(boolean fullScreen);
+        void onFullScreenChanged(View view, boolean fullScreen);
+    }
+
+    /**
+     * Interface definition of a callback to be invoked to inform that a custom action is performed.
+     *
+     * TODO: When MediaSession2 is ready, modify the method to match the signature.
+     */
+    public interface OnCustomActionListener {
+        /**
+         * Called to indicate that a custom action is performed.
+         *
+         * @param action The action that was originally sent in the
+         *               {@link PlaybackState.CustomAction}.
+         * @param extras Optional extras.
+         */
+        void onCustomAction(String action, Bundle extras);
     }
 
     @Override
@@ -534,21 +511,11 @@
     }
 
     @Override
-    public boolean onKeyDown(int keyCode, KeyEvent event) {
-        return mProvider.onKeyDown_impl(keyCode, event);
-    }
-
-    @Override
     public void onFinishInflate() {
         mProvider.onFinishInflate_impl();
     }
 
     @Override
-    public boolean dispatchKeyEvent(KeyEvent event) {
-        return mProvider.dispatchKeyEvent_impl(event);
-    }
-
-    @Override
     public void setEnabled(boolean enabled) {
         mProvider.setEnabled_impl(enabled);
     }
@@ -580,21 +547,11 @@
         }
 
         @Override
-        public boolean onKeyDown_impl(int keyCode, KeyEvent event) {
-            return VideoView2.super.onKeyDown(keyCode, event);
-        }
-
-        @Override
         public void onFinishInflate_impl() {
             VideoView2.super.onFinishInflate();
         }
 
         @Override
-        public boolean dispatchKeyEvent_impl(KeyEvent event) {
-            return VideoView2.super.dispatchKeyEvent(event);
-        }
-
-        @Override
         public void setEnabled_impl(boolean enabled) {
             VideoView2.super.setEnabled(enabled);
         }
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index ee3bec8..fd5fe10 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -41,9 +41,11 @@
 import android.os.IBatteryPropertiesRegistrar;
 import android.os.Looper;
 import android.os.Message;
+import android.os.OsProtoEnums;
 import android.os.Parcel;
 import android.os.ParcelFormatException;
 import android.os.Parcelable;
+import android.os.PowerManager;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -4252,11 +4254,11 @@
             getUidStatsLocked(uid).noteStartWakeLocked(pid, name, type, elapsedRealtime);
 
             if (wc != null) {
-                StatsLog.write(
-                        StatsLog.WAKELOCK_STATE_CHANGED, wc.getUids(), wc.getTags(), type, name, 1);
+                StatsLog.write(StatsLog.WAKELOCK_STATE_CHANGED, wc.getUids(), wc.getTags(),
+                        getPowerManagerWakeLockLevel(type), name, 1);
             } else {
-                StatsLog.write_non_chained(StatsLog.WAKELOCK_STATE_CHANGED, uid, null, type, name,
-                        1);
+                StatsLog.write_non_chained(StatsLog.WAKELOCK_STATE_CHANGED, uid, null,
+                        getPowerManagerWakeLockLevel(type), name, 1);
             }
         }
     }
@@ -4295,15 +4297,45 @@
 
             getUidStatsLocked(uid).noteStopWakeLocked(pid, name, type, elapsedRealtime);
             if (wc != null) {
-                StatsLog.write(
-                        StatsLog.WAKELOCK_STATE_CHANGED, wc.getUids(), wc.getTags(), type, name, 0);
+                StatsLog.write(StatsLog.WAKELOCK_STATE_CHANGED, wc.getUids(), wc.getTags(),
+                        getPowerManagerWakeLockLevel(type), name, 0);
             } else {
-                StatsLog.write_non_chained(StatsLog.WAKELOCK_STATE_CHANGED, uid, null, type, name,
-                        0);
+                StatsLog.write_non_chained(StatsLog.WAKELOCK_STATE_CHANGED, uid, null,
+                        getPowerManagerWakeLockLevel(type), name, 0);
             }
         }
     }
 
+    /**
+     * Converts BatteryStats wakelock types back into PowerManager wakelock levels.
+     * This is the inverse map of Notifier.getBatteryStatsWakeLockMonitorType().
+     * These are estimations, since batterystats loses some of the original data.
+     * TODO: Delete this. Instead, StatsLog.write should be called from PowerManager's Notifier.
+     */
+    private int getPowerManagerWakeLockLevel(int battertStatsWakelockType) {
+        switch (battertStatsWakelockType) {
+            // PowerManager.PARTIAL_WAKE_LOCK or PROXIMITY_SCREEN_OFF_WAKE_LOCK
+            case BatteryStats.WAKE_TYPE_PARTIAL:
+                return PowerManager.PARTIAL_WAKE_LOCK;
+
+            // PowerManager.SCREEN_DIM_WAKE_LOCK or SCREEN_BRIGHT_WAKE_LOCK
+            case BatteryStats.WAKE_TYPE_FULL:
+                return PowerManager.FULL_WAKE_LOCK;
+
+            case BatteryStats.WAKE_TYPE_DRAW:
+                return PowerManager.DRAW_WAKE_LOCK;
+
+            // It appears that nothing can ever make a Window and PowerManager lacks an equivalent.
+            case BatteryStats.WAKE_TYPE_WINDOW:
+                Slog.e(TAG, "Illegal window wakelock type observed in batterystats.");
+                return -1;
+
+            default:
+                Slog.e(TAG, "Illegal wakelock type in batterystats: " + battertStatsWakelockType);
+                return -1;
+        }
+    }
+
     public void noteStartWakeFromSourceLocked(WorkSource ws, int pid, String name,
             String historyName, int type, boolean unimportantForLogging) {
         final long elapsedRealtime = mClocks.elapsedRealtime();
@@ -12215,7 +12247,7 @@
     }
 
     // This should probably be exposed in the API, though it's not critical
-    public static final int BATTERY_PLUGGED_NONE = 0;
+    public static final int BATTERY_PLUGGED_NONE = OsProtoEnums.BATTERY_PLUGGED_NONE; // = 0
 
     public void setBatteryStateLocked(final int status, final int health, final int plugType,
             final int level, /* not final */ int temp, final int volt, final int chargeUAh,
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index c5af897..111934f 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -149,6 +149,9 @@
     final ArrayMap<String, ArraySet<String>> mVendorPrivAppPermissions = new ArrayMap<>();
     final ArrayMap<String, ArraySet<String>> mVendorPrivAppDenyPermissions = new ArrayMap<>();
 
+    final ArrayMap<String, ArraySet<String>> mProductPrivAppPermissions = new ArrayMap<>();
+    final ArrayMap<String, ArraySet<String>> mProductPrivAppDenyPermissions = new ArrayMap<>();
+
     final ArrayMap<String, ArrayMap<String, Boolean>> mOemPermissions = new ArrayMap<>();
 
     public static SystemConfig getInstance() {
@@ -240,6 +243,14 @@
         return mVendorPrivAppDenyPermissions.get(packageName);
     }
 
+    public ArraySet<String> getProductPrivAppPermissions(String packageName) {
+        return mProductPrivAppPermissions.get(packageName);
+    }
+
+    public ArraySet<String> getProductPrivAppDenyPermissions(String packageName) {
+        return mProductPrivAppDenyPermissions.get(packageName);
+    }
+
     public Map<String, Boolean> getOemPermissions(String packageName) {
         final Map<String, Boolean> oemPermissions = mOemPermissions.get(packageName);
         if (oemPermissions != null) {
@@ -278,6 +289,14 @@
                 Environment.getOemDirectory(), "etc", "sysconfig"), oemPermissionFlag);
         readPermissions(Environment.buildPath(
                 Environment.getOemDirectory(), "etc", "permissions"), oemPermissionFlag);
+
+        // Allow Product to customize system configs around libs, features, permissions and apps
+        int productPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PERMISSIONS |
+                ALLOW_APP_CONFIGS | ALLOW_PRIVAPP_PERMISSIONS;
+        readPermissions(Environment.buildPath(
+                Environment.getProductDirectory(), "etc", "sysconfig"), productPermissionFlag);
+        readPermissions(Environment.buildPath(
+                Environment.getProductDirectory(), "etc", "permissions"), productPermissionFlag);
     }
 
     void readPermissions(File libraryDir, int permissionFlag) {
@@ -598,15 +617,20 @@
                     }
                     XmlUtils.skipCurrentTag(parser);
                 } else if ("privapp-permissions".equals(name) && allowPrivappPermissions) {
-                    // privapp permissions from system and vendor partitions are stored
+                    // privapp permissions from system, vendor and product partitions are stored
                     // separately. This is to prevent xml files in the vendor partition from
                     // granting permissions to priv apps in the system partition and vice
                     // versa.
                     boolean vendor = permFile.toPath().startsWith(
                             Environment.getVendorDirectory().toPath());
+                    boolean product = permFile.toPath().startsWith(
+                            Environment.getProductDirectory().toPath());
                     if (vendor) {
                         readPrivAppPermissions(parser, mVendorPrivAppPermissions,
                                 mVendorPrivAppDenyPermissions);
+                    } else if (product) {
+                        readPrivAppPermissions(parser, mProductPrivAppPermissions,
+                                mProductPrivAppDenyPermissions);
                     } else {
                         readPrivAppPermissions(parser, mPrivAppPermissions,
                                 mPrivAppDenyPermissions);
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 5751fc9..93f95c6 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -110,8 +110,8 @@
         "android_util_AssetManager.cpp",
         "android_util_Binder.cpp",
         "android_util_EventLog.cpp",
-        "android_util_Log.cpp",
         "android_util_MemoryIntArray.cpp",
+        "android_util_Log.cpp",
         "android_util_PathParser.cpp",
         "android_util_Process.cpp",
         "android_util_StringBlock.cpp",
@@ -190,7 +190,6 @@
         "android_backup_FileBackupHelperBase.cpp",
         "android_backup_BackupHelperDispatcher.cpp",
         "android_app_backup_FullBackup.cpp",
-        "android_content_res_ApkAssets.cpp",
         "android_content_res_ObbScanner.cpp",
         "android_content_res_Configuration.cpp",
         "android_animation_PropertyValuesHolder.cpp",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index e3b5c8f..bf7a7794 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -122,7 +122,6 @@
 extern int register_android_util_PathParser(JNIEnv* env);
 extern int register_android_content_StringBlock(JNIEnv* env);
 extern int register_android_content_XmlBlock(JNIEnv* env);
-extern int register_android_content_res_ApkAssets(JNIEnv* env);
 extern int register_android_graphics_Canvas(JNIEnv* env);
 extern int register_android_graphics_CanvasProperty(JNIEnv* env);
 extern int register_android_graphics_ColorFilter(JNIEnv* env);
@@ -974,6 +973,12 @@
         addOption("--generate-debug-info");
     }
 
+    // The mini-debug-info makes it possible to backtrace through JIT code.
+    if (property_get_bool("dalvik.vm.minidebuginfo", 0)) {
+        addOption("-Xcompiler-option");
+        addOption("--generate-mini-debug-info");
+    }
+
     /*
      * Retrieve the build fingerprint and provide it to the runtime. That way, ANR dumps will
      * contain the fingerprint and can be parsed.
@@ -1341,7 +1346,6 @@
     REG_JNI(register_android_content_AssetManager),
     REG_JNI(register_android_content_StringBlock),
     REG_JNI(register_android_content_XmlBlock),
-    REG_JNI(register_android_content_res_ApkAssets),
     REG_JNI(register_android_text_AndroidCharacter),
     REG_JNI(register_android_text_Hyphenator),
     REG_JNI(register_android_text_MeasuredParagraph),
diff --git a/core/jni/android/graphics/AnimatedImageDrawable.cpp b/core/jni/android/graphics/AnimatedImageDrawable.cpp
index 262b553..0e562c0 100644
--- a/core/jni/android/graphics/AnimatedImageDrawable.cpp
+++ b/core/jni/android/graphics/AnimatedImageDrawable.cpp
@@ -17,6 +17,7 @@
 #include "GraphicsJNI.h"
 #include "ImageDecoder.h"
 #include "core_jni_helpers.h"
+#include "Utils.h"
 
 #include <hwui/AnimatedImageDrawable.h>
 #include <hwui/Canvas.h>
@@ -28,6 +29,7 @@
 
 using namespace android;
 
+static jmethodID gAnimatedImageDrawable_postOnAnimationEndMethodID;
 
 // Note: jpostProcess holds a handle to the ImageDecoder.
 static jlong AnimatedImageDrawable_nCreate(JNIEnv* env, jobject /*clazz*/,
@@ -113,6 +115,9 @@
     return drawable->isRunning();
 }
 
+// Java's NOT_RUNNING relies on this being -2.0.
+static_assert(SkAnimatedImage::kNotRunning == -2.0);
+
 static jboolean AnimatedImageDrawable_nStart(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
     auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
     return drawable->start();
@@ -123,6 +128,44 @@
     drawable->stop();
 }
 
+// Java's LOOP_INFINITE relies on this being the same.
+static_assert(SkCodec::kRepetitionCountInfinite == -1);
+
+static void AnimatedImageDrawable_nSetLoopCount(JNIEnv* env, jobject /*clazz*/, jlong nativePtr,
+                                                jint loopCount) {
+    auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
+    drawable->setRepetitionCount(loopCount);
+}
+
+class JniAnimationEndListener : public OnAnimationEndListener {
+public:
+    JniAnimationEndListener(JNIEnv* env, jobject javaObject) {
+        LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&mJvm) != JNI_OK);
+        mJavaObject = env->NewGlobalRef(javaObject);
+    }
+
+    ~JniAnimationEndListener() override {
+        auto* env = get_env_or_die(mJvm);
+        env->DeleteGlobalRef(mJavaObject);
+    }
+
+    void onAnimationEnd() override {
+        auto* env = get_env_or_die(mJvm);
+        env->CallVoidMethod(mJavaObject, gAnimatedImageDrawable_postOnAnimationEndMethodID);
+    }
+
+private:
+    JavaVM* mJvm;
+    jobject mJavaObject;
+};
+
+static void AnimatedImageDrawable_nSetOnAnimationEndListener(JNIEnv* env, jobject /*clazz*/,
+                                                             jlong nativePtr, jobject jdrawable) {
+    auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
+    drawable->setOnAnimationEndListener(std::unique_ptr<OnAnimationEndListener>(
+                new JniAnimationEndListener(env, jdrawable)));
+}
+
 static long AnimatedImageDrawable_nNativeByteSize(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
     auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr);
     // FIXME: Report the size of the internal SkBitmap etc.
@@ -139,10 +182,15 @@
     { "nIsRunning",          "(J)Z",                                                         (void*) AnimatedImageDrawable_nIsRunning },
     { "nStart",              "(J)Z",                                                         (void*) AnimatedImageDrawable_nStart },
     { "nStop",               "(J)V",                                                         (void*) AnimatedImageDrawable_nStop },
+    { "nSetLoopCount",       "(JI)V",                                                        (void*) AnimatedImageDrawable_nSetLoopCount },
+    { "nSetOnAnimationEndListener", "(JLandroid/graphics/drawable/AnimatedImageDrawable;)V", (void*) AnimatedImageDrawable_nSetOnAnimationEndListener },
     { "nNativeByteSize",     "(J)J",                                                         (void*) AnimatedImageDrawable_nNativeByteSize },
 };
 
 int register_android_graphics_drawable_AnimatedImageDrawable(JNIEnv* env) {
+    jclass animatedImageDrawable_class = FindClassOrDie(env, "android/graphics/drawable/AnimatedImageDrawable");
+    gAnimatedImageDrawable_postOnAnimationEndMethodID = GetMethodIDOrDie(env, animatedImageDrawable_class, "postOnAnimationEnd", "()V");
+
     return android::RegisterMethodsOrDie(env, "android/graphics/drawable/AnimatedImageDrawable",
             gAnimatedImageDrawableMethods, NELEM(gAnimatedImageDrawableMethods));
 }
diff --git a/core/jni/android/graphics/ByteBufferStreamAdaptor.cpp b/core/jni/android/graphics/ByteBufferStreamAdaptor.cpp
index 85c9ef3..173818b 100644
--- a/core/jni/android/graphics/ByteBufferStreamAdaptor.cpp
+++ b/core/jni/android/graphics/ByteBufferStreamAdaptor.cpp
@@ -1,5 +1,6 @@
 #include "ByteBufferStreamAdaptor.h"
 #include "core_jni_helpers.h"
+#include "Utils.h"
 
 #include <SkStream.h>
 
@@ -8,14 +9,6 @@
 static jmethodID gByteBuffer_getMethodID;
 static jmethodID gByteBuffer_setPositionMethodID;
 
-static JNIEnv* get_env_or_die(JavaVM* jvm) {
-    JNIEnv* env;
-    if (jvm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
-        LOG_ALWAYS_FATAL("Failed to get JNIEnv for JavaVM: %p", jvm);
-    }
-    return env;
-}
-
 class ByteBufferStream : public SkStreamAsset {
 private:
     ByteBufferStream(JavaVM* jvm, jobject jbyteBuffer, size_t initialPosition, size_t length,
diff --git a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
index 4257c98..7a9fea7 100644
--- a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
+++ b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
@@ -12,15 +12,6 @@
 static jmethodID    gInputStream_readMethodID;
 static jmethodID    gInputStream_skipMethodID;
 
-// FIXME: Share with ByteBufferStreamAdaptor.cpp?
-static JNIEnv* get_env_or_die(JavaVM* jvm) {
-    JNIEnv* env;
-    if (jvm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
-        LOG_ALWAYS_FATAL("Failed to get JNIEnv for JavaVM: %p", jvm);
-    }
-    return env;
-}
-
 /**
  *  Wrapper for a Java InputStream.
  */
@@ -57,13 +48,13 @@
     }
 
     ~JavaInputStreamAdaptor() override {
-        auto* env = get_env_or_die(fJvm);
+        auto* env = android::get_env_or_die(fJvm);
         env->DeleteGlobalRef(fJavaInputStream);
         env->DeleteGlobalRef(fJavaByteArray);
     }
 
     size_t read(void* buffer, size_t size) override {
-        auto* env = get_env_or_die(fJvm);
+        auto* env = android::get_env_or_die(fJvm);
         if (!fSwallowExceptions && checkException(env)) {
             // Just in case the caller did not clear from a previous exception.
             return 0;
diff --git a/core/jni/android/graphics/FontFamily.cpp b/core/jni/android/graphics/FontFamily.cpp
index c50026e..dd3e6f0 100644
--- a/core/jni/android/graphics/FontFamily.cpp
+++ b/core/jni/android/graphics/FontFamily.cpp
@@ -28,7 +28,7 @@
 #include <nativehelper/ScopedUtfChars.h>
 #include <android_runtime/AndroidRuntime.h>
 #include <android_runtime/android_util_AssetManager.h>
-#include <androidfw/AssetManager2.h>
+#include <androidfw/AssetManager.h>
 #include "Utils.h"
 #include "FontUtils.h"
 
@@ -224,8 +224,7 @@
     NPE_CHECK_RETURN_ZERO(env, jpath);
 
     NativeFamilyBuilder* builder = reinterpret_cast<NativeFamilyBuilder*>(builderPtr);
-
-    Guarded<AssetManager2>* mgr = AssetManagerForJavaObject(env, jassetMgr);
+    AssetManager* mgr = assetManagerForJavaObject(env, jassetMgr);
     if (NULL == mgr) {
         builder->axes.clear();
         return false;
@@ -237,33 +236,27 @@
         return false;
     }
 
-    std::unique_ptr<Asset> asset;
-    {
-      ScopedLock<AssetManager2> locked_mgr(*mgr);
-      if (isAsset) {
-          asset = locked_mgr->Open(str.c_str(), Asset::ACCESS_BUFFER);
-      } else if (cookie > 0) {
-          // Valid java cookies are 1-based, but AssetManager cookies are 0-based.
-          asset = locked_mgr->OpenNonAsset(str.c_str(), static_cast<ApkAssetsCookie>(cookie - 1),
-                  Asset::ACCESS_BUFFER);
-      } else {
-          asset = locked_mgr->OpenNonAsset(str.c_str(), Asset::ACCESS_BUFFER);
-      }
+    Asset* asset;
+    if (isAsset) {
+        asset = mgr->open(str.c_str(), Asset::ACCESS_BUFFER);
+    } else {
+        asset = cookie ? mgr->openNonAsset(static_cast<int32_t>(cookie), str.c_str(),
+                Asset::ACCESS_BUFFER) : mgr->openNonAsset(str.c_str(), Asset::ACCESS_BUFFER);
     }
 
-    if (nullptr == asset) {
+    if (NULL == asset) {
         builder->axes.clear();
         return false;
     }
 
     const void* buf = asset->getBuffer(false);
     if (NULL == buf) {
+        delete asset;
         builder->axes.clear();
         return false;
     }
 
-    sk_sp<SkData> data(SkData::MakeWithProc(buf, asset->getLength(), releaseAsset,
-            asset.release()));
+    sk_sp<SkData> data(SkData::MakeWithProc(buf, asset->getLength(), releaseAsset, asset));
     return addSkTypeface(builder, std::move(data), ttcIndex, weight, isItalic);
 }
 
diff --git a/core/jni/android/graphics/Utils.cpp b/core/jni/android/graphics/Utils.cpp
index 630220a..dd9bafe 100644
--- a/core/jni/android/graphics/Utils.cpp
+++ b/core/jni/android/graphics/Utils.cpp
@@ -117,3 +117,11 @@
 bool android::isSeekable(int descriptor) {
     return ::lseek64(descriptor, 0, SEEK_CUR) != -1;
 }
+
+JNIEnv* android::get_env_or_die(JavaVM* jvm) {
+    JNIEnv* env;
+    if (jvm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
+        LOG_ALWAYS_FATAL("Failed to get JNIEnv for JavaVM: %p", jvm);
+    }
+    return env;
+}
diff --git a/core/jni/android/graphics/Utils.h b/core/jni/android/graphics/Utils.h
index 69930a5..2f2ee96 100644
--- a/core/jni/android/graphics/Utils.h
+++ b/core/jni/android/graphics/Utils.h
@@ -74,6 +74,8 @@
  */
 bool isSeekable(int descriptor);
 
+JNIEnv* get_env_or_die(JavaVM* jvm);
+
 }; // namespace android
 
 #endif  // _ANDROID_GRAPHICS_UTILS_H_
diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp
index 49a24a3..09e37e1 100644
--- a/core/jni/android_app_NativeActivity.cpp
+++ b/core/jni/android_app_NativeActivity.cpp
@@ -361,7 +361,7 @@
     code->sdkVersion = sdkVersion;
 
     code->javaAssetManager = env->NewGlobalRef(jAssetMgr);
-    code->assetManager = NdkAssetManagerForJavaObject(env, jAssetMgr);
+    code->assetManager = assetManagerForJavaObject(env, jAssetMgr);
 
     if (obbDir != NULL) {
         dirStr = env->GetStringUTFChars(obbDir, NULL);
diff --git a/core/jni/android_content_res_ApkAssets.cpp b/core/jni/android_content_res_ApkAssets.cpp
deleted file mode 100644
index c0f151b..0000000
--- a/core/jni/android_content_res_ApkAssets.cpp
+++ /dev/null
@@ -1,150 +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 "android-base/macros.h"
-#include "android-base/stringprintf.h"
-#include "android-base/unique_fd.h"
-#include "androidfw/ApkAssets.h"
-#include "utils/misc.h"
-
-#include "core_jni_helpers.h"
-#include "jni.h"
-#include "nativehelper/ScopedUtfChars.h"
-
-using ::android::base::unique_fd;
-
-namespace android {
-
-static jlong NativeLoad(JNIEnv* env, jclass /*clazz*/, jstring java_path, jboolean system,
-                        jboolean force_shared_lib, jboolean overlay) {
-  ScopedUtfChars path(env, java_path);
-  if (path.c_str() == nullptr) {
-    return 0;
-  }
-
-  std::unique_ptr<const ApkAssets> apk_assets;
-  if (overlay) {
-    apk_assets = ApkAssets::LoadOverlay(path.c_str(), system);
-  } else if (force_shared_lib) {
-    apk_assets = ApkAssets::LoadAsSharedLibrary(path.c_str(), system);
-  } else {
-    apk_assets = ApkAssets::Load(path.c_str(), system);
-  }
-
-  if (apk_assets == nullptr) {
-    std::string error_msg = base::StringPrintf("Failed to load asset path %s", path.c_str());
-    jniThrowException(env, "java/io/IOException", error_msg.c_str());
-    return 0;
-  }
-  return reinterpret_cast<jlong>(apk_assets.release());
-}
-
-static jlong NativeLoadFromFd(JNIEnv* env, jclass /*clazz*/, jobject file_descriptor,
-                              jstring friendly_name, jboolean system, jboolean force_shared_lib) {
-  ScopedUtfChars friendly_name_utf8(env, friendly_name);
-  if (friendly_name_utf8.c_str() == nullptr) {
-    return 0;
-  }
-
-  int fd = jniGetFDFromFileDescriptor(env, file_descriptor);
-  if (fd < 0) {
-    jniThrowException(env, "java/lang/IllegalArgumentException", "Bad FileDescriptor");
-    return 0;
-  }
-
-  unique_fd dup_fd(::dup(fd));
-  if (dup_fd < 0) {
-    jniThrowIOException(env, errno);
-    return 0;
-  }
-
-  std::unique_ptr<const ApkAssets> apk_assets = ApkAssets::LoadFromFd(std::move(dup_fd),
-                                                                      friendly_name_utf8.c_str(),
-                                                                      system, force_shared_lib);
-  if (apk_assets == nullptr) {
-    std::string error_msg = base::StringPrintf("Failed to load asset path %s from fd %d",
-                                               friendly_name_utf8.c_str(), dup_fd.get());
-    jniThrowException(env, "java/io/IOException", error_msg.c_str());
-    return 0;
-  }
-  return reinterpret_cast<jlong>(apk_assets.release());
-}
-
-static void NativeDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
-  delete reinterpret_cast<ApkAssets*>(ptr);
-}
-
-static jstring NativeGetAssetPath(JNIEnv* env, jclass /*clazz*/, jlong ptr) {
-  const ApkAssets* apk_assets = reinterpret_cast<const ApkAssets*>(ptr);
-  return env->NewStringUTF(apk_assets->GetPath().c_str());
-}
-
-static jlong NativeGetStringBlock(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
-  const ApkAssets* apk_assets = reinterpret_cast<const ApkAssets*>(ptr);
-  return reinterpret_cast<jlong>(apk_assets->GetLoadedArsc()->GetStringPool());
-}
-
-static jboolean NativeIsUpToDate(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
-  const ApkAssets* apk_assets = reinterpret_cast<const ApkAssets*>(ptr);
-  (void)apk_assets;
-  return JNI_TRUE;
-}
-
-static jlong NativeOpenXml(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring file_name) {
-  ScopedUtfChars path_utf8(env, file_name);
-  if (path_utf8.c_str() == nullptr) {
-    return 0;
-  }
-
-  const ApkAssets* apk_assets = reinterpret_cast<const ApkAssets*>(ptr);
-  std::unique_ptr<Asset> asset = apk_assets->Open(path_utf8.c_str(),
-                                                  Asset::AccessMode::ACCESS_RANDOM);
-  if (asset == nullptr) {
-    jniThrowException(env, "java/io/FileNotFoundException", path_utf8.c_str());
-    return 0;
-  }
-
-  // DynamicRefTable is only needed when looking up resource references. Opening an XML file
-  // directly from an ApkAssets has no notion of proper resource references.
-  std::unique_ptr<ResXMLTree> xml_tree = util::make_unique<ResXMLTree>(nullptr /*dynamicRefTable*/);
-  status_t err = xml_tree->setTo(asset->getBuffer(true), asset->getLength(), true);
-  asset.reset();
-
-  if (err != NO_ERROR) {
-    jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
-    return 0;
-  }
-  return reinterpret_cast<jlong>(xml_tree.release());
-}
-
-// JNI registration.
-static const JNINativeMethod gApkAssetsMethods[] = {
-    {"nativeLoad", "(Ljava/lang/String;ZZZ)J", (void*)NativeLoad},
-    {"nativeLoadFromFd", "(Ljava/io/FileDescriptor;Ljava/lang/String;ZZ)J",
-        (void*)NativeLoadFromFd},
-    {"nativeDestroy", "(J)V", (void*)NativeDestroy},
-    {"nativeGetAssetPath", "(J)Ljava/lang/String;", (void*)NativeGetAssetPath},
-    {"nativeGetStringBlock", "(J)J", (void*)NativeGetStringBlock},
-    {"nativeIsUpToDate", "(J)Z", (void*)NativeIsUpToDate},
-    {"nativeOpenXml", "(JLjava/lang/String;)J", (void*)NativeOpenXml},
-};
-
-int register_android_content_res_ApkAssets(JNIEnv* env) {
-  return RegisterMethodsOrDie(env, "android/content/res/ApkAssets", gApkAssetsMethods,
-                              arraysize(gApkAssetsMethods));
-}
-
-}  // namespace android
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index 403937b..683b4c4 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -1,1437 +1,1851 @@
-/*
- * Copyright 2006, 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.
- */
+/* //device/libs/android_runtime/android_util_AssetManager.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
 
 #define LOG_TAG "asset"
 
+#include <android_runtime/android_util_AssetManager.h>
+
 #include <inttypes.h>
 #include <linux/capability.h>
 #include <stdio.h>
-#include <sys/stat.h>
-#include <sys/system_properties.h>
 #include <sys/types.h>
 #include <sys/wait.h>
+#include <sys/stat.h>
+#include <sys/system_properties.h>
 
 #include <private/android_filesystem_config.h> // for AID_SYSTEM
 
-#include "android-base/logging.h"
-#include "android-base/properties.h"
-#include "android-base/stringprintf.h"
-#include "android_runtime/android_util_AssetManager.h"
-#include "android_runtime/AndroidRuntime.h"
-#include "android_util_Binder.h"
 #include "androidfw/Asset.h"
 #include "androidfw/AssetManager.h"
-#include "androidfw/AssetManager2.h"
 #include "androidfw/AttributeResolution.h"
-#include "androidfw/MutexGuard.h"
 #include "androidfw/ResourceTypes.h"
+#include "android_runtime/AndroidRuntime.h"
+#include "android_util_Binder.h"
 #include "core_jni_helpers.h"
 #include "jni.h"
-#include "nativehelper/JNIHelp.h"
-#include "nativehelper/ScopedPrimitiveArray.h"
-#include "nativehelper/ScopedStringChars.h"
-#include "nativehelper/ScopedUtfChars.h"
+#include <nativehelper/JNIHelp.h>
+#include <nativehelper/ScopedStringChars.h>
+#include <nativehelper/ScopedUtfChars.h>
 #include "utils/Log.h"
-#include "utils/String8.h"
 #include "utils/misc.h"
+#include "utils/String8.h"
 
 extern "C" int capget(cap_user_header_t hdrp, cap_user_data_t datap);
 extern "C" int capset(cap_user_header_t hdrp, const cap_user_data_t datap);
 
-using ::android::base::StringPrintf;
 
 namespace android {
 
+static const bool kThrowOnBadId = false;
+
 // ----------------------------------------------------------------------------
 
-static struct typedvalue_offsets_t {
-  jfieldID mType;
-  jfieldID mData;
-  jfieldID mString;
-  jfieldID mAssetCookie;
-  jfieldID mResourceId;
-  jfieldID mChangingConfigurations;
-  jfieldID mDensity;
+static struct typedvalue_offsets_t
+{
+    jfieldID mType;
+    jfieldID mData;
+    jfieldID mString;
+    jfieldID mAssetCookie;
+    jfieldID mResourceId;
+    jfieldID mChangingConfigurations;
+    jfieldID mDensity;
 } gTypedValueOffsets;
 
-static struct assetfiledescriptor_offsets_t {
-  jfieldID mFd;
-  jfieldID mStartOffset;
-  jfieldID mLength;
+static struct assetfiledescriptor_offsets_t
+{
+    jfieldID mFd;
+    jfieldID mStartOffset;
+    jfieldID mLength;
 } gAssetFileDescriptorOffsets;
 
-static struct assetmanager_offsets_t {
-  jfieldID mObject;
+static struct assetmanager_offsets_t
+{
+    jfieldID mObject;
 } gAssetManagerOffsets;
 
-static struct {
-  jfieldID native_ptr;
-} gApkAssetsFields;
-
-static struct sparsearray_offsets_t {
-  jclass classObject;
-  jmethodID constructor;
-  jmethodID put;
+static struct sparsearray_offsets_t
+{
+    jclass classObject;
+    jmethodID constructor;
+    jmethodID put;
 } gSparseArrayOffsets;
 
-static struct configuration_offsets_t {
-  jclass classObject;
-  jmethodID constructor;
-  jfieldID mSmallestScreenWidthDpOffset;
-  jfieldID mScreenWidthDpOffset;
-  jfieldID mScreenHeightDpOffset;
+static struct configuration_offsets_t
+{
+    jclass classObject;
+    jmethodID constructor;
+    jfieldID mSmallestScreenWidthDpOffset;
+    jfieldID mScreenWidthDpOffset;
+    jfieldID mScreenHeightDpOffset;
 } gConfigurationOffsets;
 
-jclass g_stringClass = nullptr;
+jclass g_stringClass = NULL;
 
 // ----------------------------------------------------------------------------
 
-// Java asset cookies have 0 as an invalid cookie, but TypedArray expects < 0.
-constexpr inline static jint ApkAssetsCookieToJavaCookie(ApkAssetsCookie cookie) {
-  return cookie != kInvalidCookie ? static_cast<jint>(cookie + 1) : -1;
-}
+static jint copyValue(JNIEnv* env, jobject outValue, const ResTable* table,
+                      const Res_value& value, uint32_t ref, ssize_t block,
+                      uint32_t typeSpecFlags, ResTable_config* config = NULL);
 
-constexpr inline static ApkAssetsCookie JavaCookieToApkAssetsCookie(jint cookie) {
-  return cookie > 0 ? static_cast<ApkAssetsCookie>(cookie - 1) : kInvalidCookie;
+jint copyValue(JNIEnv* env, jobject outValue, const ResTable* table,
+               const Res_value& value, uint32_t ref, ssize_t block,
+               uint32_t typeSpecFlags, ResTable_config* config)
+{
+    env->SetIntField(outValue, gTypedValueOffsets.mType, value.dataType);
+    env->SetIntField(outValue, gTypedValueOffsets.mAssetCookie,
+                     static_cast<jint>(table->getTableCookie(block)));
+    env->SetIntField(outValue, gTypedValueOffsets.mData, value.data);
+    env->SetObjectField(outValue, gTypedValueOffsets.mString, NULL);
+    env->SetIntField(outValue, gTypedValueOffsets.mResourceId, ref);
+    env->SetIntField(outValue, gTypedValueOffsets.mChangingConfigurations,
+            typeSpecFlags);
+    if (config != NULL) {
+        env->SetIntField(outValue, gTypedValueOffsets.mDensity, config->density);
+    }
+    return block;
 }
 
 // This is called by zygote (running as user root) as part of preloadResources.
-static void NativeVerifySystemIdmaps(JNIEnv* /*env*/, jclass /*clazz*/) {
-  switch (pid_t pid = fork()) {
-    case -1:
-      PLOG(ERROR) << "failed to fork for idmap";
-      break;
+static void verifySystemIdmaps()
+{
+    pid_t pid;
+    char system_id[10];
 
-    // child
-    case 0: {
-      struct __user_cap_header_struct capheader;
-      struct __user_cap_data_struct capdata;
+    snprintf(system_id, sizeof(system_id), "%d", AID_SYSTEM);
 
-      memset(&capheader, 0, sizeof(capheader));
-      memset(&capdata, 0, sizeof(capdata));
+    switch (pid = fork()) {
+        case -1:
+            ALOGE("failed to fork for idmap: %s", strerror(errno));
+            break;
+        case 0: // child
+            {
+                struct __user_cap_header_struct capheader;
+                struct __user_cap_data_struct capdata;
 
-      capheader.version = _LINUX_CAPABILITY_VERSION;
-      capheader.pid = 0;
+                memset(&capheader, 0, sizeof(capheader));
+                memset(&capdata, 0, sizeof(capdata));
 
-      if (capget(&capheader, &capdata) != 0) {
-        PLOG(ERROR) << "capget";
-        exit(1);
-      }
+                capheader.version = _LINUX_CAPABILITY_VERSION;
+                capheader.pid = 0;
 
-      capdata.effective = capdata.permitted;
-      if (capset(&capheader, &capdata) != 0) {
-        PLOG(ERROR) << "capset";
-        exit(1);
-      }
+                if (capget(&capheader, &capdata) != 0) {
+                    ALOGE("capget: %s\n", strerror(errno));
+                    exit(1);
+                }
 
-      if (setgid(AID_SYSTEM) != 0) {
-        PLOG(ERROR) << "setgid";
-        exit(1);
-      }
+                capdata.effective = capdata.permitted;
+                if (capset(&capheader, &capdata) != 0) {
+                    ALOGE("capset: %s\n", strerror(errno));
+                    exit(1);
+                }
 
-      if (setuid(AID_SYSTEM) != 0) {
-        PLOG(ERROR) << "setuid";
-        exit(1);
-      }
+                if (setgid(AID_SYSTEM) != 0) {
+                    ALOGE("setgid: %s\n", strerror(errno));
+                    exit(1);
+                }
 
-      // Generic idmap parameters
-      const char* argv[8];
-      int argc = 0;
-      struct stat st;
+                if (setuid(AID_SYSTEM) != 0) {
+                    ALOGE("setuid: %s\n", strerror(errno));
+                    exit(1);
+                }
 
-      memset(argv, 0, sizeof(argv));
-      argv[argc++] = AssetManager::IDMAP_BIN;
-      argv[argc++] = "--scan";
-      argv[argc++] = AssetManager::TARGET_PACKAGE_NAME;
-      argv[argc++] = AssetManager::TARGET_APK_PATH;
-      argv[argc++] = AssetManager::IDMAP_DIR;
+                // Generic idmap parameters
+                const char* argv[8];
+                int argc = 0;
+                struct stat st;
 
-      // Directories to scan for overlays: if OVERLAY_THEME_DIR_PROPERTY is defined,
-      // use OVERLAY_DIR/<value of OVERLAY_THEME_DIR_PROPERTY> in addition to OVERLAY_DIR.
-      std::string overlay_theme_path = base::GetProperty(AssetManager::OVERLAY_THEME_DIR_PROPERTY,
-                                                         "");
-      if (!overlay_theme_path.empty()) {
-        overlay_theme_path = std::string(AssetManager::OVERLAY_DIR) + "/" + overlay_theme_path;
-        if (stat(overlay_theme_path.c_str(), &st) == 0) {
-          argv[argc++] = overlay_theme_path.c_str();
-        }
-      }
+                memset(argv, NULL, sizeof(argv));
+                argv[argc++] = AssetManager::IDMAP_BIN;
+                argv[argc++] = "--scan";
+                argv[argc++] = AssetManager::TARGET_PACKAGE_NAME;
+                argv[argc++] = AssetManager::TARGET_APK_PATH;
+                argv[argc++] = AssetManager::IDMAP_DIR;
 
-      if (stat(AssetManager::OVERLAY_DIR, &st) == 0) {
-          argv[argc++] = AssetManager::OVERLAY_DIR;
-      }
+                // Directories to scan for overlays: if OVERLAY_THEME_DIR_PROPERTY is defined,
+                // use OVERLAY_DIR/<value of OVERLAY_THEME_DIR_PROPERTY> in addition to OVERLAY_DIR.
+                char subdir[PROP_VALUE_MAX];
+                int len = __system_property_get(AssetManager::OVERLAY_THEME_DIR_PROPERTY, subdir);
+                if (len > 0) {
+                    String8 overlayPath = String8(AssetManager::OVERLAY_DIR) + "/" + subdir;
+                    if (stat(overlayPath.string(), &st) == 0) {
+                        argv[argc++] = overlayPath.string();
+                    }
+                }
+                if (stat(AssetManager::OVERLAY_DIR, &st) == 0) {
+                    argv[argc++] = AssetManager::OVERLAY_DIR;
+                }
 
-      // Finally, invoke idmap (if any overlay directory exists)
-      if (argc > 5) {
-        execv(AssetManager::IDMAP_BIN, (char* const*)argv);
-        PLOG(ERROR) << "failed to execv for idmap";
-        exit(1); // should never get here
-      } else {
-        exit(0);
-      }
-  } break;
+                if (stat(AssetManager::PRODUCT_OVERLAY_DIR, &st) == 0) {
+                    argv[argc++] = AssetManager::PRODUCT_OVERLAY_DIR;
+                }
 
-  // parent
-  default:
-    waitpid(pid, nullptr, 0);
-    break;
-  }
+                // Finally, invoke idmap (if any overlay directory exists)
+                if (argc > 5) {
+                    execv(AssetManager::IDMAP_BIN, (char* const*)argv);
+                    ALOGE("failed to execv for idmap: %s", strerror(errno));
+                    exit(1); // should never get here
+                } else {
+                    exit(0);
+                }
+            }
+            break;
+        default: // parent
+            waitpid(pid, NULL, 0);
+            break;
+    }
 }
 
-static jint CopyValue(JNIEnv* env, ApkAssetsCookie cookie, const Res_value& value, uint32_t ref,
-                      uint32_t type_spec_flags, ResTable_config* config, jobject out_typed_value) {
-  env->SetIntField(out_typed_value, gTypedValueOffsets.mType, value.dataType);
-  env->SetIntField(out_typed_value, gTypedValueOffsets.mAssetCookie,
-                   ApkAssetsCookieToJavaCookie(cookie));
-  env->SetIntField(out_typed_value, gTypedValueOffsets.mData, value.data);
-  env->SetObjectField(out_typed_value, gTypedValueOffsets.mString, nullptr);
-  env->SetIntField(out_typed_value, gTypedValueOffsets.mResourceId, ref);
-  env->SetIntField(out_typed_value, gTypedValueOffsets.mChangingConfigurations, type_spec_flags);
-  if (config != nullptr) {
-    env->SetIntField(out_typed_value, gTypedValueOffsets.mDensity, config->density);
-  }
-  return static_cast<jint>(ApkAssetsCookieToJavaCookie(cookie));
-}
 
 // ----------------------------------------------------------------------------
 
-// Let the opaque type AAssetManager refer to a guarded AssetManager2 instance.
-struct GuardedAssetManager : public ::AAssetManager {
-  Guarded<AssetManager2> guarded_assetmanager;
-};
-
-::AAssetManager* NdkAssetManagerForJavaObject(JNIEnv* env, jobject jassetmanager) {
-  jlong assetmanager_handle = env->GetLongField(jassetmanager, gAssetManagerOffsets.mObject);
-  ::AAssetManager* am = reinterpret_cast<::AAssetManager*>(assetmanager_handle);
-  if (am == nullptr) {
+// this guy is exported to other jni routines
+AssetManager* assetManagerForJavaObject(JNIEnv* env, jobject obj)
+{
+    jlong amHandle = env->GetLongField(obj, gAssetManagerOffsets.mObject);
+    AssetManager* am = reinterpret_cast<AssetManager*>(amHandle);
+    if (am != NULL) {
+        return am;
+    }
     jniThrowException(env, "java/lang/IllegalStateException", "AssetManager has been finalized!");
-    return nullptr;
-  }
-  return am;
+    return NULL;
 }
 
-Guarded<AssetManager2>* AssetManagerForNdkAssetManager(::AAssetManager* assetmanager) {
-  if (assetmanager == nullptr) {
-    return nullptr;
-  }
-  return &reinterpret_cast<GuardedAssetManager*>(assetmanager)->guarded_assetmanager;
-}
-
-Guarded<AssetManager2>* AssetManagerForJavaObject(JNIEnv* env, jobject jassetmanager) {
-  return AssetManagerForNdkAssetManager(NdkAssetManagerForJavaObject(env, jassetmanager));
-}
-
-static Guarded<AssetManager2>& AssetManagerFromLong(jlong ptr) {
-  return *AssetManagerForNdkAssetManager(reinterpret_cast<AAssetManager*>(ptr));
-}
-
-static jobject ReturnParcelFileDescriptor(JNIEnv* env, std::unique_ptr<Asset> asset,
-                                          jlongArray out_offsets) {
-  off64_t start_offset, length;
-  int fd = asset->openFileDescriptor(&start_offset, &length);
-  asset.reset();
-
-  if (fd < 0) {
-    jniThrowException(env, "java/io/FileNotFoundException",
-                      "This file can not be opened as a file descriptor; it is probably "
-                      "compressed");
-    return nullptr;
-  }
-
-  jlong* offsets = reinterpret_cast<jlong*>(env->GetPrimitiveArrayCritical(out_offsets, 0));
-  if (offsets == nullptr) {
-    close(fd);
-    return nullptr;
-  }
-
-  offsets[0] = start_offset;
-  offsets[1] = length;
-
-  env->ReleasePrimitiveArrayCritical(out_offsets, offsets, 0);
-
-  jobject file_desc = jniCreateFileDescriptor(env, fd);
-  if (file_desc == nullptr) {
-    close(fd);
-    return nullptr;
-  }
-  return newParcelFileDescriptor(env, file_desc);
-}
-
-static jint NativeGetGlobalAssetCount(JNIEnv* /*env*/, jobject /*clazz*/) {
-  return Asset::getGlobalCount();
-}
-
-static jobject NativeGetAssetAllocations(JNIEnv* env, jobject /*clazz*/) {
-  String8 alloc = Asset::getAssetAllocations();
-  if (alloc.length() <= 0) {
-    return nullptr;
-  }
-  return env->NewStringUTF(alloc.string());
-}
-
-static jint NativeGetGlobalAssetManagerCount(JNIEnv* /*env*/, jobject /*clazz*/) {
-  // TODO(adamlesinski): Switch to AssetManager2.
-  return AssetManager::getGlobalCount();
-}
-
-static jlong NativeCreate(JNIEnv* /*env*/, jclass /*clazz*/) {
-  // AssetManager2 needs to be protected by a lock. To avoid cache misses, we allocate the lock and
-  // AssetManager2 in a contiguous block (GuardedAssetManager).
-  return reinterpret_cast<jlong>(new GuardedAssetManager());
-}
-
-static void NativeDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
-  delete reinterpret_cast<GuardedAssetManager*>(ptr);
-}
-
-static void NativeSetApkAssets(JNIEnv* env, jclass /*clazz*/, jlong ptr,
-                               jobjectArray apk_assets_array, jboolean invalidate_caches) {
-  const jsize apk_assets_len = env->GetArrayLength(apk_assets_array);
-  std::vector<const ApkAssets*> apk_assets;
-  apk_assets.reserve(apk_assets_len);
-  for (jsize i = 0; i < apk_assets_len; i++) {
-    jobject obj = env->GetObjectArrayElement(apk_assets_array, i);
-    if (obj == nullptr) {
-      std::string msg = StringPrintf("ApkAssets at index %d is null", i);
-      jniThrowNullPointerException(env, msg.c_str());
-      return;
+static jlong android_content_AssetManager_openAsset(JNIEnv* env, jobject clazz,
+                                                jstring fileName, jint mode)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return 0;
     }
 
-    jlong apk_assets_native_ptr = env->GetLongField(obj, gApkAssetsFields.native_ptr);
-    if (env->ExceptionCheck()) {
-      return;
-    }
-    apk_assets.push_back(reinterpret_cast<const ApkAssets*>(apk_assets_native_ptr));
-  }
+    ALOGV("openAsset in %p (Java object %p)\n", am, clazz);
 
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  assetmanager->SetApkAssets(apk_assets, invalidate_caches);
-}
-
-static void NativeSetConfiguration(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint mcc, jint mnc,
-                                   jstring locale, jint orientation, jint touchscreen, jint density,
-                                   jint keyboard, jint keyboard_hidden, jint navigation,
-                                   jint screen_width, jint screen_height,
-                                   jint smallest_screen_width_dp, jint screen_width_dp,
-                                   jint screen_height_dp, jint screen_layout, jint ui_mode,
-                                   jint color_mode, jint major_version) {
-  ResTable_config configuration;
-  memset(&configuration, 0, sizeof(configuration));
-  configuration.mcc = static_cast<uint16_t>(mcc);
-  configuration.mnc = static_cast<uint16_t>(mnc);
-  configuration.orientation = static_cast<uint8_t>(orientation);
-  configuration.touchscreen = static_cast<uint8_t>(touchscreen);
-  configuration.density = static_cast<uint16_t>(density);
-  configuration.keyboard = static_cast<uint8_t>(keyboard);
-  configuration.inputFlags = static_cast<uint8_t>(keyboard_hidden);
-  configuration.navigation = static_cast<uint8_t>(navigation);
-  configuration.screenWidth = static_cast<uint16_t>(screen_width);
-  configuration.screenHeight = static_cast<uint16_t>(screen_height);
-  configuration.smallestScreenWidthDp = static_cast<uint16_t>(smallest_screen_width_dp);
-  configuration.screenWidthDp = static_cast<uint16_t>(screen_width_dp);
-  configuration.screenHeightDp = static_cast<uint16_t>(screen_height_dp);
-  configuration.screenLayout = static_cast<uint8_t>(screen_layout);
-  configuration.uiMode = static_cast<uint8_t>(ui_mode);
-  configuration.colorMode = static_cast<uint8_t>(color_mode);
-  configuration.sdkVersion = static_cast<uint16_t>(major_version);
-
-  if (locale != nullptr) {
-    ScopedUtfChars locale_utf8(env, locale);
-    CHECK(locale_utf8.c_str() != nullptr);
-    configuration.setBcp47Locale(locale_utf8.c_str());
-  }
-
-  // Constants duplicated from Java class android.content.res.Configuration.
-  static const jint kScreenLayoutRoundMask = 0x300;
-  static const jint kScreenLayoutRoundShift = 8;
-
-  // In Java, we use a 32bit integer for screenLayout, while we only use an 8bit integer
-  // in C++. We must extract the round qualifier out of the Java screenLayout and put it
-  // into screenLayout2.
-  configuration.screenLayout2 =
-      static_cast<uint8_t>((screen_layout & kScreenLayoutRoundMask) >> kScreenLayoutRoundShift);
-
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  assetmanager->SetConfiguration(configuration);
-}
-
-static jobject NativeGetAssignedPackageIdentifiers(JNIEnv* env, jclass /*clazz*/, jlong ptr) {
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-
-  jobject sparse_array =
-        env->NewObject(gSparseArrayOffsets.classObject, gSparseArrayOffsets.constructor);
-
-  if (sparse_array == nullptr) {
-    // An exception is pending.
-    return nullptr;
-  }
-
-  assetmanager->ForEachPackage([&](const std::string& package_name, uint8_t package_id) {
-    jstring jpackage_name = env->NewStringUTF(package_name.c_str());
-    if (jpackage_name == nullptr) {
-      // An exception is pending.
-      return;
+    ScopedUtfChars fileName8(env, fileName);
+    if (fileName8.c_str() == NULL) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", "Empty file name");
+        return -1;
     }
 
-    env->CallVoidMethod(sparse_array, gSparseArrayOffsets.put, static_cast<jint>(package_id),
-                        jpackage_name);
-  });
-  return sparse_array;
+    if (mode != Asset::ACCESS_UNKNOWN && mode != Asset::ACCESS_RANDOM
+        && mode != Asset::ACCESS_STREAMING && mode != Asset::ACCESS_BUFFER) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
+        return -1;
+    }
+
+    Asset* a = am->open(fileName8.c_str(), (Asset::AccessMode)mode);
+
+    if (a == NULL) {
+        jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
+        return -1;
+    }
+
+    //printf("Created Asset Stream: %p\n", a);
+
+    return reinterpret_cast<jlong>(a);
 }
 
-static jobjectArray NativeList(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring path) {
-  ScopedUtfChars path_utf8(env, path);
-  if (path_utf8.c_str() == nullptr) {
-    // This will throw NPE.
-    return nullptr;
-  }
+static jobject returnParcelFileDescriptor(JNIEnv* env, Asset* a, jlongArray outOffsets)
+{
+    off64_t startOffset, length;
+    int fd = a->openFileDescriptor(&startOffset, &length);
+    delete a;
 
-  std::vector<std::string> all_file_paths;
-  {
-    StringPiece normalized_path = path_utf8.c_str();
-    if (normalized_path.data()[0] == '/') {
-      normalized_path = normalized_path.substr(1);
+    if (fd < 0) {
+        jniThrowException(env, "java/io/FileNotFoundException",
+                "This file can not be opened as a file descriptor; it is probably compressed");
+        return NULL;
     }
-    std::string root_path = StringPrintf("assets/%s", normalized_path.data());
-    ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-    for (const ApkAssets* assets : assetmanager->GetApkAssets()) {
-      assets->ForEachFile(root_path, [&](const StringPiece& file_path, FileType type) {
-        if (type == FileType::kFileTypeRegular) {
-          all_file_paths.push_back(file_path.to_string());
+
+    jlong* offsets = (jlong*)env->GetPrimitiveArrayCritical(outOffsets, 0);
+    if (offsets == NULL) {
+        close(fd);
+        return NULL;
+    }
+
+    offsets[0] = startOffset;
+    offsets[1] = length;
+
+    env->ReleasePrimitiveArrayCritical(outOffsets, offsets, 0);
+
+    jobject fileDesc = jniCreateFileDescriptor(env, fd);
+    if (fileDesc == NULL) {
+        close(fd);
+        return NULL;
+    }
+
+    return newParcelFileDescriptor(env, fileDesc);
+}
+
+static jobject android_content_AssetManager_openAssetFd(JNIEnv* env, jobject clazz,
+                                                jstring fileName, jlongArray outOffsets)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return NULL;
+    }
+
+    ALOGV("openAssetFd in %p (Java object %p)\n", am, clazz);
+
+    ScopedUtfChars fileName8(env, fileName);
+    if (fileName8.c_str() == NULL) {
+        return NULL;
+    }
+
+    Asset* a = am->open(fileName8.c_str(), Asset::ACCESS_RANDOM);
+
+    if (a == NULL) {
+        jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
+        return NULL;
+    }
+
+    //printf("Created Asset Stream: %p\n", a);
+
+    return returnParcelFileDescriptor(env, a, outOffsets);
+}
+
+static jlong android_content_AssetManager_openNonAssetNative(JNIEnv* env, jobject clazz,
+                                                         jint cookie,
+                                                         jstring fileName,
+                                                         jint mode)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return 0;
+    }
+
+    ALOGV("openNonAssetNative in %p (Java object %p)\n", am, clazz);
+
+    ScopedUtfChars fileName8(env, fileName);
+    if (fileName8.c_str() == NULL) {
+        return -1;
+    }
+
+    if (mode != Asset::ACCESS_UNKNOWN && mode != Asset::ACCESS_RANDOM
+        && mode != Asset::ACCESS_STREAMING && mode != Asset::ACCESS_BUFFER) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
+        return -1;
+    }
+
+    Asset* a = cookie
+        ? am->openNonAsset(static_cast<int32_t>(cookie), fileName8.c_str(),
+                (Asset::AccessMode)mode)
+        : am->openNonAsset(fileName8.c_str(), (Asset::AccessMode)mode);
+
+    if (a == NULL) {
+        jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
+        return -1;
+    }
+
+    //printf("Created Asset Stream: %p\n", a);
+
+    return reinterpret_cast<jlong>(a);
+}
+
+static jobject android_content_AssetManager_openNonAssetFdNative(JNIEnv* env, jobject clazz,
+                                                         jint cookie,
+                                                         jstring fileName,
+                                                         jlongArray outOffsets)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return NULL;
+    }
+
+    ALOGV("openNonAssetFd in %p (Java object %p)\n", am, clazz);
+
+    ScopedUtfChars fileName8(env, fileName);
+    if (fileName8.c_str() == NULL) {
+        return NULL;
+    }
+
+    Asset* a = cookie
+        ? am->openNonAsset(static_cast<int32_t>(cookie), fileName8.c_str(), Asset::ACCESS_RANDOM)
+        : am->openNonAsset(fileName8.c_str(), Asset::ACCESS_RANDOM);
+
+    if (a == NULL) {
+        jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
+        return NULL;
+    }
+
+    //printf("Created Asset Stream: %p\n", a);
+
+    return returnParcelFileDescriptor(env, a, outOffsets);
+}
+
+static jobjectArray android_content_AssetManager_list(JNIEnv* env, jobject clazz,
+                                                   jstring fileName)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return NULL;
+    }
+
+    ScopedUtfChars fileName8(env, fileName);
+    if (fileName8.c_str() == NULL) {
+        return NULL;
+    }
+
+    AssetDir* dir = am->openDir(fileName8.c_str());
+
+    if (dir == NULL) {
+        jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
+        return NULL;
+    }
+
+    size_t N = dir->getFileCount();
+
+    jobjectArray array = env->NewObjectArray(dir->getFileCount(),
+                                                g_stringClass, NULL);
+    if (array == NULL) {
+        delete dir;
+        return NULL;
+    }
+
+    for (size_t i=0; i<N; i++) {
+        const String8& name = dir->getFileName(i);
+        jstring str = env->NewStringUTF(name.string());
+        if (str == NULL) {
+            delete dir;
+            return NULL;
         }
-      });
-    }
-  }
-
-  jobjectArray array = env->NewObjectArray(all_file_paths.size(), g_stringClass, nullptr);
-  if (array == nullptr) {
-    return nullptr;
-  }
-
-  jsize index = 0;
-  for (const std::string& file_path : all_file_paths) {
-    jstring java_string = env->NewStringUTF(file_path.c_str());
-
-    // Check for errors creating the strings (if malformed or no memory).
-    if (env->ExceptionCheck()) {
-     return nullptr;
+        env->SetObjectArrayElement(array, i, str);
+        env->DeleteLocalRef(str);
     }
 
-    env->SetObjectArrayElement(array, index++, java_string);
+    delete dir;
 
-    // If we have a large amount of string in our array, we might overflow the
-    // local reference table of the VM.
-    env->DeleteLocalRef(java_string);
-  }
-  return array;
+    return array;
 }
 
-static jlong NativeOpenAsset(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring asset_path,
-                             jint access_mode) {
-  ScopedUtfChars asset_path_utf8(env, asset_path);
-  if (asset_path_utf8.c_str() == nullptr) {
-    // This will throw NPE.
-    return 0;
-  }
+static void android_content_AssetManager_destroyAsset(JNIEnv* env, jobject clazz,
+                                                      jlong assetHandle)
+{
+    Asset* a = reinterpret_cast<Asset*>(assetHandle);
 
-  if (access_mode != Asset::ACCESS_UNKNOWN && access_mode != Asset::ACCESS_RANDOM &&
-      access_mode != Asset::ACCESS_STREAMING && access_mode != Asset::ACCESS_BUFFER) {
-    jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
-    return 0;
-  }
+    //printf("Destroying Asset Stream: %p\n", a);
 
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  std::unique_ptr<Asset> asset =
-      assetmanager->Open(asset_path_utf8.c_str(), static_cast<Asset::AccessMode>(access_mode));
-  if (!asset) {
-    jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
-    return 0;
-  }
-  return reinterpret_cast<jlong>(asset.release());
-}
-
-static jobject NativeOpenAssetFd(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring asset_path,
-                                 jlongArray out_offsets) {
-  ScopedUtfChars asset_path_utf8(env, asset_path);
-  if (asset_path_utf8.c_str() == nullptr) {
-    // This will throw NPE.
-    return nullptr;
-  }
-
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  std::unique_ptr<Asset> asset = assetmanager->Open(asset_path_utf8.c_str(), Asset::ACCESS_RANDOM);
-  if (!asset) {
-    jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
-    return nullptr;
-  }
-  return ReturnParcelFileDescriptor(env, std::move(asset), out_offsets);
-}
-
-static jlong NativeOpenNonAsset(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint jcookie,
-                                jstring asset_path, jint access_mode) {
-  ApkAssetsCookie cookie = JavaCookieToApkAssetsCookie(jcookie);
-  ScopedUtfChars asset_path_utf8(env, asset_path);
-  if (asset_path_utf8.c_str() == nullptr) {
-    // This will throw NPE.
-    return 0;
-  }
-
-  if (access_mode != Asset::ACCESS_UNKNOWN && access_mode != Asset::ACCESS_RANDOM &&
-      access_mode != Asset::ACCESS_STREAMING && access_mode != Asset::ACCESS_BUFFER) {
-    jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
-    return 0;
-  }
-
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  std::unique_ptr<Asset> asset;
-  if (cookie != kInvalidCookie) {
-    asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), cookie,
-                                       static_cast<Asset::AccessMode>(access_mode));
-  } else {
-    asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(),
-                                       static_cast<Asset::AccessMode>(access_mode));
-  }
-
-  if (!asset) {
-    jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
-    return 0;
-  }
-  return reinterpret_cast<jlong>(asset.release());
-}
-
-static jobject NativeOpenNonAssetFd(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint jcookie,
-                                    jstring asset_path, jlongArray out_offsets) {
-  ApkAssetsCookie cookie = JavaCookieToApkAssetsCookie(jcookie);
-  ScopedUtfChars asset_path_utf8(env, asset_path);
-  if (asset_path_utf8.c_str() == nullptr) {
-    // This will throw NPE.
-    return nullptr;
-  }
-
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  std::unique_ptr<Asset> asset;
-  if (cookie != kInvalidCookie) {
-    asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), cookie, Asset::ACCESS_RANDOM);
-  } else {
-    asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), Asset::ACCESS_RANDOM);
-  }
-
-  if (!asset) {
-    jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
-    return nullptr;
-  }
-  return ReturnParcelFileDescriptor(env, std::move(asset), out_offsets);
-}
-
-static jlong NativeOpenXmlAsset(JNIEnv* env, jobject /*clazz*/, jlong ptr, jint jcookie,
-                                jstring asset_path) {
-  ApkAssetsCookie cookie = JavaCookieToApkAssetsCookie(jcookie);
-  ScopedUtfChars asset_path_utf8(env, asset_path);
-  if (asset_path_utf8.c_str() == nullptr) {
-    // This will throw NPE.
-    return 0;
-  }
-
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  std::unique_ptr<Asset> asset;
-  if (cookie != kInvalidCookie) {
-    asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), cookie, Asset::ACCESS_RANDOM);
-  } else {
-    asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), Asset::ACCESS_RANDOM, &cookie);
-  }
-
-  if (!asset) {
-    jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
-    return 0;
-  }
-
-  // May be nullptr.
-  const DynamicRefTable* dynamic_ref_table = assetmanager->GetDynamicRefTableForCookie(cookie);
-
-  std::unique_ptr<ResXMLTree> xml_tree = util::make_unique<ResXMLTree>(dynamic_ref_table);
-  status_t err = xml_tree->setTo(asset->getBuffer(true), asset->getLength(), true);
-  asset.reset();
-
-  if (err != NO_ERROR) {
-    jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
-    return 0;
-  }
-  return reinterpret_cast<jlong>(xml_tree.release());
-}
-
-static jint NativeGetResourceValue(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid,
-                                   jshort density, jobject typed_value,
-                                   jboolean resolve_references) {
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  Res_value value;
-  ResTable_config selected_config;
-  uint32_t flags;
-  ApkAssetsCookie cookie =
-      assetmanager->GetResource(static_cast<uint32_t>(resid), false /*may_be_bag*/,
-                                static_cast<uint16_t>(density), &value, &selected_config, &flags);
-  if (cookie == kInvalidCookie) {
-    return ApkAssetsCookieToJavaCookie(kInvalidCookie);
-  }
-
-  uint32_t ref = static_cast<uint32_t>(resid);
-  if (resolve_references) {
-    cookie = assetmanager->ResolveReference(cookie, &value, &selected_config, &flags, &ref);
-    if (cookie == kInvalidCookie) {
-      return ApkAssetsCookieToJavaCookie(kInvalidCookie);
-    }
-  }
-  return CopyValue(env, cookie, value, ref, flags, &selected_config, typed_value);
-}
-
-static jint NativeGetResourceBagValue(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid,
-                                      jint bag_entry_id, jobject typed_value) {
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
-  if (bag == nullptr) {
-    return ApkAssetsCookieToJavaCookie(kInvalidCookie);
-  }
-
-  uint32_t type_spec_flags = bag->type_spec_flags;
-  ApkAssetsCookie cookie = kInvalidCookie;
-  const Res_value* bag_value = nullptr;
-  for (const ResolvedBag::Entry& entry : bag) {
-    if (entry.key == static_cast<uint32_t>(bag_entry_id)) {
-      cookie = entry.cookie;
-      bag_value = &entry.value;
-
-      // Keep searching (the old implementation did that).
-    }
-  }
-
-  if (cookie == kInvalidCookie) {
-    return ApkAssetsCookieToJavaCookie(kInvalidCookie);
-  }
-
-  Res_value value = *bag_value;
-  uint32_t ref = static_cast<uint32_t>(resid);
-  ResTable_config selected_config;
-  cookie = assetmanager->ResolveReference(cookie, &value, &selected_config, &type_spec_flags, &ref);
-  if (cookie == kInvalidCookie) {
-    return ApkAssetsCookieToJavaCookie(kInvalidCookie);
-  }
-  return CopyValue(env, cookie, value, ref, type_spec_flags, nullptr, typed_value);
-}
-
-static jintArray NativeGetStyleAttributes(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
-  if (bag == nullptr) {
-    return nullptr;
-  }
-
-  jintArray array = env->NewIntArray(bag->entry_count);
-  if (env->ExceptionCheck()) {
-    return nullptr;
-  }
-
-  for (uint32_t i = 0; i < bag->entry_count; i++) {
-    jint attr_resid = bag->entries[i].key;
-    env->SetIntArrayRegion(array, i, 1, &attr_resid);
-  }
-  return array;
-}
-
-static jobjectArray NativeGetResourceStringArray(JNIEnv* env, jclass /*clazz*/, jlong ptr,
-                                                 jint resid) {
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
-  if (bag == nullptr) {
-    return nullptr;
-  }
-
-  jobjectArray array = env->NewObjectArray(bag->entry_count, g_stringClass, nullptr);
-  if (array == nullptr) {
-    return nullptr;
-  }
-
-  for (uint32_t i = 0; i < bag->entry_count; i++) {
-    const ResolvedBag::Entry& entry = bag->entries[i];
-
-    // Resolve any references to their final value.
-    Res_value value = entry.value;
-    ResTable_config selected_config;
-    uint32_t flags;
-    uint32_t ref;
-    ApkAssetsCookie cookie =
-        assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
-    if (cookie == kInvalidCookie) {
-      return nullptr;
+    if (a == NULL) {
+        jniThrowNullPointerException(env, "asset");
+        return;
     }
 
-    if (value.dataType == Res_value::TYPE_STRING) {
-      const ApkAssets* apk_assets = assetmanager->GetApkAssets()[cookie];
-      const ResStringPool* pool = apk_assets->GetLoadedArsc()->GetStringPool();
-
-      jstring java_string = nullptr;
-      size_t str_len;
-      const char* str_utf8 = pool->string8At(value.data, &str_len);
-      if (str_utf8 != nullptr) {
-        java_string = env->NewStringUTF(str_utf8);
-      } else {
-        const char16_t* str_utf16 = pool->stringAt(value.data, &str_len);
-        java_string = env->NewString(reinterpret_cast<const jchar*>(str_utf16), str_len);
-      }
-
-      // Check for errors creating the strings (if malformed or no memory).
-      if (env->ExceptionCheck()) {
-        return nullptr;
-      }
-
-      env->SetObjectArrayElement(array, i, java_string);
-
-      // If we have a large amount of string in our array, we might overflow the
-      // local reference table of the VM.
-      env->DeleteLocalRef(java_string);
-    }
-  }
-  return array;
+    delete a;
 }
 
-static jintArray NativeGetResourceStringArrayInfo(JNIEnv* env, jclass /*clazz*/, jlong ptr,
-                                                  jint resid) {
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
-  if (bag == nullptr) {
-    return nullptr;
-  }
+static jint android_content_AssetManager_readAssetChar(JNIEnv* env, jobject clazz,
+                                                       jlong assetHandle)
+{
+    Asset* a = reinterpret_cast<Asset*>(assetHandle);
 
-  jintArray array = env->NewIntArray(bag->entry_count * 2);
-  if (array == nullptr) {
-    return nullptr;
-  }
-
-  jint* buffer = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(array, nullptr));
-  if (buffer == nullptr) {
-    return nullptr;
-  }
-
-  for (size_t i = 0; i < bag->entry_count; i++) {
-    const ResolvedBag::Entry& entry = bag->entries[i];
-    Res_value value = entry.value;
-    ResTable_config selected_config;
-    uint32_t flags;
-    uint32_t ref;
-    ApkAssetsCookie cookie =
-        assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
-    if (cookie == kInvalidCookie) {
-      env->ReleasePrimitiveArrayCritical(array, buffer, JNI_ABORT);
-      return nullptr;
+    if (a == NULL) {
+        jniThrowNullPointerException(env, "asset");
+        return -1;
     }
 
-    jint string_index = -1;
-    if (value.dataType == Res_value::TYPE_STRING) {
-      string_index = static_cast<jint>(value.data);
-    }
-
-    buffer[i * 2] = ApkAssetsCookieToJavaCookie(cookie);
-    buffer[(i * 2) + 1] = string_index;
-  }
-  env->ReleasePrimitiveArrayCritical(array, buffer, 0);
-  return array;
+    uint8_t b;
+    ssize_t res = a->read(&b, 1);
+    return res == 1 ? b : -1;
 }
 
-static jintArray NativeGetResourceIntArray(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
-  if (bag == nullptr) {
-    return nullptr;
-  }
+static jint android_content_AssetManager_readAsset(JNIEnv* env, jobject clazz,
+                                                jlong assetHandle, jbyteArray bArray,
+                                                jint off, jint len)
+{
+    Asset* a = reinterpret_cast<Asset*>(assetHandle);
 
-  jintArray array = env->NewIntArray(bag->entry_count);
-  if (array == nullptr) {
-    return nullptr;
-  }
-
-  jint* buffer = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(array, nullptr));
-  if (buffer == nullptr) {
-    return nullptr;
-  }
-
-  for (size_t i = 0; i < bag->entry_count; i++) {
-    const ResolvedBag::Entry& entry = bag->entries[i];
-    Res_value value = entry.value;
-    ResTable_config selected_config;
-    uint32_t flags;
-    uint32_t ref;
-    ApkAssetsCookie cookie =
-        assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
-    if (cookie == kInvalidCookie) {
-      env->ReleasePrimitiveArrayCritical(array, buffer, JNI_ABORT);
-      return nullptr;
+    if (a == NULL || bArray == NULL) {
+        jniThrowNullPointerException(env, "asset");
+        return -1;
     }
 
-    if (value.dataType >= Res_value::TYPE_FIRST_INT && value.dataType <= Res_value::TYPE_LAST_INT) {
-      buffer[i] = static_cast<jint>(value.data);
+    if (len == 0) {
+        return 0;
     }
-  }
-  env->ReleasePrimitiveArrayCritical(array, buffer, 0);
-  return array;
-}
 
-static jint NativeGetResourceArraySize(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr, jint resid) {
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
-  if (bag == nullptr) {
+    jsize bLen = env->GetArrayLength(bArray);
+    if (off < 0 || off >= bLen || len < 0 || len > bLen || (off+len) > bLen) {
+        jniThrowException(env, "java/lang/IndexOutOfBoundsException", "");
+        return -1;
+    }
+
+    jbyte* b = env->GetByteArrayElements(bArray, NULL);
+    ssize_t res = a->read(b+off, len);
+    env->ReleaseByteArrayElements(bArray, b, 0);
+
+    if (res > 0) return static_cast<jint>(res);
+
+    if (res < 0) {
+        jniThrowException(env, "java/io/IOException", "");
+    }
     return -1;
-  }
-  return static_cast<jint>(bag->entry_count);
 }
 
-static jint NativeGetResourceArray(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid,
-                                   jintArray out_data) {
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
-  if (bag == nullptr) {
-    return -1;
-  }
+static jlong android_content_AssetManager_seekAsset(JNIEnv* env, jobject clazz,
+                                                 jlong assetHandle,
+                                                 jlong offset, jint whence)
+{
+    Asset* a = reinterpret_cast<Asset*>(assetHandle);
 
-  const jsize out_data_length = env->GetArrayLength(out_data);
-  if (env->ExceptionCheck()) {
-    return -1;
-  }
-
-  if (static_cast<jsize>(bag->entry_count) > out_data_length * STYLE_NUM_ENTRIES) {
-    jniThrowException(env, "java/lang/IllegalArgumentException", "Input array is not large enough");
-    return -1;
-  }
-
-  jint* buffer = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_data, nullptr));
-  if (buffer == nullptr) {
-    return -1;
-  }
-
-  jint* cursor = buffer;
-  for (size_t i = 0; i < bag->entry_count; i++) {
-    const ResolvedBag::Entry& entry = bag->entries[i];
-    Res_value value = entry.value;
-    ResTable_config selected_config;
-    selected_config.density = 0;
-    uint32_t flags = bag->type_spec_flags;
-    uint32_t ref;
-    ApkAssetsCookie cookie =
-        assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
-    if (cookie == kInvalidCookie) {
-      env->ReleasePrimitiveArrayCritical(out_data, buffer, JNI_ABORT);
-      return -1;
+    if (a == NULL) {
+        jniThrowNullPointerException(env, "asset");
+        return -1;
     }
 
-    // Deal with the special @null value -- it turns back to TYPE_NULL.
-    if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
-      value.dataType = Res_value::TYPE_NULL;
-      value.data = Res_value::DATA_NULL_UNDEFINED;
+    return a->seek(
+        offset, (whence > 0) ? SEEK_END : (whence < 0 ? SEEK_SET : SEEK_CUR));
+}
+
+static jlong android_content_AssetManager_getAssetLength(JNIEnv* env, jobject clazz,
+                                                      jlong assetHandle)
+{
+    Asset* a = reinterpret_cast<Asset*>(assetHandle);
+
+    if (a == NULL) {
+        jniThrowNullPointerException(env, "asset");
+        return -1;
     }
 
-    cursor[STYLE_TYPE] = static_cast<jint>(value.dataType);
-    cursor[STYLE_DATA] = static_cast<jint>(value.data);
-    cursor[STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(cookie);
-    cursor[STYLE_RESOURCE_ID] = static_cast<jint>(ref);
-    cursor[STYLE_CHANGING_CONFIGURATIONS] = static_cast<jint>(flags);
-    cursor[STYLE_DENSITY] = static_cast<jint>(selected_config.density);
-    cursor += STYLE_NUM_ENTRIES;
-  }
-  env->ReleasePrimitiveArrayCritical(out_data, buffer, 0);
-  return static_cast<jint>(bag->entry_count);
+    return a->getLength();
 }
 
-static jint NativeGetResourceIdentifier(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring name,
-                                        jstring def_type, jstring def_package) {
-  ScopedUtfChars name_utf8(env, name);
-  if (name_utf8.c_str() == nullptr) {
-    // This will throw NPE.
-    return 0;
-  }
+static jlong android_content_AssetManager_getAssetRemainingLength(JNIEnv* env, jobject clazz,
+                                                               jlong assetHandle)
+{
+    Asset* a = reinterpret_cast<Asset*>(assetHandle);
 
-  std::string type;
-  if (def_type != nullptr) {
-    ScopedUtfChars type_utf8(env, def_type);
-    CHECK(type_utf8.c_str() != nullptr);
-    type = type_utf8.c_str();
-  }
-
-  std::string package;
-  if (def_package != nullptr) {
-    ScopedUtfChars package_utf8(env, def_package);
-    CHECK(package_utf8.c_str() != nullptr);
-    package = package_utf8.c_str();
-  }
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  return static_cast<jint>(assetmanager->GetResourceId(name_utf8.c_str(), type, package));
-}
-
-static jstring NativeGetResourceName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  AssetManager2::ResourceName name;
-  if (!assetmanager->GetResourceName(static_cast<uint32_t>(resid), &name)) {
-    return nullptr;
-  }
-
-  std::string result;
-  if (name.package != nullptr) {
-    result.append(name.package, name.package_len);
-  }
-
-  if (name.type != nullptr || name.type16 != nullptr) {
-    if (!result.empty()) {
-      result += ":";
+    if (a == NULL) {
+        jniThrowNullPointerException(env, "asset");
+        return -1;
     }
 
-    if (name.type != nullptr) {
-      result.append(name.type, name.type_len);
-    } else {
-      result += util::Utf16ToUtf8(StringPiece16(name.type16, name.type_len));
-    }
-  }
+    return a->getRemainingLength();
+}
 
-  if (name.entry != nullptr || name.entry16 != nullptr) {
-    if (!result.empty()) {
-      result += "/";
+static jint android_content_AssetManager_addAssetPath(JNIEnv* env, jobject clazz,
+                                                       jstring path, jboolean appAsLib)
+{
+    ScopedUtfChars path8(env, path);
+    if (path8.c_str() == NULL) {
+        return 0;
     }
 
-    if (name.entry != nullptr) {
-      result.append(name.entry, name.entry_len);
-    } else {
-      result += util::Utf16ToUtf8(StringPiece16(name.entry16, name.entry_len));
-    }
-  }
-  return env->NewStringUTF(result.c_str());
-}
-
-static jstring NativeGetResourcePackageName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  AssetManager2::ResourceName name;
-  if (!assetmanager->GetResourceName(static_cast<uint32_t>(resid), &name)) {
-    return nullptr;
-  }
-
-  if (name.package != nullptr) {
-    return env->NewStringUTF(name.package);
-  }
-  return nullptr;
-}
-
-static jstring NativeGetResourceTypeName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  AssetManager2::ResourceName name;
-  if (!assetmanager->GetResourceName(static_cast<uint32_t>(resid), &name)) {
-    return nullptr;
-  }
-
-  if (name.type != nullptr) {
-    return env->NewStringUTF(name.type);
-  } else if (name.type16 != nullptr) {
-    return env->NewString(reinterpret_cast<const jchar*>(name.type16), name.type_len);
-  }
-  return nullptr;
-}
-
-static jstring NativeGetResourceEntryName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  AssetManager2::ResourceName name;
-  if (!assetmanager->GetResourceName(static_cast<uint32_t>(resid), &name)) {
-    return nullptr;
-  }
-
-  if (name.entry != nullptr) {
-    return env->NewStringUTF(name.entry);
-  } else if (name.entry16 != nullptr) {
-    return env->NewString(reinterpret_cast<const jchar*>(name.entry16), name.entry_len);
-  }
-  return nullptr;
-}
-
-static jobjectArray NativeGetLocales(JNIEnv* env, jclass /*class*/, jlong ptr,
-                                     jboolean exclude_system) {
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  std::set<std::string> locales =
-      assetmanager->GetResourceLocales(exclude_system, true /*merge_equivalent_languages*/);
-
-  jobjectArray array = env->NewObjectArray(locales.size(), g_stringClass, nullptr);
-  if (array == nullptr) {
-    return nullptr;
-  }
-
-  size_t idx = 0;
-  for (const std::string& locale : locales) {
-    jstring java_string = env->NewStringUTF(locale.c_str());
-    if (java_string == nullptr) {
-      return nullptr;
-    }
-    env->SetObjectArrayElement(array, idx++, java_string);
-    env->DeleteLocalRef(java_string);
-  }
-  return array;
-}
-
-static jobject ConstructConfigurationObject(JNIEnv* env, const ResTable_config& config) {
-  jobject result =
-      env->NewObject(gConfigurationOffsets.classObject, gConfigurationOffsets.constructor);
-  if (result == nullptr) {
-    return nullptr;
-  }
-
-  env->SetIntField(result, gConfigurationOffsets.mSmallestScreenWidthDpOffset,
-                   config.smallestScreenWidthDp);
-  env->SetIntField(result, gConfigurationOffsets.mScreenWidthDpOffset, config.screenWidthDp);
-  env->SetIntField(result, gConfigurationOffsets.mScreenHeightDpOffset, config.screenHeightDp);
-  return result;
-}
-
-static jobjectArray NativeGetSizeConfigurations(JNIEnv* env, jclass /*clazz*/, jlong ptr) {
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  std::set<ResTable_config> configurations =
-      assetmanager->GetResourceConfigurations(true /*exclude_system*/, false /*exclude_mipmap*/);
-
-  jobjectArray array =
-      env->NewObjectArray(configurations.size(), gConfigurationOffsets.classObject, nullptr);
-  if (array == nullptr) {
-    return nullptr;
-  }
-
-  size_t idx = 0;
-  for (const ResTable_config& configuration : configurations) {
-    jobject java_configuration = ConstructConfigurationObject(env, configuration);
-    if (java_configuration == nullptr) {
-      return nullptr;
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return 0;
     }
 
-    env->SetObjectArrayElement(array, idx++, java_configuration);
-    env->DeleteLocalRef(java_configuration);
-  }
-  return array;
+    int32_t cookie;
+    bool res = am->addAssetPath(String8(path8.c_str()), &cookie, appAsLib);
+
+    return (res) ? static_cast<jint>(cookie) : 0;
 }
 
-static void NativeApplyStyle(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
-                             jint def_style_attr, jint def_style_resid, jlong xml_parser_ptr,
-                             jintArray java_attrs, jlong out_values_ptr, jlong out_indices_ptr) {
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
-  CHECK(theme->GetAssetManager() == &(*assetmanager));
-  (void) assetmanager;
+static jint android_content_AssetManager_addOverlayPath(JNIEnv* env, jobject clazz,
+                                                     jstring idmapPath)
+{
+    ScopedUtfChars idmapPath8(env, idmapPath);
+    if (idmapPath8.c_str() == NULL) {
+        return 0;
+    }
 
-  ResXMLParser* xml_parser = reinterpret_cast<ResXMLParser*>(xml_parser_ptr);
-  uint32_t* out_values = reinterpret_cast<uint32_t*>(out_values_ptr);
-  uint32_t* out_indices = reinterpret_cast<uint32_t*>(out_indices_ptr);
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return 0;
+    }
 
-  jsize attrs_len = env->GetArrayLength(java_attrs);
-  jint* attrs = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(java_attrs, nullptr));
-  if (attrs == nullptr) {
-    return;
-  }
+    int32_t cookie;
+    bool res = am->addOverlayPath(String8(idmapPath8.c_str()), &cookie);
 
-  ApplyStyle(theme, xml_parser, static_cast<uint32_t>(def_style_attr),
-             static_cast<uint32_t>(def_style_resid), reinterpret_cast<uint32_t*>(attrs), attrs_len,
-             out_values, out_indices);
-  env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
+    return (res) ? (jint)cookie : 0;
 }
 
-static jboolean NativeResolveAttrs(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
-                                   jint def_style_attr, jint def_style_resid, jintArray java_values,
-                                   jintArray java_attrs, jintArray out_java_values,
-                                   jintArray out_java_indices) {
-  const jsize attrs_len = env->GetArrayLength(java_attrs);
-  const jsize out_values_len = env->GetArrayLength(out_java_values);
-  if (out_values_len < (attrs_len * STYLE_NUM_ENTRIES)) {
-    jniThrowException(env, "java/lang/IndexOutOfBoundsException", "outValues too small");
-    return JNI_FALSE;
-  }
+static jint android_content_AssetManager_addAssetFd(JNIEnv* env, jobject clazz,
+                                                    jobject fileDescriptor, jstring debugPathName,
+                                                    jboolean appAsLib)
+{
+    ScopedUtfChars debugPathName8(env, debugPathName);
 
-  jint* attrs = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(java_attrs, nullptr));
-  if (attrs == nullptr) {
-    return JNI_FALSE;
-  }
-
-  jint* values = nullptr;
-  jsize values_len = 0;
-  if (java_values != nullptr) {
-    values_len = env->GetArrayLength(java_values);
-    values = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(java_values, nullptr));
-    if (values == nullptr) {
-      env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
-      return JNI_FALSE;
+    int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
+    if (fd < 0) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", "Bad FileDescriptor");
+        return 0;
     }
-  }
 
-  jint* out_values =
-      reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_java_values, nullptr));
-  if (out_values == nullptr) {
-    env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
-    if (values != nullptr) {
-      env->ReleasePrimitiveArrayCritical(java_values, values, JNI_ABORT);
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return 0;
     }
-    return JNI_FALSE;
-  }
 
-  jint* out_indices = nullptr;
-  if (out_java_indices != nullptr) {
-    jsize out_indices_len = env->GetArrayLength(out_java_indices);
-    if (out_indices_len > attrs_len) {
-      out_indices =
-          reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_java_indices, nullptr));
-      if (out_indices == nullptr) {
-        env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
-        if (values != nullptr) {
-          env->ReleasePrimitiveArrayCritical(java_values, values, JNI_ABORT);
+    int dupfd = ::dup(fd);
+    if (dupfd < 0) {
+        jniThrowIOException(env, errno);
+        return 0;
+    }
+
+    int32_t cookie;
+    bool res = am->addAssetFd(dupfd, String8(debugPathName8.c_str()), &cookie, appAsLib);
+
+    return (res) ? static_cast<jint>(cookie) : 0;
+}
+
+static jboolean android_content_AssetManager_isUpToDate(JNIEnv* env, jobject clazz)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return JNI_TRUE;
+    }
+    return am->isUpToDate() ? JNI_TRUE : JNI_FALSE;
+}
+
+static jobjectArray getLocales(JNIEnv* env, jobject clazz, bool includeSystemLocales)
+{
+    Vector<String8> locales;
+
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return NULL;
+    }
+
+    am->getLocales(&locales, includeSystemLocales);
+
+    const int N = locales.size();
+
+    jobjectArray result = env->NewObjectArray(N, g_stringClass, NULL);
+    if (result == NULL) {
+        return NULL;
+    }
+
+    for (int i=0; i<N; i++) {
+        jstring str = env->NewStringUTF(locales[i].string());
+        if (str == NULL) {
+            return NULL;
         }
-        env->ReleasePrimitiveArrayCritical(out_java_values, out_values, JNI_ABORT);
+        env->SetObjectArrayElement(result, i, str);
+        env->DeleteLocalRef(str);
+    }
+
+    return result;
+}
+
+static jobjectArray android_content_AssetManager_getLocales(JNIEnv* env, jobject clazz)
+{
+    return getLocales(env, clazz, true /* include system locales */);
+}
+
+static jobjectArray android_content_AssetManager_getNonSystemLocales(JNIEnv* env, jobject clazz)
+{
+    return getLocales(env, clazz, false /* don't include system locales */);
+}
+
+static jobject constructConfigurationObject(JNIEnv* env, const ResTable_config& config) {
+    jobject result = env->NewObject(gConfigurationOffsets.classObject,
+            gConfigurationOffsets.constructor);
+    if (result == NULL) {
+        return NULL;
+    }
+
+    env->SetIntField(result, gConfigurationOffsets.mSmallestScreenWidthDpOffset,
+            config.smallestScreenWidthDp);
+    env->SetIntField(result, gConfigurationOffsets.mScreenWidthDpOffset, config.screenWidthDp);
+    env->SetIntField(result, gConfigurationOffsets.mScreenHeightDpOffset, config.screenHeightDp);
+
+    return result;
+}
+
+static jobjectArray getSizeConfigurationsInternal(JNIEnv* env,
+        const Vector<ResTable_config>& configs) {
+    const int N = configs.size();
+    jobjectArray result = env->NewObjectArray(N, gConfigurationOffsets.classObject, NULL);
+    if (result == NULL) {
+        return NULL;
+    }
+
+    for (int i=0; i<N; i++) {
+        jobject config = constructConfigurationObject(env, configs[i]);
+        if (config == NULL) {
+            env->DeleteLocalRef(result);
+            return NULL;
+        }
+
+        env->SetObjectArrayElement(result, i, config);
+        env->DeleteLocalRef(config);
+    }
+
+    return result;
+}
+
+static jobjectArray android_content_AssetManager_getSizeConfigurations(JNIEnv* env, jobject clazz) {
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return NULL;
+    }
+
+    const ResTable& res(am->getResources());
+    Vector<ResTable_config> configs;
+    res.getConfigurations(&configs, false /* ignoreMipmap */, true /* ignoreAndroidPackage */);
+
+    return getSizeConfigurationsInternal(env, configs);
+}
+
+static void android_content_AssetManager_setConfiguration(JNIEnv* env, jobject clazz,
+                                                          jint mcc, jint mnc,
+                                                          jstring locale, jint orientation,
+                                                          jint touchscreen, jint density,
+                                                          jint keyboard, jint keyboardHidden,
+                                                          jint navigation,
+                                                          jint screenWidth, jint screenHeight,
+                                                          jint smallestScreenWidthDp,
+                                                          jint screenWidthDp, jint screenHeightDp,
+                                                          jint screenLayout, jint uiMode,
+                                                          jint colorMode, jint sdkVersion)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return;
+    }
+
+    ResTable_config config;
+    memset(&config, 0, sizeof(config));
+
+    const char* locale8 = locale != NULL ? env->GetStringUTFChars(locale, NULL) : NULL;
+
+    // Constants duplicated from Java class android.content.res.Configuration.
+    static const jint kScreenLayoutRoundMask = 0x300;
+    static const jint kScreenLayoutRoundShift = 8;
+
+    config.mcc = (uint16_t)mcc;
+    config.mnc = (uint16_t)mnc;
+    config.orientation = (uint8_t)orientation;
+    config.touchscreen = (uint8_t)touchscreen;
+    config.density = (uint16_t)density;
+    config.keyboard = (uint8_t)keyboard;
+    config.inputFlags = (uint8_t)keyboardHidden;
+    config.navigation = (uint8_t)navigation;
+    config.screenWidth = (uint16_t)screenWidth;
+    config.screenHeight = (uint16_t)screenHeight;
+    config.smallestScreenWidthDp = (uint16_t)smallestScreenWidthDp;
+    config.screenWidthDp = (uint16_t)screenWidthDp;
+    config.screenHeightDp = (uint16_t)screenHeightDp;
+    config.screenLayout = (uint8_t)screenLayout;
+    config.uiMode = (uint8_t)uiMode;
+    config.colorMode = (uint8_t)colorMode;
+    config.sdkVersion = (uint16_t)sdkVersion;
+    config.minorVersion = 0;
+
+    // In Java, we use a 32bit integer for screenLayout, while we only use an 8bit integer
+    // in C++. We must extract the round qualifier out of the Java screenLayout and put it
+    // into screenLayout2.
+    config.screenLayout2 =
+            (uint8_t)((screenLayout & kScreenLayoutRoundMask) >> kScreenLayoutRoundShift);
+
+    am->setConfiguration(config, locale8);
+
+    if (locale != NULL) env->ReleaseStringUTFChars(locale, locale8);
+}
+
+static jint android_content_AssetManager_getResourceIdentifier(JNIEnv* env, jobject clazz,
+                                                            jstring name,
+                                                            jstring defType,
+                                                            jstring defPackage)
+{
+    ScopedStringChars name16(env, name);
+    if (name16.get() == NULL) {
+        return 0;
+    }
+
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return 0;
+    }
+
+    const char16_t* defType16 = reinterpret_cast<const char16_t*>(defType)
+        ? reinterpret_cast<const char16_t*>(env->GetStringChars(defType, NULL))
+        : NULL;
+    jsize defTypeLen = defType
+        ? env->GetStringLength(defType) : 0;
+    const char16_t* defPackage16 = reinterpret_cast<const char16_t*>(defPackage)
+        ? reinterpret_cast<const char16_t*>(env->GetStringChars(defPackage,
+                                                                NULL))
+        : NULL;
+    jsize defPackageLen = defPackage
+        ? env->GetStringLength(defPackage) : 0;
+
+    jint ident = am->getResources().identifierForName(
+        reinterpret_cast<const char16_t*>(name16.get()), name16.size(),
+        defType16, defTypeLen, defPackage16, defPackageLen);
+
+    if (defPackage16) {
+        env->ReleaseStringChars(defPackage,
+                                reinterpret_cast<const jchar*>(defPackage16));
+    }
+    if (defType16) {
+        env->ReleaseStringChars(defType,
+                                reinterpret_cast<const jchar*>(defType16));
+    }
+
+    return ident;
+}
+
+static jstring android_content_AssetManager_getResourceName(JNIEnv* env, jobject clazz,
+                                                            jint resid)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return NULL;
+    }
+
+    ResTable::resource_name name;
+    if (!am->getResources().getResourceName(resid, true, &name)) {
+        return NULL;
+    }
+
+    String16 str;
+    if (name.package != NULL) {
+        str.setTo(name.package, name.packageLen);
+    }
+    if (name.type8 != NULL || name.type != NULL) {
+        if (str.size() > 0) {
+            char16_t div = ':';
+            str.append(&div, 1);
+        }
+        if (name.type8 != NULL) {
+            str.append(String16(name.type8, name.typeLen));
+        } else {
+            str.append(name.type, name.typeLen);
+        }
+    }
+    if (name.name8 != NULL || name.name != NULL) {
+        if (str.size() > 0) {
+            char16_t div = '/';
+            str.append(&div, 1);
+        }
+        if (name.name8 != NULL) {
+            str.append(String16(name.name8, name.nameLen));
+        } else {
+            str.append(name.name, name.nameLen);
+        }
+    }
+
+    return env->NewString((const jchar*)str.string(), str.size());
+}
+
+static jstring android_content_AssetManager_getResourcePackageName(JNIEnv* env, jobject clazz,
+                                                                   jint resid)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return NULL;
+    }
+
+    ResTable::resource_name name;
+    if (!am->getResources().getResourceName(resid, true, &name)) {
+        return NULL;
+    }
+
+    if (name.package != NULL) {
+        return env->NewString((const jchar*)name.package, name.packageLen);
+    }
+
+    return NULL;
+}
+
+static jstring android_content_AssetManager_getResourceTypeName(JNIEnv* env, jobject clazz,
+                                                                jint resid)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return NULL;
+    }
+
+    ResTable::resource_name name;
+    if (!am->getResources().getResourceName(resid, true, &name)) {
+        return NULL;
+    }
+
+    if (name.type8 != NULL) {
+        return env->NewStringUTF(name.type8);
+    }
+
+    if (name.type != NULL) {
+        return env->NewString((const jchar*)name.type, name.typeLen);
+    }
+
+    return NULL;
+}
+
+static jstring android_content_AssetManager_getResourceEntryName(JNIEnv* env, jobject clazz,
+                                                                 jint resid)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return NULL;
+    }
+
+    ResTable::resource_name name;
+    if (!am->getResources().getResourceName(resid, true, &name)) {
+        return NULL;
+    }
+
+    if (name.name8 != NULL) {
+        return env->NewStringUTF(name.name8);
+    }
+
+    if (name.name != NULL) {
+        return env->NewString((const jchar*)name.name, name.nameLen);
+    }
+
+    return NULL;
+}
+
+static jint android_content_AssetManager_loadResourceValue(JNIEnv* env, jobject clazz,
+                                                           jint ident,
+                                                           jshort density,
+                                                           jobject outValue,
+                                                           jboolean resolve)
+{
+    if (outValue == NULL) {
+         jniThrowNullPointerException(env, "outValue");
+         return 0;
+    }
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return 0;
+    }
+    const ResTable& res(am->getResources());
+
+    Res_value value;
+    ResTable_config config;
+    uint32_t typeSpecFlags;
+    ssize_t block = res.getResource(ident, &value, false, density, &typeSpecFlags, &config);
+    if (kThrowOnBadId) {
+        if (block == BAD_INDEX) {
+            jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
+            return 0;
+        }
+    }
+    uint32_t ref = ident;
+    if (resolve) {
+        block = res.resolveReference(&value, block, &ref, &typeSpecFlags, &config);
+        if (kThrowOnBadId) {
+            if (block == BAD_INDEX) {
+                jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
+                return 0;
+            }
+        }
+    }
+    if (block >= 0) {
+        return copyValue(env, outValue, &res, value, ref, block, typeSpecFlags, &config);
+    }
+
+    return static_cast<jint>(block);
+}
+
+static jint android_content_AssetManager_loadResourceBagValue(JNIEnv* env, jobject clazz,
+                                                           jint ident, jint bagEntryId,
+                                                           jobject outValue, jboolean resolve)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return 0;
+    }
+    const ResTable& res(am->getResources());
+
+    // Now lock down the resource object and start pulling stuff from it.
+    res.lock();
+
+    ssize_t block = -1;
+    Res_value value;
+
+    const ResTable::bag_entry* entry = NULL;
+    uint32_t typeSpecFlags;
+    ssize_t entryCount = res.getBagLocked(ident, &entry, &typeSpecFlags);
+
+    for (ssize_t i=0; i<entryCount; i++) {
+        if (((uint32_t)bagEntryId) == entry->map.name.ident) {
+            block = entry->stringBlock;
+            value = entry->map.value;
+        }
+        entry++;
+    }
+
+    res.unlock();
+
+    if (block < 0) {
+        return static_cast<jint>(block);
+    }
+
+    uint32_t ref = ident;
+    if (resolve) {
+        block = res.resolveReference(&value, block, &ref, &typeSpecFlags);
+        if (kThrowOnBadId) {
+            if (block == BAD_INDEX) {
+                jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
+                return 0;
+            }
+        }
+    }
+    if (block >= 0) {
+        return copyValue(env, outValue, &res, value, ref, block, typeSpecFlags);
+    }
+
+    return static_cast<jint>(block);
+}
+
+static jint android_content_AssetManager_getStringBlockCount(JNIEnv* env, jobject clazz)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return 0;
+    }
+    return am->getResources().getTableCount();
+}
+
+static jlong android_content_AssetManager_getNativeStringBlock(JNIEnv* env, jobject clazz,
+                                                           jint block)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return 0;
+    }
+    return reinterpret_cast<jlong>(am->getResources().getTableStringBlock(block));
+}
+
+static jstring android_content_AssetManager_getCookieName(JNIEnv* env, jobject clazz,
+                                                       jint cookie)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return NULL;
+    }
+    String8 name(am->getAssetPath(static_cast<int32_t>(cookie)));
+    if (name.length() == 0) {
+        jniThrowException(env, "java/lang/IndexOutOfBoundsException", "Empty cookie name");
+        return NULL;
+    }
+    jstring str = env->NewStringUTF(name.string());
+    return str;
+}
+
+static jobject android_content_AssetManager_getAssignedPackageIdentifiers(JNIEnv* env, jobject clazz)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return 0;
+    }
+
+    const ResTable& res = am->getResources();
+
+    jobject sparseArray = env->NewObject(gSparseArrayOffsets.classObject,
+            gSparseArrayOffsets.constructor);
+    const size_t N = res.getBasePackageCount();
+    for (size_t i = 0; i < N; i++) {
+        const String16 name = res.getBasePackageName(i);
+        env->CallVoidMethod(
+            sparseArray, gSparseArrayOffsets.put,
+            static_cast<jint>(res.getBasePackageId(i)),
+            env->NewString(reinterpret_cast<const jchar*>(name.string()),
+                           name.size()));
+    }
+    return sparseArray;
+}
+
+static jlong android_content_AssetManager_newTheme(JNIEnv* env, jobject clazz)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return 0;
+    }
+    return reinterpret_cast<jlong>(new ResTable::Theme(am->getResources()));
+}
+
+static void android_content_AssetManager_deleteTheme(JNIEnv* env, jobject clazz,
+                                                     jlong themeHandle)
+{
+    ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
+    delete theme;
+}
+
+static void android_content_AssetManager_applyThemeStyle(JNIEnv* env, jobject clazz,
+                                                         jlong themeHandle,
+                                                         jint styleRes,
+                                                         jboolean force)
+{
+    ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
+    theme->applyStyle(styleRes, force ? true : false);
+}
+
+static void android_content_AssetManager_copyTheme(JNIEnv* env, jobject clazz,
+                                                   jlong destHandle, jlong srcHandle)
+{
+    ResTable::Theme* dest = reinterpret_cast<ResTable::Theme*>(destHandle);
+    ResTable::Theme* src = reinterpret_cast<ResTable::Theme*>(srcHandle);
+    dest->setTo(*src);
+}
+
+static void android_content_AssetManager_clearTheme(JNIEnv* env, jobject clazz, jlong themeHandle)
+{
+    ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
+    theme->clear();
+}
+
+static jint android_content_AssetManager_loadThemeAttributeValue(
+    JNIEnv* env, jobject clazz, jlong themeHandle, jint ident, jobject outValue, jboolean resolve)
+{
+    ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
+    const ResTable& res(theme->getResTable());
+
+    Res_value value;
+    // XXX value could be different in different configs!
+    uint32_t typeSpecFlags = 0;
+    ssize_t block = theme->getAttribute(ident, &value, &typeSpecFlags);
+    uint32_t ref = 0;
+    if (resolve) {
+        block = res.resolveReference(&value, block, &ref, &typeSpecFlags);
+        if (kThrowOnBadId) {
+            if (block == BAD_INDEX) {
+                jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
+                return 0;
+            }
+        }
+    }
+    return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags) : block;
+}
+
+static jint android_content_AssetManager_getThemeChangingConfigurations(JNIEnv* env, jobject clazz,
+                                                                        jlong themeHandle)
+{
+    ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
+    return theme->getChangingConfigurations();
+}
+
+static void android_content_AssetManager_dumpTheme(JNIEnv* env, jobject clazz,
+                                                   jlong themeHandle, jint pri,
+                                                   jstring tag, jstring prefix)
+{
+    ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
+    const ResTable& res(theme->getResTable());
+    (void)res;
+
+    // XXX Need to use params.
+    theme->dumpToLog();
+}
+
+static jboolean android_content_AssetManager_resolveAttrs(JNIEnv* env, jobject clazz,
+                                                          jlong themeToken,
+                                                          jint defStyleAttr,
+                                                          jint defStyleRes,
+                                                          jintArray inValues,
+                                                          jintArray attrs,
+                                                          jintArray outValues,
+                                                          jintArray outIndices)
+{
+    if (themeToken == 0) {
+        jniThrowNullPointerException(env, "theme token");
         return JNI_FALSE;
-      }
     }
-  }
-
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
-  CHECK(theme->GetAssetManager() == &(*assetmanager));
-  (void) assetmanager;
-
-  bool result = ResolveAttrs(
-      theme, static_cast<uint32_t>(def_style_attr), static_cast<uint32_t>(def_style_resid),
-      reinterpret_cast<uint32_t*>(values), values_len, reinterpret_cast<uint32_t*>(attrs),
-      attrs_len, reinterpret_cast<uint32_t*>(out_values), reinterpret_cast<uint32_t*>(out_indices));
-  if (out_indices != nullptr) {
-    env->ReleasePrimitiveArrayCritical(out_java_indices, out_indices, 0);
-  }
-
-  env->ReleasePrimitiveArrayCritical(out_java_values, out_values, 0);
-  if (values != nullptr) {
-    env->ReleasePrimitiveArrayCritical(java_values, values, JNI_ABORT);
-  }
-  env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
-  return result ? JNI_TRUE : JNI_FALSE;
-}
-
-static jboolean NativeRetrieveAttributes(JNIEnv* env, jclass /*clazz*/, jlong ptr,
-                                         jlong xml_parser_ptr, jintArray java_attrs,
-                                         jintArray out_java_values, jintArray out_java_indices) {
-  const jsize attrs_len = env->GetArrayLength(java_attrs);
-  const jsize out_values_len = env->GetArrayLength(out_java_values);
-  if (out_values_len < (attrs_len * STYLE_NUM_ENTRIES)) {
-    jniThrowException(env, "java/lang/IndexOutOfBoundsException", "outValues too small");
-    return JNI_FALSE;
-  }
-
-  jint* attrs = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(java_attrs, nullptr));
-  if (attrs == nullptr) {
-    return JNI_FALSE;
-  }
-
-  jint* out_values =
-      reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_java_values, nullptr));
-  if (out_values == nullptr) {
-    env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
-    return JNI_FALSE;
-  }
-
-  jint* out_indices = nullptr;
-  if (out_java_indices != nullptr) {
-    jsize out_indices_len = env->GetArrayLength(out_java_indices);
-    if (out_indices_len > attrs_len) {
-      out_indices =
-          reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_java_indices, nullptr));
-      if (out_indices == nullptr) {
-        env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
-        env->ReleasePrimitiveArrayCritical(out_java_values, out_values, JNI_ABORT);
+    if (attrs == NULL) {
+        jniThrowNullPointerException(env, "attrs");
         return JNI_FALSE;
-      }
     }
-  }
-
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  ResXMLParser* xml_parser = reinterpret_cast<ResXMLParser*>(xml_parser_ptr);
-
-  bool result = RetrieveAttributes(assetmanager.get(), xml_parser,
-                                   reinterpret_cast<uint32_t*>(attrs), attrs_len,
-                                   reinterpret_cast<uint32_t*>(out_values),
-                                   reinterpret_cast<uint32_t*>(out_indices));
-
-  if (out_indices != nullptr) {
-    env->ReleasePrimitiveArrayCritical(out_java_indices, out_indices, 0);
-  }
-  env->ReleasePrimitiveArrayCritical(out_java_values, out_values, 0);
-  env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
-  return result ? JNI_TRUE : JNI_FALSE;
-}
-
-static jlong NativeThemeCreate(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  return reinterpret_cast<jlong>(assetmanager->NewTheme().release());
-}
-
-static void NativeThemeDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong theme_ptr) {
-  delete reinterpret_cast<Theme*>(theme_ptr);
-}
-
-static void NativeThemeApplyStyle(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
-                                  jint resid, jboolean force) {
-  // AssetManager is accessed via the theme, so grab an explicit lock here.
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
-  CHECK(theme->GetAssetManager() == &(*assetmanager));
-  (void) assetmanager;
-  theme->ApplyStyle(static_cast<uint32_t>(resid), force);
-
-  // TODO(adamlesinski): Consider surfacing exception when result is failure.
-  // CTS currently expects no exceptions from this method.
-  // std::string error_msg = StringPrintf("Failed to apply style 0x%08x to theme", resid);
-  // jniThrowException(env, "java/lang/IllegalArgumentException", error_msg.c_str());
-}
-
-static void NativeThemeCopy(JNIEnv* env, jclass /*clazz*/, jlong dst_theme_ptr,
-                            jlong src_theme_ptr) {
-  Theme* dst_theme = reinterpret_cast<Theme*>(dst_theme_ptr);
-  Theme* src_theme = reinterpret_cast<Theme*>(src_theme_ptr);
-  if (!dst_theme->SetTo(*src_theme)) {
-    jniThrowException(env, "java/lang/IllegalArgumentException",
-                      "Themes are from different AssetManagers");
-  }
-}
-
-static void NativeThemeClear(JNIEnv* /*env*/, jclass /*clazz*/, jlong theme_ptr) {
-  reinterpret_cast<Theme*>(theme_ptr)->Clear();
-}
-
-static jint NativeThemeGetAttributeValue(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
-                                         jint resid, jobject typed_value,
-                                         jboolean resolve_references) {
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
-  CHECK(theme->GetAssetManager() == &(*assetmanager));
-  (void) assetmanager;
-
-  Res_value value;
-  uint32_t flags;
-  ApkAssetsCookie cookie = theme->GetAttribute(static_cast<uint32_t>(resid), &value, &flags);
-  if (cookie == kInvalidCookie) {
-    return ApkAssetsCookieToJavaCookie(kInvalidCookie);
-  }
-
-  uint32_t ref = 0u;
-  if (resolve_references) {
-    ResTable_config selected_config;
-    cookie =
-        theme->GetAssetManager()->ResolveReference(cookie, &value, &selected_config, &flags, &ref);
-    if (cookie == kInvalidCookie) {
-      return ApkAssetsCookieToJavaCookie(kInvalidCookie);
+    if (outValues == NULL) {
+        jniThrowNullPointerException(env, "out values");
+        return JNI_FALSE;
     }
-  }
-  return CopyValue(env, cookie, value, ref, flags, nullptr, typed_value);
+
+    const jsize NI = env->GetArrayLength(attrs);
+    const jsize NV = env->GetArrayLength(outValues);
+    if (NV < (NI*STYLE_NUM_ENTRIES)) {
+        jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
+        return JNI_FALSE;
+    }
+
+    jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
+    if (src == NULL) {
+        return JNI_FALSE;
+    }
+
+    jint* srcValues = (jint*)env->GetPrimitiveArrayCritical(inValues, 0);
+    const jsize NSV = srcValues == NULL ? 0 : env->GetArrayLength(inValues);
+
+    jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
+    if (baseDest == NULL) {
+        env->ReleasePrimitiveArrayCritical(attrs, src, 0);
+        return JNI_FALSE;
+    }
+
+    jint* indices = NULL;
+    if (outIndices != NULL) {
+        if (env->GetArrayLength(outIndices) > NI) {
+            indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
+        }
+    }
+
+    ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeToken);
+    bool result = ResolveAttrs(theme, defStyleAttr, defStyleRes,
+                               (uint32_t*) srcValues, NSV,
+                               (uint32_t*) src, NI,
+                               (uint32_t*) baseDest,
+                               (uint32_t*) indices);
+
+    if (indices != NULL) {
+        env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
+    }
+    env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
+    env->ReleasePrimitiveArrayCritical(inValues, srcValues, 0);
+    env->ReleasePrimitiveArrayCritical(attrs, src, 0);
+    return result ? JNI_TRUE : JNI_FALSE;
 }
 
-static void NativeThemeDump(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
-                            jint priority, jstring tag, jstring prefix) {
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
-  CHECK(theme->GetAssetManager() == &(*assetmanager));
-  (void) assetmanager;
-  (void) theme;
-  (void) priority;
-  (void) tag;
-  (void) prefix;
+static void android_content_AssetManager_applyStyle(JNIEnv* env, jobject, jlong themeToken,
+        jint defStyleAttr, jint defStyleRes, jlong xmlParserToken, jintArray attrsObj, jint length,
+        jlong outValuesAddress, jlong outIndicesAddress) {
+    jint* attrs = env->GetIntArrayElements(attrsObj, 0);
+    ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeToken);
+    ResXMLParser* xmlParser = reinterpret_cast<ResXMLParser*>(xmlParserToken);
+    uint32_t* outValues = reinterpret_cast<uint32_t*>(static_cast<uintptr_t>(outValuesAddress));
+    uint32_t* outIndices = reinterpret_cast<uint32_t*>(static_cast<uintptr_t>(outIndicesAddress));
+    ApplyStyle(theme, xmlParser, defStyleAttr, defStyleRes,
+            reinterpret_cast<const uint32_t*>(attrs), length, outValues, outIndices);
+    env->ReleaseIntArrayElements(attrsObj, attrs, JNI_ABORT);
 }
 
-static jint NativeThemeGetChangingConfigurations(JNIEnv* /*env*/, jclass /*clazz*/,
-                                                 jlong theme_ptr) {
-  Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
-  return static_cast<jint>(theme->GetChangingConfigurations());
+static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, jobject clazz,
+                                                        jlong xmlParserToken,
+                                                        jintArray attrs,
+                                                        jintArray outValues,
+                                                        jintArray outIndices)
+{
+    if (xmlParserToken == 0) {
+        jniThrowNullPointerException(env, "xmlParserToken");
+        return JNI_FALSE;
+    }
+    if (attrs == NULL) {
+        jniThrowNullPointerException(env, "attrs");
+        return JNI_FALSE;
+    }
+    if (outValues == NULL) {
+        jniThrowNullPointerException(env, "out values");
+        return JNI_FALSE;
+    }
+
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return JNI_FALSE;
+    }
+    const ResTable& res(am->getResources());
+    ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken;
+
+    const jsize NI = env->GetArrayLength(attrs);
+    const jsize NV = env->GetArrayLength(outValues);
+    if (NV < (NI*STYLE_NUM_ENTRIES)) {
+        jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
+        return JNI_FALSE;
+    }
+
+    jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
+    if (src == NULL) {
+        return JNI_FALSE;
+    }
+
+    jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
+    if (baseDest == NULL) {
+        env->ReleasePrimitiveArrayCritical(attrs, src, 0);
+        return JNI_FALSE;
+    }
+
+    jint* indices = NULL;
+    if (outIndices != NULL) {
+        if (env->GetArrayLength(outIndices) > NI) {
+            indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
+        }
+    }
+
+    bool result = RetrieveAttributes(&res, xmlParser,
+                                     (uint32_t*) src, NI,
+                                     (uint32_t*) baseDest,
+                                     (uint32_t*) indices);
+
+    if (indices != NULL) {
+        env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
+    }
+    env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
+    env->ReleasePrimitiveArrayCritical(attrs, src, 0);
+    return result ? JNI_TRUE : JNI_FALSE;
 }
 
-static void NativeAssetDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
-  delete reinterpret_cast<Asset*>(asset_ptr);
+static jint android_content_AssetManager_getArraySize(JNIEnv* env, jobject clazz,
+                                                       jint id)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return 0;
+    }
+    const ResTable& res(am->getResources());
+
+    res.lock();
+    const ResTable::bag_entry* defStyleEnt = NULL;
+    ssize_t bagOff = res.getBagLocked(id, &defStyleEnt);
+    res.unlock();
+
+    return static_cast<jint>(bagOff);
 }
 
-static jint NativeAssetReadChar(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
-  Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
-  uint8_t b;
-  ssize_t res = asset->read(&b, sizeof(b));
-  return res == sizeof(b) ? static_cast<jint>(b) : -1;
+static jint android_content_AssetManager_retrieveArray(JNIEnv* env, jobject clazz,
+                                                        jint id,
+                                                        jintArray outValues)
+{
+    if (outValues == NULL) {
+        jniThrowNullPointerException(env, "out values");
+        return JNI_FALSE;
+    }
+
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return JNI_FALSE;
+    }
+    const ResTable& res(am->getResources());
+    ResTable_config config;
+    Res_value value;
+    ssize_t block;
+
+    const jsize NV = env->GetArrayLength(outValues);
+
+    jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
+    jint* dest = baseDest;
+    if (dest == NULL) {
+        jniThrowException(env, "java/lang/OutOfMemoryError", "");
+        return JNI_FALSE;
+    }
+
+    // Now lock down the resource object and start pulling stuff from it.
+    res.lock();
+
+    const ResTable::bag_entry* arrayEnt = NULL;
+    uint32_t arrayTypeSetFlags = 0;
+    ssize_t bagOff = res.getBagLocked(id, &arrayEnt, &arrayTypeSetFlags);
+    const ResTable::bag_entry* endArrayEnt = arrayEnt +
+        (bagOff >= 0 ? bagOff : 0);
+
+    int i = 0;
+    uint32_t typeSetFlags;
+    while (i < NV && arrayEnt < endArrayEnt) {
+        block = arrayEnt->stringBlock;
+        typeSetFlags = arrayTypeSetFlags;
+        config.density = 0;
+        value = arrayEnt->map.value;
+
+        uint32_t resid = 0;
+        if (value.dataType != Res_value::TYPE_NULL) {
+            // Take care of resolving the found resource to its final value.
+            //printf("Resolving attribute reference\n");
+            ssize_t newBlock = res.resolveReference(&value, block, &resid,
+                    &typeSetFlags, &config);
+            if (kThrowOnBadId) {
+                if (newBlock == BAD_INDEX) {
+                    jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
+                    return JNI_FALSE;
+                }
+            }
+            if (newBlock >= 0) block = newBlock;
+        }
+
+        // Deal with the special @null value -- it turns back to TYPE_NULL.
+        if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
+            value.dataType = Res_value::TYPE_NULL;
+            value.data = Res_value::DATA_NULL_UNDEFINED;
+        }
+
+        //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
+
+        // Write the final value back to Java.
+        dest[STYLE_TYPE] = value.dataType;
+        dest[STYLE_DATA] = value.data;
+        dest[STYLE_ASSET_COOKIE] = reinterpret_cast<jint>(res.getTableCookie(block));
+        dest[STYLE_RESOURCE_ID] = resid;
+        dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
+        dest[STYLE_DENSITY] = config.density;
+        dest += STYLE_NUM_ENTRIES;
+        i+= STYLE_NUM_ENTRIES;
+        arrayEnt++;
+    }
+
+    i /= STYLE_NUM_ENTRIES;
+
+    res.unlock();
+
+    env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
+
+    return i;
 }
 
-static jint NativeAssetRead(JNIEnv* env, jclass /*clazz*/, jlong asset_ptr, jbyteArray java_buffer,
-                            jint offset, jint len) {
-  if (len == 0) {
-    return 0;
-  }
+static jlong android_content_AssetManager_openXmlAssetNative(JNIEnv* env, jobject clazz,
+                                                         jint cookie,
+                                                         jstring fileName)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return 0;
+    }
 
-  jsize buffer_len = env->GetArrayLength(java_buffer);
-  if (offset < 0 || offset >= buffer_len || len < 0 || len > buffer_len ||
-      offset > buffer_len - len) {
-    jniThrowException(env, "java/lang/IndexOutOfBoundsException", "");
-    return -1;
-  }
+    ALOGV("openXmlAsset in %p (Java object %p)\n", am, clazz);
 
-  ScopedByteArrayRW byte_array(env, java_buffer);
-  if (byte_array.get() == nullptr) {
-    return -1;
-  }
+    ScopedUtfChars fileName8(env, fileName);
+    if (fileName8.c_str() == NULL) {
+        return 0;
+    }
 
-  Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
-  ssize_t res = asset->read(byte_array.get() + offset, len);
-  if (res < 0) {
-    jniThrowException(env, "java/io/IOException", "");
-    return -1;
-  }
-  return res > 0 ? static_cast<jint>(res) : -1;
+    int32_t assetCookie = static_cast<int32_t>(cookie);
+    Asset* a = assetCookie
+        ? am->openNonAsset(assetCookie, fileName8.c_str(), Asset::ACCESS_BUFFER)
+        : am->openNonAsset(fileName8.c_str(), Asset::ACCESS_BUFFER, &assetCookie);
+
+    if (a == NULL) {
+        jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
+        return 0;
+    }
+
+    const DynamicRefTable* dynamicRefTable =
+            am->getResources().getDynamicRefTableForCookie(assetCookie);
+    ResXMLTree* block = new ResXMLTree(dynamicRefTable);
+    status_t err = block->setTo(a->getBuffer(true), a->getLength(), true);
+    a->close();
+    delete a;
+
+    if (err != NO_ERROR) {
+        jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
+        return 0;
+    }
+
+    return reinterpret_cast<jlong>(block);
 }
 
-static jlong NativeAssetSeek(JNIEnv* env, jclass /*clazz*/, jlong asset_ptr, jlong offset,
-                             jint whence) {
-  Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
-  return static_cast<jlong>(asset->seek(
-      static_cast<off64_t>(offset), (whence > 0 ? SEEK_END : (whence < 0 ? SEEK_SET : SEEK_CUR))));
+static jintArray android_content_AssetManager_getArrayStringInfo(JNIEnv* env, jobject clazz,
+                                                                 jint arrayResId)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return NULL;
+    }
+    const ResTable& res(am->getResources());
+
+    const ResTable::bag_entry* startOfBag;
+    const ssize_t N = res.lockBag(arrayResId, &startOfBag);
+    if (N < 0) {
+        return NULL;
+    }
+
+    jintArray array = env->NewIntArray(N * 2);
+    if (array == NULL) {
+        res.unlockBag(startOfBag);
+        return NULL;
+    }
+
+    Res_value value;
+    const ResTable::bag_entry* bag = startOfBag;
+    for (size_t i = 0, j = 0; ((ssize_t)i)<N; i++, bag++) {
+        jint stringIndex = -1;
+        jint stringBlock = 0;
+        value = bag->map.value;
+
+        // Take care of resolving the found resource to its final value.
+        stringBlock = res.resolveReference(&value, bag->stringBlock, NULL);
+        if (value.dataType == Res_value::TYPE_STRING) {
+            stringIndex = value.data;
+        }
+
+        if (kThrowOnBadId) {
+            if (stringBlock == BAD_INDEX) {
+                jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
+                return array;
+            }
+        }
+
+        //todo: It might be faster to allocate a C array to contain
+        //      the blocknums and indices, put them in there and then
+        //      do just one SetIntArrayRegion()
+        env->SetIntArrayRegion(array, j, 1, &stringBlock);
+        env->SetIntArrayRegion(array, j + 1, 1, &stringIndex);
+        j = j + 2;
+    }
+    res.unlockBag(startOfBag);
+    return array;
 }
 
-static jlong NativeAssetGetLength(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
-  Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
-  return static_cast<jlong>(asset->getLength());
+static jobjectArray android_content_AssetManager_getArrayStringResource(JNIEnv* env, jobject clazz,
+                                                                        jint arrayResId)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return NULL;
+    }
+    const ResTable& res(am->getResources());
+
+    const ResTable::bag_entry* startOfBag;
+    const ssize_t N = res.lockBag(arrayResId, &startOfBag);
+    if (N < 0) {
+        return NULL;
+    }
+
+    jobjectArray array = env->NewObjectArray(N, g_stringClass, NULL);
+    if (env->ExceptionCheck()) {
+        res.unlockBag(startOfBag);
+        return NULL;
+    }
+
+    Res_value value;
+    const ResTable::bag_entry* bag = startOfBag;
+    size_t strLen = 0;
+    for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
+        value = bag->map.value;
+        jstring str = NULL;
+
+        // Take care of resolving the found resource to its final value.
+        ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
+        if (kThrowOnBadId) {
+            if (block == BAD_INDEX) {
+                jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
+                return array;
+            }
+        }
+        if (value.dataType == Res_value::TYPE_STRING) {
+            const ResStringPool* pool = res.getTableStringBlock(block);
+            const char* str8 = pool->string8At(value.data, &strLen);
+            if (str8 != NULL) {
+                str = env->NewStringUTF(str8);
+            } else {
+                const char16_t* str16 = pool->stringAt(value.data, &strLen);
+                str = env->NewString(reinterpret_cast<const jchar*>(str16),
+                                     strLen);
+            }
+
+            // If one of our NewString{UTF} calls failed due to memory, an
+            // exception will be pending.
+            if (env->ExceptionCheck()) {
+                res.unlockBag(startOfBag);
+                return NULL;
+            }
+
+            env->SetObjectArrayElement(array, i, str);
+
+            // str is not NULL at that point, otherwise ExceptionCheck would have been true.
+            // If we have a large amount of strings in our array, we might
+            // overflow the local reference table of the VM.
+            env->DeleteLocalRef(str);
+        }
+    }
+    res.unlockBag(startOfBag);
+    return array;
 }
 
-static jlong NativeAssetGetRemainingLength(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
-  Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
-  return static_cast<jlong>(asset->getRemainingLength());
+static jintArray android_content_AssetManager_getArrayIntResource(JNIEnv* env, jobject clazz,
+                                                                        jint arrayResId)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return NULL;
+    }
+    const ResTable& res(am->getResources());
+
+    const ResTable::bag_entry* startOfBag;
+    const ssize_t N = res.lockBag(arrayResId, &startOfBag);
+    if (N < 0) {
+        return NULL;
+    }
+
+    jintArray array = env->NewIntArray(N);
+    if (array == NULL) {
+        res.unlockBag(startOfBag);
+        return NULL;
+    }
+
+    Res_value value;
+    const ResTable::bag_entry* bag = startOfBag;
+    for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
+        value = bag->map.value;
+
+        // Take care of resolving the found resource to its final value.
+        ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
+        if (kThrowOnBadId) {
+            if (block == BAD_INDEX) {
+                jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
+                return array;
+            }
+        }
+        if (value.dataType >= Res_value::TYPE_FIRST_INT
+                && value.dataType <= Res_value::TYPE_LAST_INT) {
+            int intVal = value.data;
+            env->SetIntArrayRegion(array, i, 1, &intVal);
+        }
+    }
+    res.unlockBag(startOfBag);
+    return array;
+}
+
+static jintArray android_content_AssetManager_getStyleAttributes(JNIEnv* env, jobject clazz,
+                                                                 jint styleId)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return NULL;
+    }
+    const ResTable& res(am->getResources());
+
+    const ResTable::bag_entry* startOfBag;
+    const ssize_t N = res.lockBag(styleId, &startOfBag);
+    if (N < 0) {
+        return NULL;
+    }
+
+    jintArray array = env->NewIntArray(N);
+    if (array == NULL) {
+        res.unlockBag(startOfBag);
+        return NULL;
+    }
+
+    const ResTable::bag_entry* bag = startOfBag;
+    for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
+        int resourceId = bag->map.name.ident;
+        env->SetIntArrayRegion(array, i, 1, &resourceId);
+    }
+    res.unlockBag(startOfBag);
+    return array;
+}
+
+static void android_content_AssetManager_init(JNIEnv* env, jobject clazz, jboolean isSystem)
+{
+    if (isSystem) {
+        verifySystemIdmaps();
+    }
+    AssetManager* am = new AssetManager();
+    if (am == NULL) {
+        jniThrowException(env, "java/lang/OutOfMemoryError", "");
+        return;
+    }
+
+    am->addDefaultAssets();
+
+    ALOGV("Created AssetManager %p for Java object %p\n", am, clazz);
+    env->SetLongField(clazz, gAssetManagerOffsets.mObject, reinterpret_cast<jlong>(am));
+}
+
+static void android_content_AssetManager_destroy(JNIEnv* env, jobject clazz)
+{
+    AssetManager* am = (AssetManager*)
+        (env->GetLongField(clazz, gAssetManagerOffsets.mObject));
+    ALOGV("Destroying AssetManager %p for Java object %p\n", am, clazz);
+    if (am != NULL) {
+        delete am;
+        env->SetLongField(clazz, gAssetManagerOffsets.mObject, 0);
+    }
+}
+
+static jint android_content_AssetManager_getGlobalAssetCount(JNIEnv* env, jobject clazz)
+{
+    return Asset::getGlobalCount();
+}
+
+static jobject android_content_AssetManager_getAssetAllocations(JNIEnv* env, jobject clazz)
+{
+    String8 alloc = Asset::getAssetAllocations();
+    if (alloc.length() <= 0) {
+        return NULL;
+    }
+
+    jstring str = env->NewStringUTF(alloc.string());
+    return str;
+}
+
+static jint android_content_AssetManager_getGlobalAssetManagerCount(JNIEnv* env, jobject clazz)
+{
+    return AssetManager::getGlobalCount();
 }
 
 // ----------------------------------------------------------------------------
 
-// JNI registration.
+/*
+ * JNI registration.
+ */
 static const JNINativeMethod gAssetManagerMethods[] = {
-    // AssetManager setup methods.
-    {"nativeCreate", "()J", (void*)NativeCreate},
-    {"nativeDestroy", "(J)V", (void*)NativeDestroy},
-    {"nativeSetApkAssets", "(J[Landroid/content/res/ApkAssets;Z)V", (void*)NativeSetApkAssets},
-    {"nativeSetConfiguration", "(JIILjava/lang/String;IIIIIIIIIIIIIII)V",
-     (void*)NativeSetConfiguration},
-    {"nativeGetAssignedPackageIdentifiers", "(J)Landroid/util/SparseArray;",
-     (void*)NativeGetAssignedPackageIdentifiers},
+    /* name, signature, funcPtr */
 
-    // AssetManager file methods.
-    {"nativeList", "(JLjava/lang/String;)[Ljava/lang/String;", (void*)NativeList},
-    {"nativeOpenAsset", "(JLjava/lang/String;I)J", (void*)NativeOpenAsset},
-    {"nativeOpenAssetFd", "(JLjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
-     (void*)NativeOpenAssetFd},
-    {"nativeOpenNonAsset", "(JILjava/lang/String;I)J", (void*)NativeOpenNonAsset},
-    {"nativeOpenNonAssetFd", "(JILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
-     (void*)NativeOpenNonAssetFd},
-    {"nativeOpenXmlAsset", "(JILjava/lang/String;)J", (void*)NativeOpenXmlAsset},
+    // Basic asset stuff.
+    { "openAsset",      "(Ljava/lang/String;I)J",
+        (void*) android_content_AssetManager_openAsset },
+    { "openAssetFd",      "(Ljava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
+        (void*) android_content_AssetManager_openAssetFd },
+    { "openNonAssetNative", "(ILjava/lang/String;I)J",
+        (void*) android_content_AssetManager_openNonAssetNative },
+    { "openNonAssetFdNative", "(ILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
+        (void*) android_content_AssetManager_openNonAssetFdNative },
+    { "list",           "(Ljava/lang/String;)[Ljava/lang/String;",
+        (void*) android_content_AssetManager_list },
+    { "destroyAsset",   "(J)V",
+        (void*) android_content_AssetManager_destroyAsset },
+    { "readAssetChar",  "(J)I",
+        (void*) android_content_AssetManager_readAssetChar },
+    { "readAsset",      "(J[BII)I",
+        (void*) android_content_AssetManager_readAsset },
+    { "seekAsset",      "(JJI)J",
+        (void*) android_content_AssetManager_seekAsset },
+    { "getAssetLength", "(J)J",
+        (void*) android_content_AssetManager_getAssetLength },
+    { "getAssetRemainingLength", "(J)J",
+        (void*) android_content_AssetManager_getAssetRemainingLength },
+    { "addAssetPathNative", "(Ljava/lang/String;Z)I",
+        (void*) android_content_AssetManager_addAssetPath },
+    { "addAssetFdNative", "(Ljava/io/FileDescriptor;Ljava/lang/String;Z)I",
+        (void*) android_content_AssetManager_addAssetFd },
+    { "addOverlayPathNative",   "(Ljava/lang/String;)I",
+        (void*) android_content_AssetManager_addOverlayPath },
+    { "isUpToDate",     "()Z",
+        (void*) android_content_AssetManager_isUpToDate },
 
-    // AssetManager resource methods.
-    {"nativeGetResourceValue", "(JISLandroid/util/TypedValue;Z)I", (void*)NativeGetResourceValue},
-    {"nativeGetResourceBagValue", "(JIILandroid/util/TypedValue;)I",
-     (void*)NativeGetResourceBagValue},
-    {"nativeGetStyleAttributes", "(JI)[I", (void*)NativeGetStyleAttributes},
-    {"nativeGetResourceStringArray", "(JI)[Ljava/lang/String;",
-     (void*)NativeGetResourceStringArray},
-    {"nativeGetResourceStringArrayInfo", "(JI)[I", (void*)NativeGetResourceStringArrayInfo},
-    {"nativeGetResourceIntArray", "(JI)[I", (void*)NativeGetResourceIntArray},
-    {"nativeGetResourceArraySize", "(JI)I", (void*)NativeGetResourceArraySize},
-    {"nativeGetResourceArray", "(JI[I)I", (void*)NativeGetResourceArray},
+    // Resources.
+    { "getLocales",      "()[Ljava/lang/String;",
+        (void*) android_content_AssetManager_getLocales },
+    { "getNonSystemLocales", "()[Ljava/lang/String;",
+        (void*) android_content_AssetManager_getNonSystemLocales },
+    { "getSizeConfigurations", "()[Landroid/content/res/Configuration;",
+        (void*) android_content_AssetManager_getSizeConfigurations },
+    { "setConfiguration", "(IILjava/lang/String;IIIIIIIIIIIIIII)V",
+        (void*) android_content_AssetManager_setConfiguration },
+    { "getResourceIdentifier","(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
+        (void*) android_content_AssetManager_getResourceIdentifier },
+    { "getResourceName","(I)Ljava/lang/String;",
+        (void*) android_content_AssetManager_getResourceName },
+    { "getResourcePackageName","(I)Ljava/lang/String;",
+        (void*) android_content_AssetManager_getResourcePackageName },
+    { "getResourceTypeName","(I)Ljava/lang/String;",
+        (void*) android_content_AssetManager_getResourceTypeName },
+    { "getResourceEntryName","(I)Ljava/lang/String;",
+        (void*) android_content_AssetManager_getResourceEntryName },
+    { "loadResourceValue","(ISLandroid/util/TypedValue;Z)I",
+        (void*) android_content_AssetManager_loadResourceValue },
+    { "loadResourceBagValue","(IILandroid/util/TypedValue;Z)I",
+        (void*) android_content_AssetManager_loadResourceBagValue },
+    { "getStringBlockCount","()I",
+        (void*) android_content_AssetManager_getStringBlockCount },
+    { "getNativeStringBlock","(I)J",
+        (void*) android_content_AssetManager_getNativeStringBlock },
+    { "getCookieName","(I)Ljava/lang/String;",
+        (void*) android_content_AssetManager_getCookieName },
+    { "getAssignedPackageIdentifiers","()Landroid/util/SparseArray;",
+        (void*) android_content_AssetManager_getAssignedPackageIdentifiers },
 
-    // AssetManager resource name/ID methods.
-    {"nativeGetResourceIdentifier", "(JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
-     (void*)NativeGetResourceIdentifier},
-    {"nativeGetResourceName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceName},
-    {"nativeGetResourcePackageName", "(JI)Ljava/lang/String;", (void*)NativeGetResourcePackageName},
-    {"nativeGetResourceTypeName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceTypeName},
-    {"nativeGetResourceEntryName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceEntryName},
-    {"nativeGetLocales", "(JZ)[Ljava/lang/String;", (void*)NativeGetLocales},
-    {"nativeGetSizeConfigurations", "(J)[Landroid/content/res/Configuration;",
-     (void*)NativeGetSizeConfigurations},
+    // Themes.
+    { "newTheme", "()J",
+        (void*) android_content_AssetManager_newTheme },
+    { "deleteTheme", "(J)V",
+        (void*) android_content_AssetManager_deleteTheme },
+    { "applyThemeStyle", "(JIZ)V",
+        (void*) android_content_AssetManager_applyThemeStyle },
+    { "copyTheme", "(JJ)V",
+        (void*) android_content_AssetManager_copyTheme },
+    { "clearTheme", "(J)V",
+        (void*) android_content_AssetManager_clearTheme },
+    { "loadThemeAttributeValue", "(JILandroid/util/TypedValue;Z)I",
+        (void*) android_content_AssetManager_loadThemeAttributeValue },
+    { "getThemeChangingConfigurations", "(J)I",
+        (void*) android_content_AssetManager_getThemeChangingConfigurations },
+    { "dumpTheme", "(JILjava/lang/String;Ljava/lang/String;)V",
+        (void*) android_content_AssetManager_dumpTheme },
+    { "applyStyle","(JIIJ[IIJJ)V",
+        (void*) android_content_AssetManager_applyStyle },
+    { "resolveAttrs","(JII[I[I[I[I)Z",
+        (void*) android_content_AssetManager_resolveAttrs },
+    { "retrieveAttributes","(J[I[I[I)Z",
+        (void*) android_content_AssetManager_retrieveAttributes },
+    { "getArraySize","(I)I",
+        (void*) android_content_AssetManager_getArraySize },
+    { "retrieveArray","(I[I)I",
+        (void*) android_content_AssetManager_retrieveArray },
 
-    // Style attribute related methods.
-    {"nativeApplyStyle", "(JJIIJ[IJJ)V", (void*)NativeApplyStyle},
-    {"nativeResolveAttrs", "(JJII[I[I[I[I)Z", (void*)NativeResolveAttrs},
-    {"nativeRetrieveAttributes", "(JJ[I[I[I)Z", (void*)NativeRetrieveAttributes},
+    // XML files.
+    { "openXmlAssetNative", "(ILjava/lang/String;)J",
+        (void*) android_content_AssetManager_openXmlAssetNative },
 
-    // Theme related methods.
-    {"nativeThemeCreate", "(J)J", (void*)NativeThemeCreate},
-    {"nativeThemeDestroy", "(J)V", (void*)NativeThemeDestroy},
-    {"nativeThemeApplyStyle", "(JJIZ)V", (void*)NativeThemeApplyStyle},
-    {"nativeThemeCopy", "(JJ)V", (void*)NativeThemeCopy},
-    {"nativeThemeClear", "(J)V", (void*)NativeThemeClear},
-    {"nativeThemeGetAttributeValue", "(JJILandroid/util/TypedValue;Z)I",
-     (void*)NativeThemeGetAttributeValue},
-    {"nativeThemeDump", "(JJILjava/lang/String;Ljava/lang/String;)V", (void*)NativeThemeDump},
-    {"nativeThemeGetChangingConfigurations", "(J)I", (void*)NativeThemeGetChangingConfigurations},
+    // Arrays.
+    { "getArrayStringResource","(I)[Ljava/lang/String;",
+        (void*) android_content_AssetManager_getArrayStringResource },
+    { "getArrayStringInfo","(I)[I",
+        (void*) android_content_AssetManager_getArrayStringInfo },
+    { "getArrayIntResource","(I)[I",
+        (void*) android_content_AssetManager_getArrayIntResource },
+    { "getStyleAttributes","(I)[I",
+        (void*) android_content_AssetManager_getStyleAttributes },
 
-    // AssetInputStream methods.
-    {"nativeAssetDestroy", "(J)V", (void*)NativeAssetDestroy},
-    {"nativeAssetReadChar", "(J)I", (void*)NativeAssetReadChar},
-    {"nativeAssetRead", "(J[BII)I", (void*)NativeAssetRead},
-    {"nativeAssetSeek", "(JJI)J", (void*)NativeAssetSeek},
-    {"nativeAssetGetLength", "(J)J", (void*)NativeAssetGetLength},
-    {"nativeAssetGetRemainingLength", "(J)J", (void*)NativeAssetGetRemainingLength},
-
-    // System/idmap related methods.
-    {"nativeVerifySystemIdmaps", "()V", (void*)NativeVerifySystemIdmaps},
-
-    // Global management/debug methods.
-    {"getGlobalAssetCount", "()I", (void*)NativeGetGlobalAssetCount},
-    {"getAssetAllocations", "()Ljava/lang/String;", (void*)NativeGetAssetAllocations},
-    {"getGlobalAssetManagerCount", "()I", (void*)NativeGetGlobalAssetManagerCount},
+    // Bookkeeping.
+    { "init",           "(Z)V",
+        (void*) android_content_AssetManager_init },
+    { "destroy",        "()V",
+        (void*) android_content_AssetManager_destroy },
+    { "getGlobalAssetCount", "()I",
+        (void*) android_content_AssetManager_getGlobalAssetCount },
+    { "getAssetAllocations", "()Ljava/lang/String;",
+        (void*) android_content_AssetManager_getAssetAllocations },
+    { "getGlobalAssetManagerCount", "()I",
+        (void*) android_content_AssetManager_getGlobalAssetManagerCount },
 };
 
-int register_android_content_AssetManager(JNIEnv* env) {
-  jclass apk_assets_class = FindClassOrDie(env, "android/content/res/ApkAssets");
-  gApkAssetsFields.native_ptr = GetFieldIDOrDie(env, apk_assets_class, "mNativePtr", "J");
+int register_android_content_AssetManager(JNIEnv* env)
+{
+    jclass typedValue = FindClassOrDie(env, "android/util/TypedValue");
+    gTypedValueOffsets.mType = GetFieldIDOrDie(env, typedValue, "type", "I");
+    gTypedValueOffsets.mData = GetFieldIDOrDie(env, typedValue, "data", "I");
+    gTypedValueOffsets.mString = GetFieldIDOrDie(env, typedValue, "string",
+                                                 "Ljava/lang/CharSequence;");
+    gTypedValueOffsets.mAssetCookie = GetFieldIDOrDie(env, typedValue, "assetCookie", "I");
+    gTypedValueOffsets.mResourceId = GetFieldIDOrDie(env, typedValue, "resourceId", "I");
+    gTypedValueOffsets.mChangingConfigurations = GetFieldIDOrDie(env, typedValue,
+                                                                 "changingConfigurations", "I");
+    gTypedValueOffsets.mDensity = GetFieldIDOrDie(env, typedValue, "density", "I");
 
-  jclass typedValue = FindClassOrDie(env, "android/util/TypedValue");
-  gTypedValueOffsets.mType = GetFieldIDOrDie(env, typedValue, "type", "I");
-  gTypedValueOffsets.mData = GetFieldIDOrDie(env, typedValue, "data", "I");
-  gTypedValueOffsets.mString =
-      GetFieldIDOrDie(env, typedValue, "string", "Ljava/lang/CharSequence;");
-  gTypedValueOffsets.mAssetCookie = GetFieldIDOrDie(env, typedValue, "assetCookie", "I");
-  gTypedValueOffsets.mResourceId = GetFieldIDOrDie(env, typedValue, "resourceId", "I");
-  gTypedValueOffsets.mChangingConfigurations =
-      GetFieldIDOrDie(env, typedValue, "changingConfigurations", "I");
-  gTypedValueOffsets.mDensity = GetFieldIDOrDie(env, typedValue, "density", "I");
+    jclass assetFd = FindClassOrDie(env, "android/content/res/AssetFileDescriptor");
+    gAssetFileDescriptorOffsets.mFd = GetFieldIDOrDie(env, assetFd, "mFd",
+                                                      "Landroid/os/ParcelFileDescriptor;");
+    gAssetFileDescriptorOffsets.mStartOffset = GetFieldIDOrDie(env, assetFd, "mStartOffset", "J");
+    gAssetFileDescriptorOffsets.mLength = GetFieldIDOrDie(env, assetFd, "mLength", "J");
 
-  jclass assetFd = FindClassOrDie(env, "android/content/res/AssetFileDescriptor");
-  gAssetFileDescriptorOffsets.mFd =
-      GetFieldIDOrDie(env, assetFd, "mFd", "Landroid/os/ParcelFileDescriptor;");
-  gAssetFileDescriptorOffsets.mStartOffset = GetFieldIDOrDie(env, assetFd, "mStartOffset", "J");
-  gAssetFileDescriptorOffsets.mLength = GetFieldIDOrDie(env, assetFd, "mLength", "J");
+    jclass assetManager = FindClassOrDie(env, "android/content/res/AssetManager");
+    gAssetManagerOffsets.mObject = GetFieldIDOrDie(env, assetManager, "mObject", "J");
 
-  jclass assetManager = FindClassOrDie(env, "android/content/res/AssetManager");
-  gAssetManagerOffsets.mObject = GetFieldIDOrDie(env, assetManager, "mObject", "J");
+    jclass stringClass = FindClassOrDie(env, "java/lang/String");
+    g_stringClass = MakeGlobalRefOrDie(env, stringClass);
 
-  jclass stringClass = FindClassOrDie(env, "java/lang/String");
-  g_stringClass = MakeGlobalRefOrDie(env, stringClass);
+    jclass sparseArrayClass = FindClassOrDie(env, "android/util/SparseArray");
+    gSparseArrayOffsets.classObject = MakeGlobalRefOrDie(env, sparseArrayClass);
+    gSparseArrayOffsets.constructor = GetMethodIDOrDie(env, gSparseArrayOffsets.classObject,
+                                                       "<init>", "()V");
+    gSparseArrayOffsets.put = GetMethodIDOrDie(env, gSparseArrayOffsets.classObject, "put",
+                                               "(ILjava/lang/Object;)V");
 
-  jclass sparseArrayClass = FindClassOrDie(env, "android/util/SparseArray");
-  gSparseArrayOffsets.classObject = MakeGlobalRefOrDie(env, sparseArrayClass);
-  gSparseArrayOffsets.constructor =
-      GetMethodIDOrDie(env, gSparseArrayOffsets.classObject, "<init>", "()V");
-  gSparseArrayOffsets.put =
-      GetMethodIDOrDie(env, gSparseArrayOffsets.classObject, "put", "(ILjava/lang/Object;)V");
+    jclass configurationClass = FindClassOrDie(env, "android/content/res/Configuration");
+    gConfigurationOffsets.classObject = MakeGlobalRefOrDie(env, configurationClass);
+    gConfigurationOffsets.constructor = GetMethodIDOrDie(env, configurationClass,
+            "<init>", "()V");
+    gConfigurationOffsets.mSmallestScreenWidthDpOffset = GetFieldIDOrDie(env, configurationClass,
+            "smallestScreenWidthDp", "I");
+    gConfigurationOffsets.mScreenWidthDpOffset = GetFieldIDOrDie(env, configurationClass,
+            "screenWidthDp", "I");
+    gConfigurationOffsets.mScreenHeightDpOffset = GetFieldIDOrDie(env, configurationClass,
+            "screenHeightDp", "I");
 
-  jclass configurationClass = FindClassOrDie(env, "android/content/res/Configuration");
-  gConfigurationOffsets.classObject = MakeGlobalRefOrDie(env, configurationClass);
-  gConfigurationOffsets.constructor = GetMethodIDOrDie(env, configurationClass, "<init>", "()V");
-  gConfigurationOffsets.mSmallestScreenWidthDpOffset =
-      GetFieldIDOrDie(env, configurationClass, "smallestScreenWidthDp", "I");
-  gConfigurationOffsets.mScreenWidthDpOffset =
-      GetFieldIDOrDie(env, configurationClass, "screenWidthDp", "I");
-  gConfigurationOffsets.mScreenHeightDpOffset =
-      GetFieldIDOrDie(env, configurationClass, "screenHeightDp", "I");
-
-  return RegisterMethodsOrDie(env, "android/content/res/AssetManager", gAssetManagerMethods,
-                              NELEM(gAssetManagerMethods));
+    return RegisterMethodsOrDie(env, "android/content/res/AssetManager", gAssetManagerMethods,
+                                NELEM(gAssetManagerMethods));
 }
 
 }; // namespace android
diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp
index 956b724..3b7b14c 100644
--- a/core/jni/fd_utils.cpp
+++ b/core/jni/fd_utils.cpp
@@ -85,11 +85,15 @@
   static const char* kOverlayDir = "/system/vendor/overlay/";
   static const char* kVendorOverlayDir = "/vendor/overlay";
   static const char* kOverlaySubdir = "/system/vendor/overlay-subdir/";
+  static const char* kSystemProductOverlayDir = "/system/product/overlay/";
+  static const char* kProductOverlayDir = "/product/overlay";
   static const char* kApkSuffix = ".apk";
 
   if ((android::base::StartsWith(path, kOverlayDir)
        || android::base::StartsWith(path, kOverlaySubdir)
-       || android::base::StartsWith(path, kVendorOverlayDir))
+       || android::base::StartsWith(path, kVendorOverlayDir)
+       || android::base::StartsWith(path, kSystemProductOverlayDir)
+       || android::base::StartsWith(path, kProductOverlayDir))
       && android::base::EndsWith(path, kApkSuffix)
       && path.find("/../") == std::string::npos) {
     return true;
diff --git a/core/jni/include/android_runtime/android_util_AssetManager.h b/core/jni/include/android_runtime/android_util_AssetManager.h
index 2c1e357..8dd9337 100644
--- a/core/jni/include/android_runtime/android_util_AssetManager.h
+++ b/core/jni/include/android_runtime/android_util_AssetManager.h
@@ -14,20 +14,17 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_RUNTIME_ASSETMANAGER_H
-#define ANDROID_RUNTIME_ASSETMANAGER_H
+#ifndef android_util_AssetManager_H
+#define android_util_AssetManager_H
 
-#include "androidfw/AssetManager2.h"
-#include "androidfw/MutexGuard.h"
+#include <androidfw/AssetManager.h>
 
 #include "jni.h"
 
 namespace android {
 
-extern AAssetManager* NdkAssetManagerForJavaObject(JNIEnv* env, jobject jassetmanager);
-extern Guarded<AssetManager2>* AssetManagerForJavaObject(JNIEnv* env, jobject jassetmanager);
-extern Guarded<AssetManager2>* AssetManagerForNdkAssetManager(AAssetManager* assetmanager);
+extern AssetManager* assetManagerForJavaObject(JNIEnv* env, jobject assetMgr);
 
-}  // namespace android
+}
 
-#endif  // ANDROID_RUNTIME_ASSETMANAGER_H
+#endif
diff --git a/core/proto/android/app/activitymanager.proto b/core/proto/android/app/activitymanager.proto
index 03f8204..4756c13 100644
--- a/core/proto/android/app/activitymanager.proto
+++ b/core/proto/android/app/activitymanager.proto
@@ -21,65 +21,6 @@
 option java_multiple_files = true;
 option java_outer_classname = "ActivityManagerProto";
 
-// ActivityManager.java PROCESS_STATEs
-enum ProcessState {
-  // Order matters for process states, so values have been spaced to provide
-  // room for future additions.
-
-  // Not a real process state.
-  PROCESS_STATE_UNKNOWN = -100;
-  // Process is a persistent system process.
-  PROCESS_STATE_PERSISTENT = 0;
-  // Process is a persistent system process and is doing UI.
-  PROCESS_STATE_PERSISTENT_UI = 100;
-  // Process is hosting the current top activities. Note that this covers
-  // all activities that are visible to the user.
-  PROCESS_STATE_TOP = 200;
-  // Process is hosting a foreground service due to a system binding.
-  PROCESS_STATE_BOUND_FOREGROUND_SERVICE = 300;
-  // Process is hosting a foreground service.
-  PROCESS_STATE_FOREGROUND_SERVICE = 400;
-  // Process is important to the user, and something they are aware of.
-  PROCESS_STATE_IMPORTANT_FOREGROUND = 500;
-  // Process is important to the user, but not something they are aware of.
-  PROCESS_STATE_IMPORTANT_BACKGROUND = 600;
-  // Process is in the background transient so we will try to keep running.
-  PROCESS_STATE_TRANSIENT_BACKGROUND = 700;
-  // Process is in the background running a backup/restore operation.
-  PROCESS_STATE_BACKUP = 800;
-  // Process is in the background running a service. Unlike oom_adj, this
-  // level is used for both the normal running in background state and the
-  // executing operations state.
-  PROCESS_STATE_SERVICE = 900;
-  // Process is in the background running a receiver. Note that from the
-  // perspective of oom_adj, receivers run at a higher foreground level, but
-  // for our prioritization here that is not necessary and putting them
-  // below services means many fewer changes in some process states as they
-  // receive broadcasts.
-  PROCESS_STATE_RECEIVER = 1000;
-  // Same as PROCESS_STATE_TOP but while device is sleeping.
-  PROCESS_STATE_TOP_SLEEPING = 1100;
-  // Process is in the background, but it can't restore its state so we want
-  // to try to avoid killing it.
-  PROCESS_STATE_HEAVY_WEIGHT = 1200;
-  // Process is in the background but hosts the home activity.
-  PROCESS_STATE_HOME = 1300;
-  // Process is in the background but hosts the last shown activity.
-  PROCESS_STATE_LAST_ACTIVITY = 1400;
-  // Process is being cached for later use and contains activities.
-  PROCESS_STATE_CACHED_ACTIVITY = 1500;
-  // Process is being cached for later use and is a client of another cached
-  // process that contains activities.
-  PROCESS_STATE_CACHED_ACTIVITY_CLIENT = 1600;
-  // Process is being cached for later use and has an activity that corresponds
-  // to an existing recent task.
-  PROCESS_STATE_CACHED_RECENT = 1700;
-  // Process is being cached for later use and is empty.
-  PROCESS_STATE_CACHED_EMPTY = 1800;
-  // Process does not exist.
-  PROCESS_STATE_NONEXISTENT = 1900;
-}
-
 // ActivityManager.java UID_OBSERVERs flags
 enum UidObserverFlag {
   // report changes in process state, original value is 1 << 0
diff --git a/core/proto/android/app/alarmmanager.proto b/core/proto/android/app/alarmmanager.proto
index 789e3d6..7ef08ca 100644
--- a/core/proto/android/app/alarmmanager.proto
+++ b/core/proto/android/app/alarmmanager.proto
@@ -17,6 +17,7 @@
 syntax = "proto2";
 
 import "frameworks/base/core/proto/android/app/pendingintent.proto";
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
 
 option java_multiple_files = true;
 
@@ -47,6 +48,8 @@
 
 // An android.app.AlarmManager.AlarmClockInfo object.
 message AlarmClockInfoProto {
+  option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
   // This value is UTC wall clock time in milliseconds, as returned by
   // System#currentTimeMillis() for example.
   optional int64 trigger_time_ms = 1;
diff --git a/core/proto/android/app/enums.proto b/core/proto/android/app/enums.proto
new file mode 100644
index 0000000..2de2574
--- /dev/null
+++ b/core/proto/android/app/enums.proto
@@ -0,0 +1,87 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+
+package android.app;
+
+option java_outer_classname = "AppProtoEnums";
+option java_multiple_files = true;
+
+// ActivityManager.java PROCESS_STATEs
+enum ProcessStateEnum {
+    // Unlike the ActivityManager PROCESS_STATE values, the ordering and numerical values
+    // here are completely fixed and arbitrary. Order is irrelevant.
+    // No attempt need be made to keep them in sync.
+    // The values here must not be modified. Any new process states can be appended to the end.
+
+    // Process state that is unknown to this proto file (i.e. is not mapped
+    // by ActivityManager.processStateAmToProto()). Can only happen if there's a bug in the mapping.
+    PROCESS_STATE_UNKNOWN_TO_PROTO = 998;
+    // Not a real process state.
+    PROCESS_STATE_UNKNOWN = 999;
+    // Process is a persistent system process.
+    PROCESS_STATE_PERSISTENT = 1000;
+    // Process is a persistent system process and is doing UI.
+    PROCESS_STATE_PERSISTENT_UI = 1001;
+    // Process is hosting the current top activities. Note that this covers
+    // all activities that are visible to the user.
+    PROCESS_STATE_TOP = 1002;
+    // Process is hosting a foreground service.
+    PROCESS_STATE_FOREGROUND_SERVICE = 1003;
+    // Process is hosting a foreground service due to a system binding.
+    PROCESS_STATE_BOUND_FOREGROUND_SERVICE = 1004;
+    // Process is important to the user, and something they are aware of.
+    PROCESS_STATE_IMPORTANT_FOREGROUND = 1005;
+    // Process is important to the user, but not something they are aware of.
+    PROCESS_STATE_IMPORTANT_BACKGROUND = 1006;
+    // Process is in the background transient so we will try to keep running.
+    PROCESS_STATE_TRANSIENT_BACKGROUND = 1007;
+    // Process is in the background running a backup/restore operation.
+    PROCESS_STATE_BACKUP = 1008;
+    // Process is in the background running a service. Unlike oom_adj, this
+    // level is used for both the normal running in background state and the
+    // executing operations state.
+    PROCESS_STATE_SERVICE = 1009;
+    // Process is in the background running a receiver. Note that from the
+    // perspective of oom_adj, receivers run at a higher foreground level, but
+    // for our prioritization here that is not necessary and putting them
+    // below services means many fewer changes in some process states as they
+    // receive broadcasts.
+    PROCESS_STATE_RECEIVER = 1010;
+    // Same as PROCESS_STATE_TOP but while device is sleeping.
+    PROCESS_STATE_TOP_SLEEPING = 1011;
+    // Process is in the background, but it can't restore its state so we want
+    // to try to avoid killing it.
+    PROCESS_STATE_HEAVY_WEIGHT = 1012;
+    // Process is in the background but hosts the home activity.
+    PROCESS_STATE_HOME = 1013;
+    // Process is in the background but hosts the last shown activity.
+    PROCESS_STATE_LAST_ACTIVITY = 1014;
+    // Process is being cached for later use and contains activities.
+    PROCESS_STATE_CACHED_ACTIVITY = 1015;
+    // Process is being cached for later use and is a client of another cached
+    // process that contains activities.
+    PROCESS_STATE_CACHED_ACTIVITY_CLIENT = 1016;
+    // Process is being cached for later use and has an activity that corresponds
+    // to an existing recent task.
+    PROCESS_STATE_CACHED_RECENT = 1017;
+    // Process is being cached for later use and is empty.
+    PROCESS_STATE_CACHED_EMPTY = 1018;
+    // Process does not exist.
+    PROCESS_STATE_NONEXISTENT = 1019;
+}
+
diff --git a/core/proto/android/app/pendingintent.proto b/core/proto/android/app/pendingintent.proto
index b562c0b..ab0d34e 100644
--- a/core/proto/android/app/pendingintent.proto
+++ b/core/proto/android/app/pendingintent.proto
@@ -20,9 +20,13 @@
 
 package android.app;
 
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+
 /**
  * An android.app.PendingIntent object.
  */
 message PendingIntentProto {
+  option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional string target = 1;
 }
diff --git a/core/proto/android/content/clipdata.proto b/core/proto/android/content/clipdata.proto
index 6967b69..aeeef97 100644
--- a/core/proto/android/content/clipdata.proto
+++ b/core/proto/android/content/clipdata.proto
@@ -21,13 +21,18 @@
 
 import "frameworks/base/core/proto/android/content/clipdescription.proto";
 import "frameworks/base/core/proto/android/content/intent.proto";
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
 
 // An android.content.ClipData object.
 message ClipDataProto {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional android.content.ClipDescriptionProto description = 1;
 
     // Custom dump of an android.graphics.Bitmap object.
     message Icon {
+        option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
         optional int32 width = 1;
         optional int32 height = 2;
     }
@@ -35,6 +40,8 @@
 
     // An android.content.ClipData.Item object.
     message Item {
+        option (.android.msg_privacy).dest = DEST_EXPLICIT;
+
         oneof data {
             string html_text = 1;
             string text = 2;
diff --git a/core/proto/android/content/clipdescription.proto b/core/proto/android/content/clipdescription.proto
index 40f4ad3..bc0e940 100644
--- a/core/proto/android/content/clipdescription.proto
+++ b/core/proto/android/content/clipdescription.proto
@@ -20,11 +20,14 @@
 option java_multiple_files = true;
 
 import "frameworks/base/core/proto/android/os/persistablebundle.proto";
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
 
 // An android.content.ClipDescription object.
 message ClipDescriptionProto {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     repeated string mime_types = 1;
-    optional string label = 2;
+    optional string label = 2 [ (.android.privacy).dest = DEST_EXPLICIT ];
     optional android.os.PersistableBundleProto extras = 3;
     optional int64 timestamp_ms = 4;
 }
diff --git a/core/proto/android/content/component_name.proto b/core/proto/android/content/component_name.proto
index fc0c8c5..4e49cf2 100644
--- a/core/proto/android/content/component_name.proto
+++ b/core/proto/android/content/component_name.proto
@@ -20,10 +20,14 @@
 
 package android.content;
 
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+
 /**
  * An android.content.ComponentName object.
  */
 message ComponentNameProto {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional string package_name = 1;
     optional string class_name = 2;
 }
diff --git a/core/proto/android/content/intent.proto b/core/proto/android/content/intent.proto
index c25b46d..1737b62 100644
--- a/core/proto/android/content/intent.proto
+++ b/core/proto/android/content/intent.proto
@@ -51,14 +51,14 @@
 
     optional string action = 1;
     repeated string categories = 2;
-    optional string data = 3  [ (.android.privacy).dest = DEST_EXPLICIT ];
+    optional string data = 3 [ (.android.privacy).dest = DEST_EXPLICIT ];
     optional string type = 4;
     optional string flag = 5;
     optional string package = 6;
     optional string component = 7;
     optional string source_bounds = 8;
-    optional string clip_data = 9  [ (.android.privacy).dest = DEST_EXPLICIT ];
-    optional string extras = 10;
+    optional string clip_data = 9 [ (.android.privacy).dest = DEST_EXPLICIT ];
+    optional string extras = 10 [ (.android.privacy).dest = DEST_EXPLICIT ];
     optional int32 content_user_hint = 11;
     optional string selector = 12;
 }
diff --git a/core/proto/android/internal/locallog.proto b/core/proto/android/internal/locallog.proto
index 51f6c1c..73d1492 100644
--- a/core/proto/android/internal/locallog.proto
+++ b/core/proto/android/internal/locallog.proto
@@ -19,6 +19,10 @@
 
 option java_multiple_files = true;
 
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+
 message LocalLogProto {
+  option (.android.msg_privacy).dest = DEST_EXPLICIT;
+
   repeated string lines = 1;
 }
diff --git a/core/proto/android/net/network.proto b/core/proto/android/net/network.proto
index 9c7ea5d..e13ca9f 100644
--- a/core/proto/android/net/network.proto
+++ b/core/proto/android/net/network.proto
@@ -19,9 +19,14 @@
 
 package android.net;
 
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+
 /**
  * An android.net.Network object.
  */
 message NetworkProto {
-    optional int32 net_id = 1;
+    // The netId is an implementation detail which might be changed in the
+    // future, or which alone (i.e. in the absence of some additional context)
+    // might not be sufficient to fully identify a Network.
+    optional int32 net_id = 1 [ (.android.privacy).dest = DEST_AUTOMATIC ];
 }
diff --git a/core/proto/android/net/networkcapabilities.proto b/core/proto/android/net/networkcapabilities.proto
index e1c2af1..0338bf8 100644
--- a/core/proto/android/net/networkcapabilities.proto
+++ b/core/proto/android/net/networkcapabilities.proto
@@ -20,10 +20,14 @@
 
 option java_multiple_files = true;
 
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+
 /**
  * An android.net.NetworkCapabilities object.
  */
 message NetworkCapabilitiesProto {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     enum Transport {
         // Indicates this network uses a Cellular transport.
         TRANSPORT_CELLULAR = 0;
@@ -118,7 +122,7 @@
     optional int32 link_up_bandwidth_kbps = 3;
     optional int32 link_down_bandwidth_kbps = 4;
 
-    optional string network_specifier = 5;
+    optional string network_specifier = 5 [ (.android.privacy).dest = DEST_EXPLICIT ];
 
     // True if this object specifies a signal strength.
     optional bool can_report_signal_strength = 6;
diff --git a/core/proto/android/net/networkrequest.proto b/core/proto/android/net/networkrequest.proto
index 9884464..d260b13 100644
--- a/core/proto/android/net/networkrequest.proto
+++ b/core/proto/android/net/networkrequest.proto
@@ -21,11 +21,14 @@
 option java_multiple_files = true;
 
 import "frameworks/base/core/proto/android/net/networkcapabilities.proto";
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
 
 /**
  * An android.net.NetworkRequest object.
  */
 message NetworkRequestProto {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     enum Type {
         TYPE_UNKNOWN = 0;
         // Only used by applications. When an application creates a
diff --git a/core/proto/android/os/batterystats.proto b/core/proto/android/os/batterystats.proto
index ce1d5c9..9f9fd05 100644
--- a/core/proto/android/os/batterystats.proto
+++ b/core/proto/android/os/batterystats.proto
@@ -21,7 +21,7 @@
 
 import "frameworks/base/core/proto/android/app/jobparameters.proto";
 import "frameworks/base/core/proto/android/os/powermanager.proto";
-import "frameworks/base/core/proto/android/telephony/signalstrength.proto";
+import "frameworks/base/core/proto/android/telephony/enums.proto";
 import "frameworks/base/libs/incident/proto/android/privacy.proto";
 
 message BatteryStatsProto {
@@ -339,7 +339,7 @@
   message PhoneSignalStrength {
     option (android.msg_privacy).dest = DEST_AUTOMATIC;
 
-    optional android.telephony.SignalStrengthProto.StrengthName name = 1;
+    optional android.telephony.SignalStrengthEnum name = 1;
     optional TimerProto total = 2;
   };
   repeated PhoneSignalStrength phone_signal_strength = 16;
diff --git a/core/proto/android/os/bundle.proto b/core/proto/android/os/bundle.proto
index 6990281..5556936 100644
--- a/core/proto/android/os/bundle.proto
+++ b/core/proto/android/os/bundle.proto
@@ -19,10 +19,14 @@
 
 option java_multiple_files = true;
 
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+
 // An android.os.Bundle object.
 message BundleProto {
     oneof data {
-        int32 parcelled_data_size = 1;
-        string map_data = 2;
+        int32 parcelled_data_size = 1 [
+            (.android.privacy).dest = DEST_AUTOMATIC
+        ];
+        string map_data = 2 [ (.android.privacy).dest = DEST_EXPLICIT ];
     }
 }
diff --git a/core/proto/android/os/enums.proto b/core/proto/android/os/enums.proto
new file mode 100644
index 0000000..fe9b7ac
--- /dev/null
+++ b/core/proto/android/os/enums.proto
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+package android.os;
+
+option java_outer_classname = "OsProtoEnums";
+option java_multiple_files = true;
+
+// These constants are defined in hardware/interfaces/health/1.0/types.hal
+// They are primarily used by android/os/BatteryManager.java.
+enum BatteryHealthEnum {
+    BATTERY_HEALTH_INVALID = 0;
+    BATTERY_HEALTH_UNKNOWN = 1;
+    BATTERY_HEALTH_GOOD = 2;
+    BATTERY_HEALTH_OVERHEAT = 3;
+    BATTERY_HEALTH_DEAD = 4;
+    BATTERY_HEALTH_OVER_VOLTAGE = 5;
+    BATTERY_HEALTH_UNSPECIFIED_FAILURE = 6;
+    BATTERY_HEALTH_COLD = 7;
+}
+
+// Plug states, primarily used by android/os/BatteryManager.java.
+enum BatteryPluggedStateEnum {
+    // Note that NONE is not in BatteryManager.java's constants.
+    BATTERY_PLUGGED_NONE = 0;
+    // Power source is an AC charger.
+    BATTERY_PLUGGED_AC = 1;
+    // Power source is a USB port.
+    BATTERY_PLUGGED_USB = 2;
+    // Power source is wireless.
+    BATTERY_PLUGGED_WIRELESS = 4;
+}
+
+// These constants are defined in hardware/interfaces/health/1.0/types.hal
+// They are primarily used by android/os/BatteryManager.java.
+enum BatteryStatusEnum {
+    BATTERY_STATUS_INVALID = 0;
+    BATTERY_STATUS_UNKNOWN = 1;
+    BATTERY_STATUS_CHARGING = 2;
+    BATTERY_STATUS_DISCHARGING = 3;
+    BATTERY_STATUS_NOT_CHARGING = 4;
+    BATTERY_STATUS_FULL = 5;
+}
+
+// Wakelock types, primarily used by android/os/PowerManager.java.
+enum WakeLockLevelEnum {
+    // NOTE: Wake lock levels were previously defined as a bit field, except
+    // that only a few combinations were actually supported so the bit field
+    // was removed. This explains why the numbering scheme is so odd. If
+    // adding a new wake lock level, any unused value can be used.
+
+    // Ensures that the CPU is running; the screen and keyboard backlight
+    // will be allowed to go off.
+    PARTIAL_WAKE_LOCK = 1;
+
+    // Ensures that the screen is on (but may be dimmed); the keyboard
+    // backlight will be allowed to go off. If the user presses the power
+    // button, then the SCREEN_DIM_WAKE_LOCK will be implicitly released by
+    // the system, causing both the screen and the CPU to be turned off.
+    SCREEN_DIM_WAKE_LOCK = 6 [deprecated = true];
+
+    // Ensures that the screen is on at full brightness; the keyboard
+    // backlight will be allowed to go off. If the user presses the power
+    // button, then the SCREEN_BRIGHT_WAKE_LOCK will be implicitly released
+    // by the system, causing both the screen and the CPU to be turned off.
+    SCREEN_BRIGHT_WAKE_LOCK = 10 [deprecated = true];
+
+    // Ensures that the screen and keyboard backlight are on at full
+    // brightness. If the user presses the power button, then the
+    // FULL_WAKE_LOCK will be implicitly released by the system, causing
+    // both the screen and the CPU to be turned off.
+    FULL_WAKE_LOCK = 26 [deprecated = true];
+
+    // Turns the screen off when the proximity sensor activates. If the
+    // proximity sensor detects that an object is nearby, the screen turns
+    // off immediately. Shortly after the object moves away, the screen
+    // turns on again.
+    // A proximity wake lock does not prevent the device from falling asleep
+    // unlike FULL_WAKE_LOCK, SCREEN_BRIGHT_WAKE_LOCK and
+    // SCREEN_DIM_WAKE_LOCK. If there is no user activity and no other wake
+    // locks are held, then the device will fall asleep (and lock) as usual.
+    // However, the device will not fall asleep while the screen has been
+    // turned off by the proximity sensor because it effectively counts as
+    // ongoing user activity.
+    PROXIMITY_SCREEN_OFF_WAKE_LOCK = 32;
+
+    // Put the screen in a low power state and allow the CPU to suspend if
+    // no other wake locks are held. This is used by the dream manager to
+    // implement doze mode. It currently has no effect unless the power
+    // manager is in the dozing state.
+    DOZE_WAKE_LOCK = 64;
+
+    // Keep the device awake enough to allow drawing to occur. This is used
+    // by the window manager to allow applications to draw while the system
+    // is dozing. It currently has no effect unless the power manager is in
+    // the dozing state.
+    DRAW_WAKE_LOCK = 128;
+}
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index 828a55f..3ec6f05 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -123,7 +123,7 @@
 
     // Linux services
     optional Procrank procrank = 2000 [
-        (section).type = SECTION_COMMAND,
+        (section).type = SECTION_NONE, // disable procrank until figure out permission
         (section).args = "/system/xbin/procrank"
     ];
 
diff --git a/core/proto/android/os/persistablebundle.proto b/core/proto/android/os/persistablebundle.proto
index 75ff787..712f87c 100644
--- a/core/proto/android/os/persistablebundle.proto
+++ b/core/proto/android/os/persistablebundle.proto
@@ -19,10 +19,14 @@
 
 option java_multiple_files = true;
 
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+
 // An android.os.PersistableBundle object.
 message PersistableBundleProto {
     oneof data {
-        int32 parcelled_data_size = 1;
-        string map_data = 2;
+        int32 parcelled_data_size = 1 [
+            (.android.privacy).dest = DEST_AUTOMATIC
+        ];
+        string map_data = 2 [ (.android.privacy).dest = DEST_EXPLICIT ];
     }
 }
diff --git a/core/proto/android/os/powermanager.proto b/core/proto/android/os/powermanager.proto
index 8e0a607..78a28ed 100644
--- a/core/proto/android/os/powermanager.proto
+++ b/core/proto/android/os/powermanager.proto
@@ -20,6 +20,7 @@
 option java_multiple_files = true;
 
 import "frameworks/base/core/proto/android/os/worksource.proto";
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
 
 message PowerManagerProto {
     /* User activity events in PowerManager.java. */
@@ -34,62 +35,10 @@
         USER_ACTIVITY_EVENT_ACCESSIBILITY = 3;
     }
 
-    enum WakeLockLevel {
-        // NOTE: Wake lock levels were previously defined as a bit field, except
-        // that only a few combinations were actually supported so the bit field
-        // was removed. This explains why the numbering scheme is so odd. If
-        // adding a new wake lock level, any unused value can be used.
-
-        // Ensures that the CPU is running; the screen and keyboard backlight
-        // will be allowed to go off.
-        PARTIAL_WAKE_LOCK = 1;
-
-        // Ensures that the screen is on (but may be dimmed); the keyboard
-        // backlight will be allowed to go off. If the user presses the power
-        // button, then the SCREEN_DIM_WAKE_LOCK will be implicitly released by
-        // the system, causing both the screen and the CPU to be turned off.
-        SCREEN_DIM_WAKE_LOCK = 6 [deprecated = true];
-
-        // Ensures that the screen is on at full brightness; the keyboard
-        // backlight will be allowed to go off. If the user presses the power
-        // button, then the SCREEN_BRIGHT_WAKE_LOCK will be implicitly released
-        // by the system, causing both the screen and the CPU to be turned off.
-        SCREEN_BRIGHT_WAKE_LOCK = 10 [deprecated = true];
-
-        // Ensures that the screen and keyboard backlight are on at full
-        // brightness. If the user presses the power button, then the
-        // FULL_WAKE_LOCK will be implicitly released by the system, causing
-        // both the screen and the CPU to be turned off.
-        FULL_WAKE_LOCK = 26 [deprecated = true];
-
-        // Turns the screen off when the proximity sensor activates. If the
-        // proximity sensor detects that an object is nearby, the screen turns
-        // off immediately. Shortly after the object moves away, the screen
-        // turns on again.
-        // A proximity wake lock does not prevent the device from falling asleep
-        // unlike FULL_WAKE_LOCK, SCREEN_BRIGHT_WAKE_LOCK and
-        // SCREEN_DIM_WAKE_LOCK. If there is no user activity and no other wake
-        // locks are held, then the device will fall asleep (and lock) as usual.
-        // However, the device will not fall asleep while the screen has been
-        // turned off by the proximity sensor because it effectively counts as
-        // ongoing user activity.
-        PROXIMITY_SCREEN_OFF_WAKE_LOCK = 32;
-
-        // Put the screen in a low power state and allow the CPU to suspend if
-        // no other wake locks are held. This is used by the dream manager to
-        // implement doze mode. It currently has no effect unless the power
-        // manager is in the dozing state.
-        DOZE_WAKE_LOCK = 64;
-
-        // Keep the device awake enough to allow drawing to occur. This is used
-        // by the window manager to allow applications to draw while the system
-        // is dozing. It currently has no effect unless the power manager is in
-        // the dozing state.
-        DRAW_WAKE_LOCK = 128;
-    }
-
     // WakeLock class in android.os.PowerManager, it is the one used by sdk
     message WakeLockProto {
+        option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
         optional string hex_string = 1;
         optional bool held = 2;
         optional int32 internal_count = 3;
diff --git a/core/proto/android/os/worksource.proto b/core/proto/android/os/worksource.proto
index 2f8b2fb..0a9c2ed 100644
--- a/core/proto/android/os/worksource.proto
+++ b/core/proto/android/os/worksource.proto
@@ -17,15 +17,23 @@
 syntax = "proto2";
 package android.os;
 
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+
 option java_multiple_files = true;
 
 message WorkSourceProto {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     message WorkSourceContentProto {
+        option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
         optional int32 uid = 1;
         optional string name = 2;
     }
 
     message WorkChain {
+      option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
       repeated WorkSourceContentProto nodes = 1;
     }
 
diff --git a/core/proto/android/providers/settings.proto b/core/proto/android/providers/settings.proto
index 27fbb24..bfd575a 100644
--- a/core/proto/android/providers/settings.proto
+++ b/core/proto/android/providers/settings.proto
@@ -20,7 +20,11 @@
 option java_multiple_files = true;
 option java_outer_classname = "SettingsServiceProto";
 
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+
 message SettingsServiceDumpProto {
+    option (android.msg_privacy).dest = DEST_EXPLICIT;
+
     // Per user settings
     repeated UserSettingsProto user_settings = 1;
 
@@ -29,8 +33,10 @@
 }
 
 message UserSettingsProto {
+    option (android.msg_privacy).dest = DEST_EXPLICIT;
+
     // Should be 0, 10, 11, 12, etc. where 0 is the owner.
-    optional int32 user_id = 1;
+    optional int32 user_id = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
 
     // The secure settings for this user
     optional SecureSettingsProto secure_settings = 2;
@@ -42,246 +48,266 @@
 // Note: it's a conscious decision to add each setting as a separate field. This
 // allows annotating each setting with its own privacy tag.
 message GlobalSettingsProto {
+    option (android.msg_privacy).dest = DEST_EXPLICIT;
+
     repeated SettingsOperationProto historical_operations = 1;
 
-    optional SettingProto add_users_when_locked = 2;
-    optional SettingProto enable_accessibility_global_gesture_enabled = 3;
-    optional SettingProto airplane_mode_on = 4;
-    optional SettingProto theater_mode_on = 5;
-    optional SettingProto radio_bluetooth = 6;
-    optional SettingProto radio_wifi = 7;
-    optional SettingProto radio_wimax = 8;
-    optional SettingProto radio_cell = 9;
-    optional SettingProto radio_nfc = 10;
-    optional SettingProto airplane_mode_radios = 11;
-    optional SettingProto airplane_mode_toggleable_radios = 12;
-    optional SettingProto bluetooth_class_of_device = 293;
+    optional SettingProto add_users_when_locked = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto enable_accessibility_global_gesture_enabled = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto airplane_mode_on = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto theater_mode_on = 5 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    reserved 6,7,8,9,10; // Accidentally used. They are currently free to be reused.
+    // A comma-separated list of radios that need to be disabled when airplane
+    // mode is on. This overrides wifi_on and bluetooth_on if wifi and bluetooth
+    // are included in the comma-separated list.
+    optional SettingProto airplane_mode_radios = 11 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto airplane_mode_toggleable_radios = 12 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto bluetooth_class_of_device = 293 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto bluetooth_disabled_profiles = 13;
     optional SettingProto bluetooth_interoperability_list = 14;
-    optional SettingProto wifi_sleep_policy = 15;
-    optional SettingProto auto_time = 16;
-    optional SettingProto auto_time_zone = 17;
+    optional SettingProto wifi_sleep_policy = 15 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto auto_time = 16 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto auto_time_zone = 17 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto car_dock_sound = 18;
     optional SettingProto car_undock_sound = 19;
     optional SettingProto desk_dock_sound = 20;
     optional SettingProto desk_undock_sound = 21;
-    optional SettingProto dock_sounds_enabled = 22;
-    optional SettingProto dock_sounds_enabled_when_accessibility = 23;
+    optional SettingProto dock_sounds_enabled = 22 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto dock_sounds_enabled_when_accessibility = 23 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto lock_sound = 24;
     optional SettingProto unlock_sound = 25;
     optional SettingProto trusted_sound = 26;
     optional SettingProto low_battery_sound = 27;
-    optional SettingProto power_sounds_enabled = 28;
+    optional SettingProto power_sounds_enabled = 28 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto wireless_charging_started_sound = 29;
-    optional SettingProto charging_sounds_enabled = 30;
-    optional SettingProto stay_on_while_plugged_in = 31;
-    optional SettingProto bugreport_in_power_menu = 32;
-    optional SettingProto adb_enabled = 33;
-    optional SettingProto debug_view_attributes = 34;
-    optional SettingProto assisted_gps_enabled = 35;
-    optional SettingProto bluetooth_on = 36;
-    optional SettingProto cdma_cell_broadcast_sms = 37;
-    optional SettingProto cdma_roaming_mode = 38;
-    optional SettingProto cdma_subscription_mode = 39;
-    optional SettingProto data_activity_timeout_mobile = 40;
-    optional SettingProto data_activity_timeout_wifi = 41;
-    optional SettingProto data_roaming = 42;
-    optional SettingProto mdc_initial_max_retry = 43;
-    optional SettingProto force_allow_on_external = 44;
-    optional SettingProto euicc_provisioned = 294;
-    optional SettingProto development_force_resizable_activities = 45;
-    optional SettingProto development_enable_freeform_windows_support = 46;
-    optional SettingProto development_settings_enabled = 47;
-    optional SettingProto device_provisioned = 48;
-    optional SettingProto device_provisioning_mobile_data_enabled = 49;
-    optional SettingProto display_size_forced = 50;
-    optional SettingProto display_scaling_force = 51;
-    optional SettingProto download_max_bytes_over_mobile = 52;
-    optional SettingProto download_recommended_max_bytes_over_mobile = 53;
-    optional SettingProto hdmi_control_enabled = 54;
-    optional SettingProto hdmi_system_audio_control_enabled = 55;
-    optional SettingProto hdmi_control_auto_wakeup_enabled = 56;
-    optional SettingProto hdmi_control_auto_device_off_enabled = 57;
-    optional SettingProto location_background_throttle_interval_ms = 295;
-    optional SettingProto location_background_throttle_proximity_alert_interval_ms = 296;
-    optional SettingProto location_background_throttle_package_whitelist = 297;
-    optional SettingProto wifi_scan_background_throttle_interval_ms = 298;
-    optional SettingProto wifi_scan_background_throttle_package_whitelist = 299;
-    optional SettingProto mhl_input_switching_enabled = 58;
-    optional SettingProto mhl_power_charge_enabled = 59;
-    optional SettingProto mobile_data = 60;
-    optional SettingProto mobile_data_always_on = 61;
-    optional SettingProto connectivity_metrics_buffer_size = 62;
-    optional SettingProto netstats_enabled = 63;
-    optional SettingProto netstats_poll_interval = 64;
-    optional SettingProto netstats_time_cache_max_age = 65;
-    optional SettingProto netstats_global_alert_bytes = 66;
-    optional SettingProto netstats_sample_enabled = 67;
-    optional SettingProto netstats_augment_enabled = 300;
-    optional SettingProto netstats_dev_bucket_duration = 68;
-    optional SettingProto netstats_dev_persist_bytes = 69;
-    optional SettingProto netstats_dev_rotate_age = 70;
-    optional SettingProto netstats_dev_delete_age = 71;
-    optional SettingProto netstats_uid_bucket_duration = 72;
-    optional SettingProto netstats_uid_persist_bytes = 73;
-    optional SettingProto netstats_uid_rotate_age = 74;
-    optional SettingProto netstats_uid_delete_age = 75;
-    optional SettingProto netstats_uid_tag_bucket_duration = 76;
-    optional SettingProto netstats_uid_tag_persist_bytes = 77;
-    optional SettingProto netstats_uid_tag_rotate_age = 78;
-    optional SettingProto netstats_uid_tag_delete_age = 79;
+    optional SettingProto charging_sounds_enabled = 30 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto stay_on_while_plugged_in = 31 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto bugreport_in_power_menu = 32 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto adb_enabled = 33 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    // Whether views are allowed to save their attribute data.
+    optional SettingProto debug_view_attributes = 34 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto assisted_gps_enabled = 35 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto bluetooth_on = 36 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto cdma_cell_broadcast_sms = 37 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto cdma_roaming_mode = 38 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto cdma_subscription_mode = 39 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto data_activity_timeout_mobile = 40 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto data_activity_timeout_wifi = 41 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto data_roaming = 42 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto mdc_initial_max_retry = 43 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto force_allow_on_external = 44 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto euicc_provisioned = 294 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto development_force_resizable_activities = 45 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto development_enable_freeform_windows_support = 46 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto development_settings_enabled = 47 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto device_provisioned = 48 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto device_provisioning_mobile_data_enabled = 49 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto display_size_forced = 50 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto display_scaling_force = 51 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto download_max_bytes_over_mobile = 52 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto download_recommended_max_bytes_over_mobile = 53 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto hdmi_control_enabled = 54 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto hdmi_system_audio_control_enabled = 55 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto hdmi_control_auto_wakeup_enabled = 56 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto hdmi_control_auto_device_off_enabled = 57 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto location_background_throttle_interval_ms = 295 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto location_background_throttle_proximity_alert_interval_ms = 296 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    // Packages that are whitelisted for background throttling (throttling will
+    // not be applied).
+    optional SettingProto location_background_throttle_package_whitelist = 297 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto wifi_scan_background_throttle_interval_ms = 298 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto wifi_scan_background_throttle_package_whitelist = 299 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto mhl_input_switching_enabled = 58 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto mhl_power_charge_enabled = 59 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto mobile_data = 60 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto mobile_data_always_on = 61 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto connectivity_metrics_buffer_size = 62 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto netstats_enabled = 63 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto netstats_poll_interval = 64 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto netstats_time_cache_max_age = 65 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto netstats_global_alert_bytes = 66 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto netstats_sample_enabled = 67 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto netstats_augment_enabled = 300 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto netstats_dev_bucket_duration = 68 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto netstats_dev_persist_bytes = 69 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto netstats_dev_rotate_age = 70 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto netstats_dev_delete_age = 71 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto netstats_uid_bucket_duration = 72 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto netstats_uid_persist_bytes = 73 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto netstats_uid_rotate_age = 74 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto netstats_uid_delete_age = 75 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto netstats_uid_tag_bucket_duration = 76 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto netstats_uid_tag_persist_bytes = 77 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto netstats_uid_tag_rotate_age = 78 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto netstats_uid_tag_delete_age = 79 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    // User preference for which network(s) should be used.
     optional SettingProto network_preference = 80;
-    optional SettingProto network_scorer_app = 81;
-    optional SettingProto nitz_update_diff = 82;
-    optional SettingProto nitz_update_spacing = 83;
+    optional SettingProto network_scorer_app = 81 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto nitz_update_diff = 82 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto nitz_update_spacing = 83 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto ntp_server = 84;
-    optional SettingProto ntp_timeout = 85;
-    optional SettingProto storage_benchmark_interval = 86;
-    optional SettingProto dns_resolver_sample_validity_seconds = 87;
-    optional SettingProto dns_resolver_success_threshold_percent = 88;
-    optional SettingProto dns_resolver_min_samples = 89;
-    optional SettingProto dns_resolver_max_samples = 90;
-    optional SettingProto ota_disable_automatic_update = 91;
-    optional SettingProto package_verifier_enable = 92;
-    optional SettingProto package_verifier_timeout = 93;
+    optional SettingProto ntp_timeout = 85 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto storage_benchmark_interval = 86 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto dns_resolver_sample_validity_seconds = 87 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto dns_resolver_success_threshold_percent = 88 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto dns_resolver_min_samples = 89 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto dns_resolver_max_samples = 90 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    // Whether to disable the automatic scheduling of system updates.
+    optional SettingProto ota_disable_automatic_update = 91 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto package_verifier_enable = 92 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto package_verifier_timeout = 93 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto package_verifier_default_response = 94;
-    optional SettingProto package_verifier_setting_visible = 95;
-    optional SettingProto package_verifier_include_adb = 96;
-    optional SettingProto fstrim_mandatory_interval = 97;
-    optional SettingProto pdp_watchdog_poll_interval_ms = 98;
-    optional SettingProto pdp_watchdog_long_poll_interval_ms = 99;
-    optional SettingProto pdp_watchdog_error_poll_interval_ms = 100;
-    optional SettingProto pdp_watchdog_trigger_packet_count = 101;
-    optional SettingProto pdp_watchdog_error_poll_count = 102;
-    optional SettingProto pdp_watchdog_max_pdp_reset_fail_count = 103;
+    optional SettingProto package_verifier_setting_visible = 95 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto package_verifier_include_adb = 96 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto fstrim_mandatory_interval = 97 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto pdp_watchdog_poll_interval_ms = 98 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto pdp_watchdog_long_poll_interval_ms = 99 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto pdp_watchdog_error_poll_interval_ms = 100 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto pdp_watchdog_trigger_packet_count = 101 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto pdp_watchdog_error_poll_count = 102 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto pdp_watchdog_max_pdp_reset_fail_count = 103 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto setup_prepaid_data_service_url = 105;
     optional SettingProto setup_prepaid_detection_target_url = 106;
     optional SettingProto setup_prepaid_detection_redir_host = 107;
-    optional SettingProto sms_outgoing_check_interval_ms = 108;
-    optional SettingProto sms_outgoing_check_max_count = 109;
-    optional SettingProto sms_short_code_confirmation = 110;
-    optional SettingProto sms_short_code_rule = 111;
-    optional SettingProto tcp_default_init_rwnd = 112;
-    optional SettingProto tether_supported = 113;
-    optional SettingProto tether_dun_required = 114;
+    optional SettingProto sms_outgoing_check_interval_ms = 108 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto sms_outgoing_check_max_count = 109 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    // Used to disable SMS short code confirmation. Defaults to true.
+    optional SettingProto sms_short_code_confirmation = 110 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto sms_short_code_rule = 111 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto tcp_default_init_rwnd = 112 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto tether_supported = 113 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto tether_dun_required = 114 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto tether_dun_apn = 115;
-    optional SettingProto tether_offload_disabled = 301;
-    optional SettingProto carrier_app_whitelist = 116;
-    optional SettingProto usb_mass_storage_enabled = 117;
-    optional SettingProto use_google_mail = 118;
+    optional SettingProto tether_offload_disabled = 301 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    // List of carrier apps which are whitelisted to prompt the user for install
+    // when a SIM card with marchin UICC carrier privilege rules is inserted.
+    optional SettingProto carrier_app_whitelist = 116 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto usb_mass_storage_enabled = 117 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto use_google_mail = 118 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto webview_data_reduction_proxy_key = 119;
-    optional SettingProto webview_fallback_logic_enabled = 120;
-    optional SettingProto webview_provider = 121;
-    optional SettingProto webview_multiprocess = 122;
-    optional SettingProto network_switch_notification_daily_limit = 123;
-    optional SettingProto network_switch_notification_rate_limit_millis = 124;
-    optional SettingProto network_avoid_bad_wifi = 125;
-    optional SettingProto network_metered_multipath_preference = 302;
-    optional SettingProto network_watchlist_last_report_time = 303;
-    optional SettingProto wifi_badging_thresholds = 304;
-    optional SettingProto wifi_display_on = 126;
-    optional SettingProto wifi_display_certification_on = 127;
-    optional SettingProto wifi_display_wps_config = 128;
-    optional SettingProto wifi_networks_available_notification_on = 129;
-    optional SettingProto wimax_networks_available_notification_on = 130;
-    optional SettingProto wifi_networks_available_repeat_delay = 131;
+    optional SettingProto webview_fallback_logic_enabled = 120 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    // Name of the package used as WebView provider.
+    optional SettingProto webview_provider = 121 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto webview_multiprocess = 122 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto network_switch_notification_daily_limit = 123 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto network_switch_notification_rate_limit_millis = 124 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto network_avoid_bad_wifi = 125 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto network_metered_multipath_preference = 302 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto network_watchlist_last_report_time = 303 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto wifi_badging_thresholds = 304 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto wifi_display_on = 126 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto wifi_display_certification_on = 127 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto wifi_display_wps_config = 128 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto wifi_networks_available_notification_on = 129 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto wimax_networks_available_notification_on = 130 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto wifi_networks_available_repeat_delay = 131 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto wifi_country_code = 132;
-    optional SettingProto wifi_framework_scan_interval_ms = 133;
-    optional SettingProto wifi_idle_ms = 134;
-    optional SettingProto wifi_num_open_networks_kept = 135;
-    optional SettingProto wifi_on = 136;
-    optional SettingProto wifi_scan_always_available = 137;
-    optional SettingProto wifi_wakeup_enabled = 138;
-    optional SettingProto wifi_wakeup_available = 305;
-    optional SettingProto network_scoring_ui_enabled = 306;
-    optional SettingProto speed_label_cache_eviction_age_millis = 307;
-    optional SettingProto recommended_network_evaluator_cache_expiry_ms = 308;
-    optional SettingProto network_recommendations_enabled = 139;
-    optional SettingProto network_recommendations_package = 286;
-    optional SettingProto use_open_wifi_package = 309;
-    optional SettingProto network_recommendation_request_timeout_ms = 310;
-    optional SettingProto ble_scan_always_available = 140;
-    optional SettingProto wifi_saved_state = 141;
-    optional SettingProto wifi_supplicant_scan_interval_ms = 142;
-    optional SettingProto wifi_enhanced_auto_join = 143;
-    optional SettingProto wifi_network_show_rssi = 144;
-    optional SettingProto wifi_scan_interval_when_p2p_connected_ms = 145;
-    optional SettingProto wifi_watchdog_on = 146;
-    optional SettingProto wifi_watchdog_poor_network_test_enabled = 147;
-    optional SettingProto wifi_suspend_optimizations_enabled = 148;
-    optional SettingProto wifi_verbose_logging_enabled = 149;
-    optional SettingProto wifi_max_dhcp_retry_count = 150;
-    optional SettingProto wifi_mobile_data_transition_wakelock_timeout_ms = 151;
-    optional SettingProto wifi_device_owner_configs_lockdown = 152;
-    optional SettingProto wifi_frequency_band = 153;
+    optional SettingProto wifi_framework_scan_interval_ms = 133 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto wifi_idle_ms = 134 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto wifi_num_open_networks_kept = 135 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto wifi_on = 136 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto wifi_scan_always_available = 137 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto wifi_wakeup_enabled = 138 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto wifi_wakeup_available = 305 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto network_scoring_ui_enabled = 306 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto speed_label_cache_eviction_age_millis = 307 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto recommended_network_evaluator_cache_expiry_ms = 308 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto network_recommendations_enabled = 139 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto network_recommendations_package = 286 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto use_open_wifi_package = 309 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto network_recommendation_request_timeout_ms = 310 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto ble_scan_always_available = 140 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto wifi_saved_state = 141 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto wifi_supplicant_scan_interval_ms = 142 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto wifi_enhanced_auto_join = 143 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto wifi_network_show_rssi = 144 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto wifi_scan_interval_when_p2p_connected_ms = 145 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto wifi_watchdog_on = 146 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto wifi_watchdog_poor_network_test_enabled = 147 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto wifi_suspend_optimizations_enabled = 148 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto wifi_verbose_logging_enabled = 149 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto wifi_connected_mac_randomization_enabled = 350 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto wifi_max_dhcp_retry_count = 150 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto wifi_mobile_data_transition_wakelock_timeout_ms = 151 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto wifi_device_owner_configs_lockdown = 152 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto wifi_frequency_band = 153 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto wifi_p2p_device_name = 154;
-    optional SettingProto wifi_reenable_delay_ms = 155;
-    optional SettingProto wifi_ephemeral_out_of_range_timeout_ms = 156;
-    optional SettingProto data_stall_alarm_non_aggressive_delay_in_ms = 157;
-    optional SettingProto data_stall_alarm_aggressive_delay_in_ms = 158;
-    optional SettingProto provisioning_apn_alarm_delay_in_ms = 159;
-    optional SettingProto gprs_register_check_period_ms = 160;
-    optional SettingProto wtf_is_fatal = 161;
-    optional SettingProto mode_ringer = 162;
-    optional SettingProto overlay_display_devices = 163;
-    optional SettingProto battery_discharge_duration_threshold = 164;
-    optional SettingProto battery_discharge_threshold = 165;
-    optional SettingProto send_action_app_error = 166;
-    optional SettingProto dropbox_age_seconds = 167;
-    optional SettingProto dropbox_max_files = 168;
-    optional SettingProto dropbox_quota_kb = 169;
-    optional SettingProto dropbox_quota_percent = 170;
-    optional SettingProto dropbox_reserve_percent = 171;
-    optional SettingProto dropbox_tag_prefix = 172;
-    optional SettingProto error_logcat_prefix = 173;
-    optional SettingProto sys_free_storage_log_interval = 174;
-    optional SettingProto disk_free_change_reporting_threshold = 175;
-    optional SettingProto sys_storage_threshold_percentage = 176;
-    optional SettingProto sys_storage_threshold_max_bytes = 177;
-    optional SettingProto sys_storage_full_threshold_bytes = 178;
-    optional SettingProto sys_storage_cache_percentage = 311;
-    optional SettingProto sys_storage_cache_max_bytes = 312;
-    optional SettingProto sync_max_retry_delay_in_seconds = 179;
-    optional SettingProto connectivity_change_delay = 180;
-    optional SettingProto connectivity_sampling_interval_in_seconds = 181;
-    optional SettingProto pac_change_delay = 182;
-    optional SettingProto captive_portal_mode = 183;
-    optional SettingProto captive_portal_detection_enabled = 313;
+    optional SettingProto wifi_reenable_delay_ms = 155 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto wifi_ephemeral_out_of_range_timeout_ms = 156 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto data_stall_alarm_non_aggressive_delay_in_ms = 157 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto data_stall_alarm_aggressive_delay_in_ms = 158 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto provisioning_apn_alarm_delay_in_ms = 159 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto gprs_register_check_period_ms = 160 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto wtf_is_fatal = 161 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    // Ringer mode. A change in this value will not reflect as a change in the
+    // ringer mode.
+    optional SettingProto mode_ringer = 162 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    // Overlay display devices setting.
+    // The value is a specially formatted string that describes the size and
+    // density of simulated secondary devices.
+    // Format: {width}x{height}/dpi;...
+    optional SettingProto overlay_display_devices = 163 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto battery_discharge_duration_threshold = 164 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto battery_discharge_threshold = 165 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto send_action_app_error = 166 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto dropbox_age_seconds = 167 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto dropbox_max_files = 168 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto dropbox_quota_kb = 169 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto dropbox_quota_percent = 170 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto dropbox_reserve_percent = 171 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto dropbox_tag_prefix = 172 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto error_logcat_prefix = 173 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto sys_free_storage_log_interval = 174 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto disk_free_change_reporting_threshold = 175 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto sys_storage_threshold_percentage = 176 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto sys_storage_threshold_max_bytes = 177 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto sys_storage_full_threshold_bytes = 178 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto sys_storage_cache_percentage = 311 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto sys_storage_cache_max_bytes = 312 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto sync_max_retry_delay_in_seconds = 179 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto connectivity_change_delay = 180 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto connectivity_sampling_interval_in_seconds = 181 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto pac_change_delay = 182 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto captive_portal_mode = 183 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto captive_portal_detection_enabled = 313 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto captive_portal_server = 184;
     optional SettingProto captive_portal_https_url = 185;
     optional SettingProto captive_portal_http_url = 186;
     optional SettingProto captive_portal_fallback_url = 187;
     optional SettingProto captive_portal_other_fallback_urls = 314;
-    optional SettingProto captive_portal_use_https = 188;
+    optional SettingProto captive_portal_use_https = 188 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto captive_portal_user_agent = 189;
-    optional SettingProto nsd_on = 190;
-    optional SettingProto set_install_location = 191;
-    optional SettingProto default_install_location = 192;
-    optional SettingProto inet_condition_debounce_up_delay = 193;
-    optional SettingProto inet_condition_debounce_down_delay = 194;
-    optional SettingProto read_external_storage_enforced_default = 195;
+    optional SettingProto nsd_on = 190 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    // Let user pick default install location.
+    optional SettingProto set_install_location = 191 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto default_install_location = 192 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto inet_condition_debounce_up_delay = 193 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto inet_condition_debounce_down_delay = 194 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto read_external_storage_enforced_default = 195 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto http_proxy = 196;
     optional SettingProto global_http_proxy_host = 197;
     optional SettingProto global_http_proxy_port = 198;
     optional SettingProto global_http_proxy_exclusion_list = 199;
     optional SettingProto global_http_proxy_pac = 200;
-    optional SettingProto set_global_http_proxy = 201;
+    // Enables the UI setting to allow the user to specify the global HTTP proxy
+    // and associated exclusion list.
+    optional SettingProto set_global_http_proxy = 201 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto default_dns_server = 202;
     // The requested Private DNS mode and an accompanying specifier.
     optional SettingProto private_dns_mode = 315;
     optional SettingProto private_dns_specifier = 316;
-    optional SettingProto bluetooth_headset_priority_prefix = 203;
-    optional SettingProto bluetooth_a2dp_sink_priority_prefix = 204;
-    optional SettingProto bluetooth_a2dp_src_priority_prefix = 205;
-    optional SettingProto bluetooth_a2dp_supports_optional_codecs_prefix = 287;
-    optional SettingProto bluetooth_a2dp_optional_codecs_enabled_prefix = 288;
-    optional SettingProto bluetooth_input_device_priority_prefix = 206;
-    optional SettingProto bluetooth_map_priority_prefix = 207;
-    optional SettingProto bluetooth_map_client_priority_prefix = 208;
-    optional SettingProto bluetooth_pbap_client_priority_prefix = 209;
-    optional SettingProto bluetooth_sap_priority_prefix = 210;
-    optional SettingProto bluetooth_pan_priority_prefix = 211;
-    optional SettingProto bluetooth_hearing_aid_priority_prefix = 345;
+    optional SettingProto bluetooth_headset_priority_prefix = 203 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto bluetooth_a2dp_sink_priority_prefix = 204 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto bluetooth_a2dp_src_priority_prefix = 205 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto bluetooth_a2dp_supports_optional_codecs_prefix = 287 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto bluetooth_a2dp_optional_codecs_enabled_prefix = 288 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto bluetooth_input_device_priority_prefix = 206 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto bluetooth_map_priority_prefix = 207 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto bluetooth_map_client_priority_prefix = 208 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto bluetooth_pbap_client_priority_prefix = 209 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto bluetooth_sap_priority_prefix = 210 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto bluetooth_pan_priority_prefix = 211 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto bluetooth_hearing_aid_priority_prefix = 345 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto activity_manager_constants = 317;
     optional SettingProto device_idle_constants = 212;
     optional SettingProto device_idle_constants_watch = 213;
@@ -295,26 +321,28 @@
     optional SettingProto shortcut_manager_constants = 217;
     optional SettingProto device_policy_constants = 322;
     optional SettingProto text_classifier_constants = 323;
-    optional SettingProto window_animation_scale = 218;
-    optional SettingProto transition_animation_scale = 219;
-    optional SettingProto animator_duration_scale = 220;
-    optional SettingProto fancy_ime_animations = 221;
-    optional SettingProto compatibility_mode = 222;
-    optional SettingProto emergency_tone = 223;
-    optional SettingProto call_auto_retry = 224;
-    optional SettingProto emergency_affordance_needed = 225;
-    optional SettingProto preferred_network_mode = 226;
+    optional SettingProto window_animation_scale = 218 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto transition_animation_scale = 219 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto animator_duration_scale = 220 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto fancy_ime_animations = 221 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto compatibility_mode = 222 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto emergency_tone = 223 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto call_auto_retry = 224 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto emergency_affordance_needed = 225 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto preferred_network_mode = 226 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    // Name of an application package to be debugged.
     optional SettingProto debug_app = 227;
-    optional SettingProto wait_for_debugger = 228;
-    optional SettingProto enable_gpu_debug_layers = 342;
+    optional SettingProto wait_for_debugger = 228 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto enable_gpu_debug_layers = 342 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    // App allowed to load GPU debug layers.
     optional SettingProto gpu_debug_app = 343;
-    optional SettingProto gpu_debug_layers = 344;
-    optional SettingProto low_power_mode = 229;
-    optional SettingProto low_power_mode_trigger_level = 230;
-    optional SettingProto always_finish_activities = 231;
-    optional SettingProto dock_audio_media_enabled = 232;
-    optional SettingProto encoded_surround_output = 233;
-    optional SettingProto audio_safe_volume_state = 234;
+    optional SettingProto gpu_debug_layers = 344 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto low_power_mode = 229 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto low_power_mode_trigger_level = 230 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto always_finish_activities = 231 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto dock_audio_media_enabled = 232 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto encoded_surround_output = 233 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto audio_safe_volume_state = 234 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto tzinfo_update_content_url = 235;
     optional SettingProto tzinfo_update_metadata_url = 236;
     optional SettingProto selinux_update_content_url = 237;
@@ -331,308 +359,349 @@
     optional SettingProto lang_id_update_metadata_url = 325;
     optional SettingProto smart_selection_update_content_url = 326;
     optional SettingProto smart_selection_update_metadata_url = 327;
-    optional SettingProto selinux_status = 247;
-    optional SettingProto development_force_rtl = 248;
-    optional SettingProto low_battery_sound_timeout = 249;
-    optional SettingProto wifi_bounce_delay_override_ms = 250;
-    optional SettingProto policy_control = 251;
-    optional SettingProto zen_mode = 252;
-    optional SettingProto zen_mode_ringer_level = 253;
+    optional SettingProto selinux_status = 247 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto development_force_rtl = 248 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto low_battery_sound_timeout = 249 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto wifi_bounce_delay_override_ms = 250 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto policy_control = 251 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto zen_mode = 252 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto zen_mode_ringer_level = 253 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto zen_mode_config_etag = 254;
-    optional SettingProto heads_up_notifications_enabled = 255;
+    optional SettingProto heads_up_notifications_enabled = 255 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto device_name = 256;
-    optional SettingProto network_scoring_provisioned = 257;
-    optional SettingProto require_password_to_decrypt = 258;
-    optional SettingProto enhanced_4g_mode_enabled = 259;
-    optional SettingProto vt_ims_enabled = 260;
-    optional SettingProto wfc_ims_enabled = 261;
-    optional SettingProto wfc_ims_mode = 262;
-    optional SettingProto wfc_ims_roaming_mode = 263;
-    optional SettingProto wfc_ims_roaming_enabled = 264;
-    optional SettingProto lte_service_forced = 265;
-    optional SettingProto ephemeral_cookie_max_size_bytes = 266;
-    optional SettingProto enable_ephemeral_feature = 267;
-    optional SettingProto instant_app_dexopt_enabled = 328;
-    optional SettingProto installed_instant_app_min_cache_period = 268;
-    optional SettingProto installed_instant_app_max_cache_period = 289;
-    optional SettingProto uninstalled_instant_app_min_cache_period = 290;
-    optional SettingProto uninstalled_instant_app_max_cache_period = 291;
-    optional SettingProto unused_static_shared_lib_min_cache_period = 292;
-    optional SettingProto allow_user_switching_when_system_user_locked = 269;
-    optional SettingProto boot_count = 270;
-    optional SettingProto safe_boot_disallowed = 271;
-    optional SettingProto device_demo_mode = 272;
-    optional SettingProto network_access_timeout_ms = 329;
+    optional SettingProto network_scoring_provisioned = 257 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto require_password_to_decrypt = 258 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto enhanced_4g_mode_enabled = 259 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto vt_ims_enabled = 260 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto wfc_ims_enabled = 261 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto wfc_ims_mode = 262 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto wfc_ims_roaming_mode = 263 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto wfc_ims_roaming_enabled = 264 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto lte_service_forced = 265 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto ephemeral_cookie_max_size_bytes = 266 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto enable_ephemeral_feature = 267 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto instant_app_dexopt_enabled = 328 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto installed_instant_app_min_cache_period = 268 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto installed_instant_app_max_cache_period = 289 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto uninstalled_instant_app_min_cache_period = 290 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto uninstalled_instant_app_max_cache_period = 291 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto unused_static_shared_lib_min_cache_period = 292 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto allow_user_switching_when_system_user_locked = 269 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto boot_count = 270 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto safe_boot_disallowed = 271 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto device_demo_mode = 272 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto network_access_timeout_ms = 329 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto database_downgrade_reason = 274;
-    optional SettingProto database_creation_buildid = 330;
-    optional SettingProto contacts_database_wal_enabled = 275;
-    optional SettingProto location_settings_link_to_permissions_enabled = 331;
+    optional SettingProto database_creation_buildid = 330 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto contacts_database_wal_enabled = 275 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto location_settings_link_to_permissions_enabled = 331 [ (android.privacy).dest = DEST_AUTOMATIC ];
     reserved 332; // Removed backup_refactored_service_disabled
-    optional SettingProto euicc_factory_reset_timeout_millis = 333;
-    optional SettingProto storage_settings_clobber_threshold = 334;
-    optional SettingProto multi_sim_voice_call_subscription = 276;
-    optional SettingProto multi_sim_voice_prompt = 277;
-    optional SettingProto multi_sim_data_call_subscription = 278;
-    optional SettingProto multi_sim_sms_subscription = 279;
-    optional SettingProto multi_sim_sms_prompt = 280;
-    optional SettingProto new_contact_aggregator = 281;
-    optional SettingProto contact_metadata_sync_enabled = 282;
-    optional SettingProto enable_cellular_on_boot = 283;
-    optional SettingProto max_notification_enqueue_rate = 284;
-    optional SettingProto show_notification_channel_warnings = 335;
-    optional SettingProto cell_on = 285;
-    optional SettingProto show_temperature_warning = 336;
-    optional SettingProto warning_temperature = 337;
-    optional SettingProto enable_diskstats_logging = 338;
-    optional SettingProto enable_cache_quota_calculation = 339;
-    optional SettingProto enable_deletion_helper_no_threshold_toggle = 340;
-    optional SettingProto notification_snooze_options = 341;
-    optional SettingProto enable_gnss_raw_meas_full_tracking = 346;
-    optional SettingProto zram_enabled = 347;
-    optional SettingProto enable_smart_replies_in_notifications = 348;
-    optional SettingProto show_first_crash_dialog = 349;
-    optional SettingProto wifi_connected_mac_randomization_enabled = 350;
-    optional SettingProto show_restart_in_crash_dialog = 351;
-    optional SettingProto show_mute_in_crash_dialog = 352;
-    optional SettingProto chained_battery_attribution_enabled = 353;
+    optional SettingProto euicc_factory_reset_timeout_millis = 333 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto storage_settings_clobber_threshold = 334 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto chained_battery_attribution_enabled = 353 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    // Subscription to be used for voice call on a multi sim device. The
+    // supported values are 0 = SUB1, 1 = SUB2 and etc.
+    optional SettingProto multi_sim_voice_call_subscription = 276 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto multi_sim_voice_prompt = 277 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto multi_sim_data_call_subscription = 278 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto multi_sim_sms_subscription = 279 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto multi_sim_sms_prompt = 280 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    // Whether to enable new contacts aggregator or not.
+    // 1 = enable, 0 = disable.
+    optional SettingProto new_contact_aggregator = 281 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto contact_metadata_sync_enabled = 282 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto enable_cellular_on_boot = 283 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto max_notification_enqueue_rate = 284 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto show_notification_channel_warnings = 335 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto cell_on = 285 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto show_temperature_warning = 336 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto warning_temperature = 337 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto enable_diskstats_logging = 338 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto enable_cache_quota_calculation = 339 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto enable_deletion_helper_no_threshold_toggle = 340 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto notification_snooze_options = 341 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto enable_gnss_raw_meas_full_tracking = 346 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto zram_enabled = 347 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto enable_smart_replies_in_notifications = 348 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto show_first_crash_dialog = 349 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto show_restart_in_crash_dialog = 351 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto show_mute_in_crash_dialog = 352 [ (android.privacy).dest = DEST_AUTOMATIC ];
 
+    // Please insert fields in the same order as in
+    // frameworks/base/core/java/android/provider/Settings.java.
     // Next tag = 354;
 }
 
 message SecureSettingsProto {
+    option (android.msg_privacy).dest = DEST_EXPLICIT;
+
     repeated SettingsOperationProto historical_operations = 1;
 
     optional SettingProto android_id = 2;
-    optional SettingProto default_input_method = 3;
-    optional SettingProto selected_input_method_subtype = 4;
-    optional SettingProto input_methods_subtype_history = 5;
-    optional SettingProto input_method_selector_visibility = 6;
-    optional SettingProto voice_interaction_service = 7;
-    optional SettingProto autofill_service = 8;
+    optional SettingProto default_input_method = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto selected_input_method_subtype = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto input_methods_subtype_history = 5 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto input_method_selector_visibility = 6 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    // The currently selected voice interaction service flattened ComponentName.
+    optional SettingProto voice_interaction_service = 7 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    // The currently selected autofill service flattened ComponentName.
+    optional SettingProto autofill_service = 8 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto bluetooth_hci_log = 9;
-    optional SettingProto user_setup_complete = 10;
+    optional SettingProto user_setup_complete = 10 [ (android.privacy).dest = DEST_AUTOMATIC ];
     // Whether the current user has been set up via setup wizard (0 = false,
     // 1 = true). This value differs from USER_SETUP_COMPLETE in that it can be
     // reset back to 0 in case SetupWizard has been re-enabled on TV devices.
-    optional SettingProto tv_user_setup_complete = 170;
-    optional SettingProto completed_category_prefix = 11;
-    optional SettingProto enabled_input_methods = 12;
-    optional SettingProto disabled_system_input_methods = 13;
-    optional SettingProto show_ime_with_hard_keyboard = 14;
+    optional SettingProto tv_user_setup_complete = 170 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto completed_category_prefix = 11 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto enabled_input_methods = 12 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto disabled_system_input_methods = 13 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto show_ime_with_hard_keyboard = 14 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto always_on_vpn_app = 15;
-    optional SettingProto always_on_vpn_lockdown = 16;
-    optional SettingProto install_non_market_apps = 17;
-    optional SettingProto unknown_sources_default_reversed = 171;
-    optional SettingProto location_mode = 18;
+    optional SettingProto always_on_vpn_lockdown = 16 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto install_non_market_apps = 17 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto unknown_sources_default_reversed = 171 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    // The degree of location access enabled by the user.
+    optional SettingProto location_mode = 18 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto location_previous_mode = 19;
-    optional SettingProto lock_to_app_exit_locked = 20;
-    optional SettingProto lock_screen_lock_after_timeout = 21;
-    optional SettingProto lock_screen_allow_private_notifications = 172;
-    optional SettingProto lock_screen_allow_remote_input = 22;
-    optional SettingProto show_note_about_notification_hiding = 23;
-    optional SettingProto trust_agents_initialized = 24;
-    optional SettingProto parental_control_enabled = 25;
-    optional SettingProto parental_control_last_update = 26;
-    optional SettingProto parental_control_redirect_url = 27;
-    optional SettingProto settings_classname = 28;
-    optional SettingProto accessibility_enabled = 29;
-    optional SettingProto accessibility_shortcut_enabled = 173;
-    optional SettingProto accessibility_shortcut_on_lock_screen = 174;
-    optional SettingProto accessibility_shortcut_dialog_shown = 175;
-    optional SettingProto accessibility_shortcut_target_service = 176;
-    optional SettingProto accessibility_button_target_component = 177;
-    optional SettingProto touch_exploration_enabled = 30;
+    // Whether lock-to-app will lock the keyguard when exiting.
+    optional SettingProto lock_to_app_exit_locked = 20 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto lock_screen_lock_after_timeout = 21 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto lock_screen_allow_private_notifications = 172 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto lock_screen_allow_remote_input = 22 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto show_note_about_notification_hiding = 23 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto trust_agents_initialized = 24 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto parental_control_enabled = 25 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto parental_control_last_update = 26 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto parental_control_redirect_url = 27 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto settings_classname = 28 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto accessibility_enabled = 29 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto accessibility_shortcut_enabled = 173 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto accessibility_shortcut_on_lock_screen = 174 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto accessibility_shortcut_dialog_shown = 175 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto accessibility_shortcut_target_service = 176 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    // Setting specifying the accessibility service or feature to be toggled via
+    // the accessibility button in the navigation bar. This is either a
+    // flattened ComponentName or the class name of a system class implementing
+    // a supported accessibility feature.
+    optional SettingProto accessibility_button_target_component = 177 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto touch_exploration_enabled = 30 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    // List of the enabled accessibility providers.
     optional SettingProto enabled_accessibility_services = 31;
+    // 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 = 32;
-    optional SettingProto accessibility_speak_password = 33;
-    optional SettingProto accessibility_high_text_contrast_enabled = 34;
+    // Whether to speak passwords while in accessibility mode.
+    optional SettingProto accessibility_speak_password = 33 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto accessibility_high_text_contrast_enabled = 34 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto accessibility_script_injection = 35;
     optional SettingProto accessibility_screen_reader_url = 36;
     optional SettingProto accessibility_web_content_key_bindings = 37;
-    optional SettingProto accessibility_display_magnification_enabled = 38;
-    optional SettingProto accessibility_display_magnification_navbar_enabled = 178;
-    optional SettingProto accessibility_display_magnification_scale = 39;
-    optional SettingProto accessibility_display_magnification_auto_update = 179;
-    optional SettingProto accessibility_soft_keyboard_mode = 40;
-    optional SettingProto accessibility_captioning_enabled = 41;
-    optional SettingProto accessibility_captioning_locale = 42;
-    optional SettingProto accessibility_captioning_preset = 43;
-    optional SettingProto accessibility_captioning_background_color = 44;
-    optional SettingProto accessibility_captioning_foreground_color = 45;
-    optional SettingProto accessibility_captioning_edge_type = 46;
-    optional SettingProto accessibility_captioning_edge_color = 47;
-    optional SettingProto accessibility_captioning_window_color = 48;
-    optional SettingProto accessibility_captioning_typeface = 49;
-    optional SettingProto accessibility_captioning_font_scale = 50;
-    optional SettingProto accessibility_display_inversion_enabled = 51;
-    optional SettingProto accessibility_display_daltonizer_enabled = 52;
-    optional SettingProto accessibility_display_daltonizer = 53;
-    optional SettingProto accessibility_autoclick_enabled = 54;
-    optional SettingProto accessibility_autoclick_delay = 55;
-    optional SettingProto accessibility_large_pointer_icon = 56;
-    optional SettingProto long_press_timeout = 57;
-    optional SettingProto multi_press_timeout = 58;
+    optional SettingProto accessibility_display_magnification_enabled = 38 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto accessibility_display_magnification_navbar_enabled = 178 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto accessibility_display_magnification_scale = 39 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto accessibility_display_magnification_auto_update = 179 [deprecated = true];
+    optional SettingProto accessibility_soft_keyboard_mode = 40 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto accessibility_captioning_enabled = 41 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto accessibility_captioning_locale = 42 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto accessibility_captioning_preset = 43 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto accessibility_captioning_background_color = 44 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto accessibility_captioning_foreground_color = 45 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto accessibility_captioning_edge_type = 46 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto accessibility_captioning_edge_color = 47 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto accessibility_captioning_window_color = 48 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto accessibility_captioning_typeface = 49 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto accessibility_captioning_font_scale = 50 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto accessibility_display_inversion_enabled = 51 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto accessibility_display_daltonizer_enabled = 52 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto accessibility_display_daltonizer = 53 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto accessibility_autoclick_enabled = 54 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto accessibility_autoclick_delay = 55 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto accessibility_large_pointer_icon = 56 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto long_press_timeout = 57 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto multi_press_timeout = 58 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto enabled_print_services = 59;
     optional SettingProto disabled_print_services = 60;
-    optional SettingProto display_density_forced = 61;
-    optional SettingProto tts_default_rate = 62;
-    optional SettingProto tts_default_pitch = 63;
-    optional SettingProto tts_default_synth = 64;
-    optional SettingProto tts_default_locale = 65;
+    optional SettingProto display_density_forced = 61 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto tts_default_rate = 62 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto tts_default_pitch = 63 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto tts_default_synth = 64 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto tts_default_locale = 65 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto tts_enabled_plugins = 66;
-    optional SettingProto connectivity_release_pending_intent_delay_ms = 67;
+    optional SettingProto connectivity_release_pending_intent_delay_ms = 67 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto allowed_geolocation_origins = 68;
-    optional SettingProto preferred_tty_mode = 69;
-    optional SettingProto enhanced_voice_privacy_enabled = 70;
-    optional SettingProto tty_mode_enabled = 71;
-    optional SettingProto backup_enabled = 72;
-    optional SettingProto backup_auto_restore = 73;
-    optional SettingProto backup_provisioned = 74;
-    optional SettingProto backup_transport = 75;
-    optional SettingProto last_setup_shown = 76;
-    optional SettingProto search_global_search_activity = 77;
-    optional SettingProto search_num_promoted_sources = 78;
-    optional SettingProto search_max_results_to_display = 79;
-    optional SettingProto search_max_results_per_source = 80;
-    optional SettingProto search_web_results_override_limit = 81;
-    optional SettingProto search_promoted_source_deadline_millis = 82;
-    optional SettingProto search_source_timeout_millis = 83;
-    optional SettingProto search_prefill_millis = 84;
-    optional SettingProto search_max_stat_age_millis = 85;
-    optional SettingProto search_max_source_event_age_millis = 86;
-    optional SettingProto search_min_impressions_for_source_ranking = 87;
-    optional SettingProto search_min_clicks_for_source_ranking = 88;
-    optional SettingProto search_max_shortcuts_returned = 89;
-    optional SettingProto search_query_thread_core_pool_size = 90;
-    optional SettingProto search_query_thread_max_pool_size = 91;
-    optional SettingProto search_shortcut_refresh_core_pool_size = 92;
-    optional SettingProto search_shortcut_refresh_max_pool_size = 93;
-    optional SettingProto search_thread_keepalive_seconds = 94;
-    optional SettingProto search_per_source_concurrent_query_limit = 95;
-    optional SettingProto mount_play_notification_snd = 96;
-    optional SettingProto mount_ums_autostart = 97;
-    optional SettingProto mount_ums_prompt = 98;
-    optional SettingProto mount_ums_notify_enabled = 99;
-    optional SettingProto anr_show_background = 100;
-    optional SettingProto voice_recognition_service = 101;
-    optional SettingProto package_verifier_user_consent = 102;
-    optional SettingProto selected_spell_checker = 103;
-    optional SettingProto selected_spell_checker_subtype = 104;
-    optional SettingProto spell_checker_enabled = 105;
-    optional SettingProto incall_power_button_behavior = 106;
-    optional SettingProto incall_back_button_behavior = 107;
-    optional SettingProto wake_gesture_enabled = 108;
-    optional SettingProto doze_enabled = 109;
-    optional SettingProto doze_always_on = 110;
-    optional SettingProto doze_pulse_on_pick_up = 111;
-    optional SettingProto doze_pulse_on_long_press = 180;
-    optional SettingProto doze_pulse_on_double_tap = 112;
-    optional SettingProto ui_night_mode = 113;
-    optional SettingProto screensaver_enabled = 114;
-    optional SettingProto screensaver_components = 115;
-    optional SettingProto screensaver_activate_on_dock = 116;
-    optional SettingProto screensaver_activate_on_sleep = 117;
-    optional SettingProto screensaver_default_component = 118;
-    optional SettingProto nfc_payment_default_component = 119;
-    optional SettingProto nfc_payment_foreground = 120;
-    optional SettingProto sms_default_application = 121;
-    optional SettingProto dialer_default_application = 122;
-    optional SettingProto emergency_assistance_application = 123;
-    optional SettingProto assist_structure_enabled = 124;
-    optional SettingProto assist_screenshot_enabled = 125;
-    optional SettingProto assist_disclosure_enabled = 126;
-    optional SettingProto enabled_notification_assistant = 127;
-    optional SettingProto enabled_notification_listeners = 128;
-    optional SettingProto enabled_notification_policy_access_packages = 129;
-    optional SettingProto sync_parent_sounds = 130;
-    optional SettingProto immersive_mode_confirmations = 131;
-    optional SettingProto print_service_search_uri = 132;
-    optional SettingProto payment_service_search_uri = 133;
-    optional SettingProto autofill_service_search_uri = 181;
-    optional SettingProto skip_first_use_hints = 134;
-    optional SettingProto unsafe_volume_music_active_ms = 135;
-    optional SettingProto lock_screen_show_notifications = 136;
+    optional SettingProto preferred_tty_mode = 69 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto enhanced_voice_privacy_enabled = 70 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto tty_mode_enabled = 71 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto backup_enabled = 72 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto backup_auto_restore = 73 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto backup_provisioned = 74 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto backup_transport = 75 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto last_setup_shown = 76 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto search_global_search_activity = 77 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto search_num_promoted_sources = 78 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto search_max_results_to_display = 79 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto search_max_results_per_source = 80 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto search_web_results_override_limit = 81 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto search_promoted_source_deadline_millis = 82 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto search_source_timeout_millis = 83 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto search_prefill_millis = 84 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto search_max_stat_age_millis = 85 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto search_max_source_event_age_millis = 86 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto search_min_impressions_for_source_ranking = 87 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto search_min_clicks_for_source_ranking = 88 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto search_max_shortcuts_returned = 89 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto search_query_thread_core_pool_size = 90 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto search_query_thread_max_pool_size = 91 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto search_shortcut_refresh_core_pool_size = 92 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto search_shortcut_refresh_max_pool_size = 93 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto search_thread_keepalive_seconds = 94 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto search_per_source_concurrent_query_limit = 95 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    // Whether or not alert sounds are played on StorageManagerService events.
+    optional SettingProto mount_play_notification_snd = 96 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto mount_ums_autostart = 97 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto mount_ums_prompt = 98 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto mount_ums_notify_enabled = 99 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto anr_show_background = 100 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    // The ComponentName string of the service to be used as the voice
+    // recognition service.
+    optional SettingProto voice_recognition_service = 101 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto package_verifier_user_consent = 102 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto selected_spell_checker = 103 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto selected_spell_checker_subtype = 104 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto spell_checker_enabled = 105 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto incall_power_button_behavior = 106 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto incall_back_button_behavior = 107 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto wake_gesture_enabled = 108 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto doze_enabled = 109 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto doze_always_on = 110 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto doze_pulse_on_pick_up = 111 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto doze_pulse_on_long_press = 180 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto doze_pulse_on_double_tap = 112 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto ui_night_mode = 113 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto screensaver_enabled = 114 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto screensaver_components = 115 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto screensaver_activate_on_dock = 116 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto screensaver_activate_on_sleep = 117 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto screensaver_default_component = 118 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto nfc_payment_default_component = 119 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto nfc_payment_foreground = 120 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto sms_default_application = 121 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto dialer_default_application = 122 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto emergency_assistance_application = 123 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto assist_structure_enabled = 124 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto assist_screenshot_enabled = 125 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto assist_disclosure_enabled = 126 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    // Read only list of the service components that the current user has
+    // explicitly allowed to see and assist with all of the user's
+    // notifications.
+    optional SettingProto enabled_notification_assistant = 127 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto enabled_notification_listeners = 128 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto enabled_notification_policy_access_packages = 129 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    // Defines whether managed profile ringtones should be synced from its
+    // parent profile.
+    optional SettingProto sync_parent_sounds = 130 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto immersive_mode_confirmations = 131 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    // The query URI to find a print service to install.
+    optional SettingProto print_service_search_uri = 132 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    // The query URI to find an NFC service to install.
+    optional SettingProto payment_service_search_uri = 133 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    // The query URI to find an auto fill service to install.
+    optional SettingProto autofill_service_search_uri = 181 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto skip_first_use_hints = 134 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto unsafe_volume_music_active_ms = 135 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto lock_screen_show_notifications = 136 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto tv_input_hidden_inputs = 137;
     optional SettingProto tv_input_custom_labels = 138;
-    optional SettingProto usb_audio_automatic_routing_disabled = 139;
-    optional SettingProto sleep_timeout = 140;
-    optional SettingProto double_tap_to_wake = 141;
-    optional SettingProto assistant = 142;
-    optional SettingProto camera_gesture_disabled = 143;
-    optional SettingProto camera_double_tap_power_gesture_disabled = 144;
-    optional SettingProto camera_double_twist_to_flip_enabled = 145;
-    optional SettingProto camera_lift_trigger_enabled = 182;
-    optional SettingProto assist_gesture_enabled = 183;
-    optional SettingProto assist_gesture_sensitivity = 184;
-    optional SettingProto assist_gesture_silence_alerts_enabled = 185;
-    optional SettingProto assist_gesture_wake_enabled = 186;
-    optional SettingProto assist_gesture_setup_complete = 187;
-    optional SettingProto night_display_activated = 146;
-    optional SettingProto night_display_auto_mode = 147;
-    optional SettingProto night_display_color_temperature = 188;
-    optional SettingProto night_display_custom_start_time = 148;
-    optional SettingProto night_display_custom_end_time = 149;
-    optional SettingProto night_display_last_activated_time = 189;
+    optional SettingProto usb_audio_automatic_routing_disabled = 139 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto sleep_timeout = 140 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto double_tap_to_wake = 141 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    // The current assistant component. It could be a voice interaction service,
+    // or an activity that handles ACTION_ASSIST, or empty, which means using
+    // the default handling.
+    optional SettingProto assistant = 142 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto camera_gesture_disabled = 143 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto camera_double_tap_power_gesture_disabled = 144 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto camera_double_twist_to_flip_enabled = 145 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto camera_lift_trigger_enabled = 182 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto assist_gesture_enabled = 183 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto assist_gesture_sensitivity = 184 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto assist_gesture_silence_alerts_enabled = 185 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto assist_gesture_wake_enabled = 186 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto assist_gesture_setup_complete = 187 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto night_display_activated = 146 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto night_display_auto_mode = 147 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto night_display_color_temperature = 188 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto night_display_custom_start_time = 148 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto night_display_custom_end_time = 149 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto night_display_last_activated_time = 189 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto brightness_use_twilight = 150;
-    optional SettingProto enabled_vr_listeners = 151;
-    optional SettingProto vr_display_mode = 152;
-    optional SettingProto carrier_apps_handled = 153;
-    optional SettingProto managed_profile_contact_remote_search = 154;
-    optional SettingProto automatic_storage_manager_enabled = 155;
-    optional SettingProto automatic_storage_manager_days_to_retain = 156;
-    optional SettingProto automatic_storage_manager_bytes_cleared = 157;
-    optional SettingProto automatic_storage_manager_last_run = 158;
-    optional SettingProto automatic_storage_manager_turned_off_by_policy = 190;
-    optional SettingProto system_navigation_keys_enabled = 159;
+    optional SettingProto enabled_vr_listeners = 151 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto vr_display_mode = 152 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto carrier_apps_handled = 153 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto managed_profile_contact_remote_search = 154 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto automatic_storage_manager_enabled = 155 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto automatic_storage_manager_days_to_retain = 156 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto automatic_storage_manager_bytes_cleared = 157 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto automatic_storage_manager_last_run = 158 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto automatic_storage_manager_turned_off_by_policy = 190 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto system_navigation_keys_enabled = 159 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto downloads_backup_enabled = 160;
     optional SettingProto downloads_backup_allow_metered = 161;
     optional SettingProto downloads_backup_charging_only = 162;
     optional SettingProto automatic_storage_manager_downloads_days_to_retain = 163;
-    optional SettingProto qs_tiles = 164;
+    // Holds comma-separated list of ordering of QuickSettings tiles.
+    optional SettingProto qs_tiles = 164 [ (android.privacy).dest = DEST_AUTOMATIC ];
     reserved 165; // Removed demo_user_setup_complete
-    optional SettingProto instant_apps_enabled = 166;
-    optional SettingProto device_paired = 167;
-    optional SettingProto package_verifier_state = 191;
-    optional SettingProto cmas_additional_broadcast_pkg = 192;
-    optional SettingProto notification_badging = 168;
-    optional SettingProto qs_auto_added_tiles = 193;
-    optional SettingProto lockdown_in_power_menu = 194;
+    optional SettingProto instant_apps_enabled = 166 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto device_paired = 167 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto package_verifier_state = 191 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto cmas_additional_broadcast_pkg = 192 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto notification_badging = 168 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto qs_auto_added_tiles = 193 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto lockdown_in_power_menu = 194 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto backup_manager_constants = 169;
-    optional SettingProto show_first_crash_dialog_dev_option = 195;
-    optional SettingProto bluetooth_on_while_driving = 196;
+    optional SettingProto show_first_crash_dialog_dev_option = 195 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto bluetooth_on_while_driving = 196 [ (android.privacy).dest = DEST_AUTOMATIC ];
 
+    // Please insert fields in the same order as in
+    // frameworks/base/core/java/android/provider/Settings.java.
     // Next tag = 197
 }
 
 message SystemSettingsProto {
+    option (android.msg_privacy).dest = DEST_EXPLICIT;
+
     repeated SettingsOperationProto historical_operations = 1;
 
-    optional SettingProto end_button_behavior = 2;
-    optional SettingProto advanced_settings = 3;
-    optional SettingProto bluetooth_discoverability = 4;
-    optional SettingProto bluetooth_discoverability_timeout = 5;
-    optional SettingProto font_scale = 6;
-    optional SettingProto system_locales = 7;
-    optional SettingProto display_color_mode = 67;
-    optional SettingProto screen_off_timeout = 8;
-    optional SettingProto screen_brightness = 9;
-    optional SettingProto screen_brightness_for_vr = 10;
-    optional SettingProto screen_brightness_mode = 11;
-    optional SettingProto screen_auto_brightness_adj = 12;
-    optional SettingProto mode_ringer_streams_affected = 13;
-    optional SettingProto mute_streams_affected = 14;
-    optional SettingProto vibrate_on = 15;
-    optional SettingProto vibrate_input_devices = 16;
-    optional SettingProto volume_ring = 17;
-    optional SettingProto volume_system = 18;
-    optional SettingProto volume_voice = 19;
-    optional SettingProto volume_music = 20;
-    optional SettingProto volume_alarm = 21;
-    optional SettingProto volume_notification = 22;
-    optional SettingProto volume_bluetooth_sco = 23;
-    optional SettingProto volume_accessibility = 68;
-    optional SettingProto volume_master = 24;
-    optional SettingProto master_mono = 25;
+    optional SettingProto end_button_behavior = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto advanced_settings = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto bluetooth_discoverability = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto bluetooth_discoverability_timeout = 5 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto font_scale = 6 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto system_locales = 7 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto display_color_mode = 67 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto screen_off_timeout = 8 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto screen_brightness = 9 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto screen_brightness_for_vr = 10 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto screen_brightness_mode = 11 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto screen_auto_brightness_adj = 12 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    // Determines which streams are affected by ringer mode changes. The stream
+    // type's bit will be set to 1 if it should be muted when going into an
+    // inaudible ringer mode.
+    optional SettingProto mode_ringer_streams_affected = 13 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto mute_streams_affected = 14 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto vibrate_on = 15 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto vibrate_input_devices = 16 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto volume_ring = 17 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto volume_system = 18 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto volume_voice = 19 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto volume_music = 20 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto volume_alarm = 21 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto volume_notification = 22 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto volume_bluetooth_sco = 23 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto volume_accessibility = 68 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto volume_master = 24 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto master_mono = 25 [ (android.privacy).dest = DEST_AUTOMATIC ];
     // Whether silent mode should allow vibration feedback. This is used
     // internally in AudioService and the Sound settings activity to coordinate
     // decoupling of vibrate and silent modes. This setting will likely be
@@ -641,8 +710,10 @@
     // Not used anymore. On devices with vibrator, the user explicitly selects
     // silent or vibrate mode. Kept for use by legacy database upgrade code in
     // DatabaseHelper.
-    optional SettingProto vibrate_in_silent = 26;
-    optional SettingProto append_for_last_audible = 27;
+    optional SettingProto vibrate_in_silent = 26 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    // Appended to various volume related settings to record the previous values
+    // before the settings were affected by a silent/vibrate ringer mode change.
+    optional SettingProto append_for_last_audible = 27 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto ringtone = 28;
     optional SettingProto ringtone_cache = 29;
     optional SettingProto notification_sound = 30;
@@ -650,44 +721,47 @@
     optional SettingProto alarm_alert = 32;
     optional SettingProto alarm_alert_cache = 33;
     optional SettingProto media_button_receiver = 34;
-    optional SettingProto text_auto_replace = 35;
-    optional SettingProto text_auto_caps = 36;
-    optional SettingProto text_auto_punctuate = 37;
-    optional SettingProto text_show_password = 38;
-    optional SettingProto show_gtalk_service_status = 39;
-    optional SettingProto time_12_24 = 40;
-    optional SettingProto date_format = 41;
-    optional SettingProto setup_wizard_has_run = 42;
-    optional SettingProto accelerometer_rotation = 43;
-    optional SettingProto user_rotation = 44;
-    optional SettingProto hide_rotation_lock_toggle_for_accessibility = 45;
-    optional SettingProto vibrate_when_ringing = 46;
-    optional SettingProto dtmf_tone_when_dialing = 47;
-    optional SettingProto dtmf_tone_type_when_dialing = 48;
-    optional SettingProto hearing_aid = 49;
-    optional SettingProto tty_mode = 50;
-    optional SettingProto sound_effects_enabled = 51;
-    optional SettingProto haptic_feedback_enabled = 52;
-    optional SettingProto notification_light_pulse = 53;
-    optional SettingProto pointer_location = 54;
-    optional SettingProto show_touches = 55;
+    optional SettingProto text_auto_replace = 35 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto text_auto_caps = 36 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto text_auto_punctuate = 37 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto text_show_password = 38 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto show_gtalk_service_status = 39 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto time_12_24 = 40 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto date_format = 41 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto setup_wizard_has_run = 42 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto accelerometer_rotation = 43 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto user_rotation = 44 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto hide_rotation_lock_toggle_for_accessibility = 45 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto vibrate_when_ringing = 46 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto dtmf_tone_when_dialing = 47 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto dtmf_tone_type_when_dialing = 48 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto hearing_aid = 49 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto tty_mode = 50 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto sound_effects_enabled = 51 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto haptic_feedback_enabled = 52 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto notification_light_pulse = 53 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    // Show pointer location on screen? 0 = no, 1 = yes.
+    optional SettingProto pointer_location = 54 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto show_touches = 55 [ (android.privacy).dest = DEST_AUTOMATIC ];
     // Log raw orientation data from {@link
     // com.android.server.policy.WindowOrientationListener} for use with the
     // orientationplot.py tool.
     // 0 = no, 1 = yes
-    optional SettingProto window_orientation_listener_log = 56;
-    optional SettingProto lockscreen_sounds_enabled = 57;
-    optional SettingProto lockscreen_disabled = 58;
-    optional SettingProto sip_receive_calls = 59;
-    optional SettingProto sip_call_options = 60;
-    optional SettingProto sip_always = 61;
-    optional SettingProto sip_address_only = 62;
-    optional SettingProto pointer_speed = 63;
-    optional SettingProto lock_to_app_enabled = 64;
-    optional SettingProto egg_mode = 65;
-    optional SettingProto show_battery_percent = 69;
-    optional SettingProto when_to_make_wifi_calls = 66;
+    optional SettingProto window_orientation_listener_log = 56 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto lockscreen_sounds_enabled = 57 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto lockscreen_disabled = 58 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto sip_receive_calls = 59 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto sip_call_options = 60 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto sip_always = 61 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto sip_address_only = 62 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto pointer_speed = 63 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto lock_to_app_enabled = 64 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto egg_mode = 65 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto show_battery_percent = 69 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto when_to_make_wifi_calls = 66 [ (android.privacy).dest = DEST_AUTOMATIC ];
 
+    // Please insert fields in the same order as in
+    // frameworks/base/core/java/android/provider/Settings.java.
     // Next tag = 70;
 }
 
diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto
index 39c5ec7..788d901 100644
--- a/core/proto/android/server/activitymanagerservice.proto
+++ b/core/proto/android/server/activitymanagerservice.proto
@@ -19,6 +19,7 @@
 package com.android.server.am.proto;
 
 import "frameworks/base/core/proto/android/app/activitymanager.proto";
+import "frameworks/base/core/proto/android/app/enums.proto";
 import "frameworks/base/core/proto/android/app/notification.proto";
 import "frameworks/base/core/proto/android/app/profilerinfo.proto";
 import "frameworks/base/core/proto/android/content/component_name.proto";
@@ -129,6 +130,8 @@
   repeated StickyBroadcastProto sticky_broadcasts = 4;
 
   message MainHandler {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional string handler = 1;
     optional .android.os.LooperProto looper = 2;
   }
@@ -662,7 +665,7 @@
     option (.android.msg_privacy).dest = DEST_AUTOMATIC;
 
     optional .android.os.PowerManagerInternalProto.Wakefulness wakefulness = 1;
-    repeated string sleep_tokens = 2;
+    repeated string sleep_tokens = 2 [ (.android.privacy).dest = DEST_EXPLICIT ];
     optional bool sleeping = 3;
     optional bool shutting_down = 4;
     optional bool test_pss_mode = 5;
@@ -670,7 +673,7 @@
   optional SleepStatus sleep_status = 27;
 
   message VoiceProto {
-    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+    option (.android.msg_privacy).dest = DEST_EXPLICIT;
 
     optional string session = 1;
     optional .android.os.PowerManagerProto.WakeLockProto wakelock = 2;
@@ -724,7 +727,7 @@
       option (.android.msg_privacy).dest = DEST_AUTOMATIC;
 
       optional string proc_name = 1;
-      optional string file = 2  [ (.android.privacy).dest = DEST_EXPLICIT ];
+      optional string file = 2 [ (.android.privacy).dest = DEST_EXPLICIT ];
       optional int32 pid = 3;
       optional int32 uid = 4;
     }
@@ -797,7 +800,7 @@
 
   optional string hex_hash = 1;
   optional int32 uid = 2;
-  optional .android.app.ProcessState current = 3;
+  optional .android.app.ProcessStateEnum current = 3;
   optional bool ephemeral = 4;
   optional bool fg_services = 5;
   optional bool whilelist = 6;
@@ -855,7 +858,7 @@
     bool services = 6;
   }
 
-  optional .android.app.ProcessState state = 7;
+  optional .android.app.ProcessStateEnum state = 7;
   optional int32 trim_memory_level = 8;
   optional ProcessRecordProto proc = 9;
   optional string adj_type = 10;
@@ -878,8 +881,8 @@
     optional int32 set_raw_adj = 3;
     optional int32 cur_adj = 4;
     optional int32 set_adj = 5;
-    optional .android.app.ProcessState current_state = 7;
-    optional .android.app.ProcessState set_state = 8;
+    optional .android.app.ProcessStateEnum current_state = 7;
+    optional .android.app.ProcessStateEnum set_state = 8;
     optional string last_pss = 9;
     optional string last_swap_pss = 10;
     optional string last_cached_pss = 11;
@@ -997,6 +1000,8 @@
   optional int64 total_duration_ms = 2;
 
   message PackageTime {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional string package = 1;
     optional int64 duration_ms = 2;
   }
diff --git a/core/proto/android/server/alarmmanagerservice.proto b/core/proto/android/server/alarmmanagerservice.proto
index 53b4be4..aa2663f 100644
--- a/core/proto/android/server/alarmmanagerservice.proto
+++ b/core/proto/android/server/alarmmanagerservice.proto
@@ -21,12 +21,15 @@
 import "frameworks/base/core/proto/android/internal/locallog.proto";
 import "frameworks/base/core/proto/android/os/worksource.proto";
 import "frameworks/base/core/proto/android/server/forceappstandbytracker.proto";
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
 
 package com.android.server;
 
 option java_multiple_files = true;
 
 message AlarmManagerServiceProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional int64 current_time = 1;
   optional int64 elapsed_realtime = 2;
   optional int64 last_time_change_clock_time = 3;
@@ -106,6 +109,8 @@
   optional int64 allow_while_idle_min_duration_ms = 35;
 
   message LastAllowWhileIdleDispatch {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional int32 uid = 1;
     // In the 'elapsed' timebase.
     optional int64 time_ms = 2;
@@ -117,6 +122,8 @@
   optional com.android.internal.util.LocalLogProto recent_problems = 37;
 
   message TopAlarm {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional int32 uid = 1;
     optional string package_name = 2;
     optional FilterStatsProto filter = 3;
@@ -124,6 +131,8 @@
   repeated TopAlarm top_alarms = 38;
 
   message AlarmStat {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional BroadcastStatsProto broadcast = 1;
     repeated FilterStatsProto filters = 2;
   }
@@ -136,6 +145,8 @@
 // This is a soft wrapper for alarm clock information. It is not representative
 // of an android.app.AlarmManager.AlarmClockInfo object.
 message AlarmClockMetadataProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional int32 user = 1;
   optional bool is_pending_send = 2;
   // This value is UTC wall clock time in milliseconds, as returned by
@@ -145,7 +156,9 @@
 
 // A com.android.server.AlarmManagerService.Alarm object.
 message AlarmProto {
-  optional string tag = 1;
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+  optional string tag = 1 [ (.android.privacy).dest = DEST_EXPLICIT ];
   optional .android.app.AlarmManagerProto.AlarmType type = 2;
   // How long until the alarm goes off, in the 'elapsed' timebase. Can be
   // negative if 'when' is in the past.
@@ -156,11 +169,13 @@
   optional int32 flags = 7;
   optional .android.app.AlarmClockInfoProto alarm_clock = 8;
   optional .android.app.PendingIntentProto operation = 9;
-  optional string listener = 10;
+  optional string listener = 10 [ (.android.privacy).dest = DEST_EXPLICIT ];
 }
 
 // A com.android.server.AlarmManagerService.Batch object.
 message BatchProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   // Start time in terms of elapsed realtime.
   optional int64 start_realtime = 1;
   // End time in terms of elapsed realtime.
@@ -171,6 +186,8 @@
 
 // A com.android.server.AlarmManagerService.BroadcastStats object.
 message BroadcastStatsProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional int32 uid = 1;
   optional string package_name = 2;
   // The total amount of time this broadcast was in flight.
@@ -186,6 +203,8 @@
 
 // A com.android.server.AlarmManagerService.Constants object.
 message ConstantsProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   // Minimum futurity of a new alarm.
   optional int64 min_futurity_duration_ms = 1;
   // Minimum alarm recurrence interval.
@@ -202,7 +221,9 @@
 
 // A com.android.server.AlarmManagerService.FilterStats object.
 message FilterStatsProto {
-  optional string tag = 1;
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+  optional string tag = 1 [ (.android.privacy).dest = DEST_EXPLICIT ];
   // The last time this filter when in flight, in terms of elapsed realtime.
   optional int64 last_flight_time_realtime = 2;
   // The total amount of time this filter was in flight.
@@ -218,9 +239,11 @@
 
 // A com.android.server.AlarmManagerService.IdleDispatchEntry object.
 message IdleDispatchEntryProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional int32 uid = 1;
   optional string pkg = 2;
-  optional string tag = 3;
+  optional string tag = 3 [ (.android.privacy).dest = DEST_EXPLICIT ];
   optional string op = 4;
   // Time when this entry was created, in terms of elapsed realtime.
   optional int64 entry_creation_realtime = 5;
@@ -232,8 +255,10 @@
 
 // A com.android.server.AlarmManagerService.InFlight object.
 message InFlightProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional int32 uid = 1;
-  optional string tag = 2;
+  optional string tag = 2 [ (.android.privacy).dest = DEST_EXPLICIT ];
   optional int64 when_elapsed_ms = 3;
   optional .android.app.AlarmManagerProto.AlarmType alarm_type = 4;
   optional .android.app.PendingIntentProto pending_intent = 5;
@@ -244,6 +269,8 @@
 
 // A com.android.server.AlarmManagerService.WakeupEvent object.
 message WakeupEventProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   optional int32 uid = 1;
   optional string action = 2;
   optional int64 when = 3;
diff --git a/core/proto/android/server/forceappstandbytracker.proto b/core/proto/android/server/forceappstandbytracker.proto
index 8cdfdf1..d0fd0b4 100644
--- a/core/proto/android/server/forceappstandbytracker.proto
+++ b/core/proto/android/server/forceappstandbytracker.proto
@@ -22,8 +22,12 @@
 
 option java_multiple_files = true;
 
-// Dump from ForceAppStandbyTracker.
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
+
+// Dump from com.android.server.ForceAppStandbyTracker.
 message ForceAppStandbyTrackerProto {
+  option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
   // Whether all apps are forced standby or not.
   optional bool force_all_apps_standby = 1;
 
@@ -37,10 +41,11 @@
   repeated int32 temp_power_save_whitelist_app_ids = 4;
 
   message RunAnyInBackgroundRestrictedPackages {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional int32 uid = 1;
     optional string package_name = 2;
   }
-
   // Packages that are disallowed OP_RUN_ANY_IN_BACKGROUND.
   repeated RunAnyInBackgroundRestrictedPackages run_any_in_background_restricted_packages = 5;
 
diff --git a/core/proto/android/server/jobscheduler.proto b/core/proto/android/server/jobscheduler.proto
index 739fca3..304e63f 100644
--- a/core/proto/android/server/jobscheduler.proto
+++ b/core/proto/android/server/jobscheduler.proto
@@ -29,13 +29,18 @@
 import "frameworks/base/core/proto/android/os/bundle.proto";
 import "frameworks/base/core/proto/android/os/persistablebundle.proto";
 import "frameworks/base/core/proto/android/server/forceappstandbytracker.proto";
+import "frameworks/base/libs/incident/proto/android/privacy.proto";
 
 message JobSchedulerServiceDumpProto {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional ConstantsProto settings = 1;
 
     repeated int32 started_users = 2;
 
     message RegisteredJob {
+        option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
         optional JobStatusShortInfoProto info = 1;
         optional JobStatusDumpProto dump = 2;
 
@@ -56,6 +61,8 @@
 
     // Which uids are currently in the foreground.
     message PriorityOverride {
+        option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
         optional int32 uid = 1;
         // Use sint32 instead of an enum since priorities can technically be
         // negative.
@@ -71,6 +78,8 @@
     optional JobPackageTrackerDumpProto package_tracker = 8;
 
     message PendingJob {
+        option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
         optional JobStatusShortInfoProto info = 1;
         optional JobStatusDumpProto dump = 2;
         optional sint32 evaluated_priority = 3;
@@ -81,12 +90,18 @@
 
     // From a service that has currently active or pending jobs.
     message ActiveJob {
+        option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
         message InactiveJob {
+            option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
             optional int64 time_since_stopped_ms = 1;
             // This is not always provided.
             optional string stopped_reason = 2;
         }
         message RunningJob {
+            option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
             optional JobStatusShortInfoProto info = 1;
             // How long this job has been running for.
             optional int64 running_duration_ms = 2;
@@ -119,6 +134,8 @@
 
 // A com.android.server.job.JobSchedulerService.Constants object.
 message ConstantsProto {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     // Minimum # of idle jobs that must be ready in order to force the JMS to
     // schedule things early.
     optional int32 min_idle_count = 1;
@@ -187,10 +204,16 @@
 }
 
 message StateControllerProto {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     message AppIdleController {
+        option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
         optional bool is_parole_on = 1;
 
         message TrackedJob {
+            option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
             optional JobStatusShortInfoProto info = 1;
             optional int32 source_uid = 2;
             optional string source_package_name = 3;
@@ -201,9 +224,13 @@
         repeated TrackedJob tracked_jobs = 2;
     }
     message BackgroundJobsController {
+        option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
         optional com.android.server.ForceAppStandbyTrackerProto force_app_standby_tracker = 1;
 
         message TrackedJob {
+            option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
             optional JobStatusShortInfoProto info = 1;
             optional int32 source_uid = 2;
             optional string source_package_name = 3;
@@ -217,6 +244,8 @@
         repeated TrackedJob tracked_jobs = 2;
     }
     message BatteryController {
+        option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
         optional bool is_on_stable_power = 1;
         optional bool is_battery_not_low = 2;
 
@@ -226,15 +255,21 @@
         optional int32 last_broadcast_sequence_number = 4;
 
         message TrackedJob {
+            option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
             optional JobStatusShortInfoProto info = 1;
             optional int32 source_uid = 2;
         }
         repeated TrackedJob tracked_jobs = 5;
     }
     message ConnectivityController {
+        option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
         optional bool is_connected = 1;
 
         message TrackedJob {
+            option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
             optional JobStatusShortInfoProto info = 1;
             optional int32 source_uid = 2;
             optional .android.net.NetworkRequestProto required_network = 3;
@@ -242,31 +277,47 @@
         repeated TrackedJob tracked_jobs = 2;
     }
     message ContentObserverController {
+        option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
         message TrackedJob {
+            option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
             optional JobStatusShortInfoProto info = 1;
             optional int32 source_uid = 2;
         }
         repeated TrackedJob tracked_jobs = 1;
 
         message Observer {
+            option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
             optional int32 user_id = 1;
 
             message TriggerContentData {
-                optional string uri = 1;
+                option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+                optional string uri = 1 [
+                    (.android.privacy).dest = DEST_EXPLICIT
+                ];
                 optional int32 flags = 2;
 
                 // A
                 // com.android.server.job.controllers.ContentObserverController.JobInstance
                 // object.
                 message JobInstance {
+                    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
                     optional JobStatusShortInfoProto info = 1;
                     optional int32 source_uid = 2;
 
                     optional int64 trigger_content_update_delay_ms = 3;
                     optional int64 trigger_content_max_delay_ms = 4;
 
-                    repeated string changed_authorities = 5;
-                    repeated string changed_uris = 6;
+                    repeated string changed_authorities = 5 [
+                        (.android.privacy).dest = DEST_EXPLICIT
+                    ];
+                    repeated string changed_uris = 6 [
+                        (.android.privacy).dest = DEST_EXPLICIT
+                    ];
                 }
                 repeated JobInstance jobs = 3;
             }
@@ -275,10 +326,14 @@
         repeated Observer observers = 2;
     }
     message DeviceIdleJobsController {
+        option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
         // True when in device idle mode.
         optional bool is_device_idle_mode = 1;
 
         message TrackedJob {
+            option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
             optional JobStatusShortInfoProto info = 1;
             optional int32 source_uid = 2;
             optional string source_package_name = 3;
@@ -293,30 +348,42 @@
         repeated TrackedJob tracked_jobs = 2;
     }
     message IdleController {
+        option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
         optional bool is_idle = 1;
 
         message TrackedJob {
+            option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
             optional JobStatusShortInfoProto info = 1;
             optional int32 source_uid = 2;
         }
         repeated TrackedJob tracked_jobs = 2;
     }
     message StorageController {
+        option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
         optional bool is_storage_not_low = 1;
         optional int32 last_broadcast_sequence_number = 2;
 
         message TrackedJob {
+            option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
             optional JobStatusShortInfoProto info = 1;
             optional int32 source_uid = 2;
         }
         repeated TrackedJob tracked_jobs = 3;
     }
     message TimeController {
+        option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
         optional int64 now_elapsed_realtime = 1;
         optional int64 time_until_next_delay_alarm_ms = 2;
         optional int64 time_until_next_deadline_alarm_ms = 3;
 
         message TrackedJob {
+            option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
             optional JobStatusShortInfoProto info = 1;
             optional int32 source_uid = 2;
 
@@ -347,6 +414,8 @@
 
 // A com.android.server.job.JobPackageTracker.DataSet object.
 message DataSetProto {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional int64 start_clock_time_ms = 1;
     // How much time has elapsed since the DataSet was instantiated.
     optional int64 elapsed_time_ms = 2;
@@ -355,10 +424,14 @@
     // Represents a com.android.server.job.JobPackageTracker.PackageEntry
     // object, but with some extra data.
     message PackageEntryProto {
+        option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
         optional int32 uid = 1;
         optional string package_name = 2;
 
         message State {
+            option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
             optional int64 duration_ms = 1;
             optional int32 count = 2;
         }
@@ -377,6 +450,8 @@
         optional bool active_top = 8;
 
         message StopReasonCount {
+            option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
             optional .android.app.JobParametersProto.CancelReason reason = 1;
             optional int32 count = 2;
         }
@@ -390,19 +465,27 @@
 
 // Dump from com.android.server.job.GrantedUriPermissions.
 message GrantedUriPermissionsDumpProto {
-    optional int32 flags = 1;
-    optional int32 source_user_id = 2;
+    option (.android.msg_privacy).dest = DEST_EXPLICIT;
+
+    optional int32 flags = 1 [ (.android.privacy).dest = DEST_AUTOMATIC ];
+    optional int32 source_user_id = 2 [
+        (.android.privacy).dest = DEST_AUTOMATIC
+    ];
     optional string tag = 3;
     optional string permission_owner = 4;
     repeated string uris = 5;
 }
 
 message JobPackageTrackerDumpProto {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     repeated DataSetProto historical_stats = 1;
     optional DataSetProto current_stats = 2;
 }
 
 message JobPackageHistoryProto {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     enum Event {
         UNKNOWN = 0;
         START_JOB = 1;
@@ -411,12 +494,14 @@
         STOP_PERIODIC_JOB = 4;
     }
     message HistoryEvent {
+        option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
         optional Event event = 1;
         optional int64 time_since_event_ms = 2;
         optional int32 uid = 3;
         // Job IDs can technically be negative.
         optional int32 job_id = 4;
-        optional string tag = 5;
+        optional string tag = 5 [ (.android.privacy).dest = DEST_EXPLICIT ];
         // Only valid for STOP_JOB or STOP_PERIODIC_JOB Events.
         optional .android.app.JobParametersProto.CancelReason stop_reason = 6;
     }
@@ -424,17 +509,23 @@
 }
 
 message JobStatusShortInfoProto {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     optional int32 calling_uid = 1;
     // Job IDs can technically be negative.
     optional int32 job_id = 2;
-    optional string battery_name = 3;
+    optional string battery_name = 3 [
+        (.android.privacy).dest = DEST_EXPLICIT
+    ];
 }
 
 // Dump from a com.android.server.job.controllers.JobStatus object.
 message JobStatusDumpProto {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
     // The UID that scheduled the job.
     optional int32 calling_uid = 1;
-    optional string tag = 2;
+    optional string tag = 2 [ (.android.privacy).dest = DEST_EXPLICIT ];
 
     // The UID for which the job is being run.
     optional int32 source_uid = 3;
@@ -444,6 +535,8 @@
 
     // Custom dump of android.app.job.JobInfo object.
     message JobInfo {
+        option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
         optional .android.content.ComponentNameProto service = 1;
 
         optional bool is_periodic = 2;
@@ -461,8 +554,10 @@
         optional bool requires_device_idle = 10;
 
         message TriggerContentUri {
-            optional int32 flags = 1;
-            optional string uri = 2;
+            optional int32 flags = 1 [
+                (.android.privacy).dest = DEST_AUTOMATIC
+            ];
+            optional string uri = 2 [ (.android.privacy).dest = DEST_EXPLICIT ];
         }
         repeated TriggerContentUri trigger_content_uris = 11;
         optional int64 trigger_content_update_delay_ms = 12;
@@ -482,6 +577,8 @@
         optional int64 max_execution_delay_ms = 21;
 
         message Backoff {
+            option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
             enum Policy {
                 BACKOFF_POLICY_LINEAR = 0;
                 BACKOFF_POLICY_EXPONENTIAL = 1;
@@ -524,13 +621,19 @@
     // Controllers that are currently tracking the job.
     repeated TrackingController tracking_controllers = 11;
 
-    repeated string changed_authorities = 12;
-    repeated string changed_uris = 13;
+    repeated string changed_authorities = 12 [
+        (.android.privacy).dest = DEST_EXPLICIT
+    ];
+    repeated string changed_uris = 13 [
+        (.android.privacy).dest = DEST_EXPLICIT
+    ];
 
     optional .android.net.NetworkProto network = 14;
 
     // Only the desired data from an android.app.job.JobWorkItem object.
     message JobWorkItem {
+        option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
         optional int32 work_id = 1;
         optional int32 delivery_count = 2;
         optional .android.content.IntentProto intent = 3;
diff --git a/core/proto/android/server/powermanagerservice.proto b/core/proto/android/server/powermanagerservice.proto
index f3ebd41..b5c3ac0 100644
--- a/core/proto/android/server/powermanagerservice.proto
+++ b/core/proto/android/server/powermanagerservice.proto
@@ -19,15 +19,15 @@
 
 option java_multiple_files = true;
 
-import "frameworks/base/core/proto/android/app/activitymanager.proto";
+import "frameworks/base/core/proto/android/app/enums.proto";
 import "frameworks/base/core/proto/android/content/intent.proto";
-import "frameworks/base/core/proto/android/os/batterymanager.proto";
+import "frameworks/base/core/proto/android/os/enums.proto";
 import "frameworks/base/core/proto/android/os/looper.proto";
 import "frameworks/base/core/proto/android/os/powermanager.proto";
 import "frameworks/base/core/proto/android/os/worksource.proto";
 import "frameworks/base/core/proto/android/providers/settings.proto";
 import "frameworks/base/core/proto/android/server/wirelesschargerdetector.proto";
-import "frameworks/base/core/proto/android/view/display.proto";
+import "frameworks/base/core/proto/android/view/enums.proto";
 import "frameworks/base/libs/incident/proto/android/privacy.proto";
 
 message PowerManagerServiceDumpProto {
@@ -67,8 +67,7 @@
         optional string uid_string = 2;
         optional bool is_active = 3;
         optional int32 num_wake_locks = 4;
-        optional bool is_process_state_unknown = 5;
-        optional .android.app.ProcessState process_state = 6;
+        optional .android.app.ProcessStateEnum process_state = 5;
     }
 
     optional ConstantsProto constants = 1;
@@ -81,7 +80,7 @@
     // True if the device is plugged into a power source.
     optional bool is_powered = 5;
     // The current plug type
-    optional .android.os.BatteryManagerProto.PlugType plug_type = 6;
+    optional .android.os.BatteryPluggedStateEnum plug_type = 6;
     // The current battery level percentage.
     optional int32 battery_level = 7;
     // The battery level percentage at the time the dream started.
@@ -198,7 +197,7 @@
         optional bool is_on_after_release = 2;
     }
 
-    optional .android.os.PowerManagerProto.WakeLockLevel lock_level = 1;
+    optional .android.os.WakeLockLevelEnum lock_level = 1;
     optional string tag = 2 [ (.android.privacy).dest = DEST_EXPLICIT ];
     optional WakeLockFlagsProto flags = 3;
     optional bool is_disabled = 4;
@@ -323,7 +322,7 @@
     // Use NaN to disable.
     optional float temporary_screen_auto_brightness_adjustment_setting_override = 37;
     // The screen state to use while dozing.
-    optional .android.view.DisplayProto.DisplayState doze_screen_state_override_from_dream_manager = 38;
+    optional .android.view.DisplayStateEnum doze_screen_state_override_from_dream_manager = 38;
     // The screen brightness to use while dozing.
     optional float dozed_screen_brightness_override_from_dream_manager = 39;
     // Screen brightness settings limits.
diff --git a/core/proto/android/service/battery.proto b/core/proto/android/service/battery.proto
index 42fa72c..34cb229 100644
--- a/core/proto/android/service/battery.proto
+++ b/core/proto/android/service/battery.proto
@@ -20,35 +20,16 @@
 option java_multiple_files = true;
 option java_outer_classname = "BatteryServiceProto";
 
-import "frameworks/base/core/proto/android/os/batterymanager.proto";
+import "frameworks/base/core/proto/android/os/enums.proto";
 import "frameworks/base/libs/incident/proto/android/privacy.proto";
 
 message BatteryServiceDumpProto {
     option (android.msg_privacy).dest = DEST_AUTOMATIC;
 
-    enum BatteryStatus {
-        BATTERY_STATUS_INVALID = 0;
-        BATTERY_STATUS_UNKNOWN = 1;
-        BATTERY_STATUS_CHARGING = 2;
-        BATTERY_STATUS_DISCHARGING = 3;
-        BATTERY_STATUS_NOT_CHARGING = 4;
-        BATTERY_STATUS_FULL = 5;
-    }
-    enum BatteryHealth {
-        BATTERY_HEALTH_INVALID = 0;
-        BATTERY_HEALTH_UNKNOWN = 1;
-        BATTERY_HEALTH_GOOD = 2;
-        BATTERY_HEALTH_OVERHEAT = 3;
-        BATTERY_HEALTH_DEAD = 4;
-        BATTERY_HEALTH_OVER_VOLTAGE = 5;
-        BATTERY_HEALTH_UNSPECIFIED_FAILURE = 6;
-        BATTERY_HEALTH_COLD = 7;
-    }
-
     // If true: UPDATES STOPPED -- use 'reset' to restart
     optional bool are_updates_stopped = 1;
     // Plugged status of power sources
-    optional android.os.BatteryManagerProto.PlugType plugged = 2;
+    optional android.os.BatteryPluggedStateEnum plugged = 2;
     // Max current in microamperes. This may be 0 if the device's kernel drivers
     // don't support it.
     optional int32 max_charging_current = 3;
@@ -58,9 +39,9 @@
     // Battery capacity in microampere-hours
     optional int32 charge_counter = 5;
     // Charging status
-    optional BatteryStatus status = 6;
+    optional android.os.BatteryStatusEnum status = 6;
     // Battery health
-    optional BatteryHealth health = 7;
+    optional android.os.BatteryHealthEnum health = 7;
     // True if the battery is present
     optional bool is_present = 8;
     // Charge level, from 0 through "scale" inclusive
diff --git a/core/proto/android/telephony/enums.proto b/core/proto/android/telephony/enums.proto
new file mode 100644
index 0000000..60f8d8d
--- /dev/null
+++ b/core/proto/android/telephony/enums.proto
@@ -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.
+ */
+
+syntax = "proto2";
+package android.telephony;
+
+option java_outer_classname = "TelephonyProtoEnums";
+option java_multiple_files = true;
+
+// Data conn. power states, primarily used by android/telephony/DataConnectionRealTimeInfo.java.
+enum DataConnectionPowerStateEnum {
+    DATA_CONNECTION_POWER_STATE_LOW = 1;
+    DATA_CONNECTION_POWER_STATE_MEDIUM = 2;
+    DATA_CONNECTION_POWER_STATE_HIGH = 3;
+    DATA_CONNECTION_POWER_STATE_UNKNOWN = 2147483647; // Java Integer.MAX_VALUE;
+}
+
+// Signal strength levels, primarily used by android/telephony/SignalStrength.java.
+enum SignalStrengthEnum {
+    SIGNAL_STRENGTH_NONE_OR_UNKNOWN = 0;
+    SIGNAL_STRENGTH_POOR = 1;
+    SIGNAL_STRENGTH_MODERATE = 2;
+    SIGNAL_STRENGTH_GOOD = 3;
+    SIGNAL_STRENGTH_GREAT = 4;
+}
diff --git a/core/proto/android/telephony/signalstrength.proto b/core/proto/android/telephony/signalstrength.proto
deleted file mode 100644
index 366f1d1..0000000
--- a/core/proto/android/telephony/signalstrength.proto
+++ /dev/null
@@ -1,34 +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.
- */
-
-syntax = "proto2";
-option java_package = "android.telephony";
-option java_multiple_files = true;
-
-package android.telephony;
-
-/**
- * An android.telephony.SignalStrength object.
- */
-message SignalStrengthProto {
-  enum StrengthName {
-    SIGNAL_STRENGTH_NONE_OR_UNKNOWN = 0;
-    SIGNAL_STRENGTH_POOR = 1;
-    SIGNAL_STRENGTH_MODERATE = 2;
-    SIGNAL_STRENGTH_GOOD = 3;
-    SIGNAL_STRENGTH_GREAT = 4;
-  }
-}
diff --git a/core/proto/android/view/display.proto b/core/proto/android/view/display.proto
index cac0830..30046c3 100644
--- a/core/proto/android/view/display.proto
+++ b/core/proto/android/view/display.proto
@@ -20,24 +20,6 @@
 option java_multiple_files = true;
 
 message DisplayProto {
-    enum DisplayState {
-        // The display state is unknown.
-        DISPLAY_STATE_UNKNOWN = 0;
-        // The display state is off.
-        DISPLAY_STATE_OFF = 1;
-        // The display state is on.
-        DISPLAY_STATE_ON = 2;
-        // The display is dozing in a low power state; it is still on but is
-        // optimized for showing system-provided content while the device is
-        // non-interactive.
-        DISPLAY_STATE_DOZE = 3;
-        // The display is dozing in a suspended low power state; it is still on
-        // but is optimized for showing static system-provided content while the
-        // device is non-interactive.
-        DISPLAY_STATE_DOZE_SUSPEND = 4;
-        // The display is on and optimized for VR mode.
-        DISPLAY_STATE_VR = 5;
-    }
     enum ColorMode {
         COLOR_MODE_INVALID = -1;
         COLOR_MODE_BT601_625 = 1;
diff --git a/core/proto/android/view/enums.proto b/core/proto/android/view/enums.proto
new file mode 100644
index 0000000..10785ce
--- /dev/null
+++ b/core/proto/android/view/enums.proto
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+package android.view;
+
+option java_outer_classname = "ViewProtoEnums";
+option java_multiple_files = true;
+
+// Screen states, primarily used by android/view/Display.java.
+enum DisplayStateEnum {
+    // The display state is unknown.
+    DISPLAY_STATE_UNKNOWN = 0;
+    // The display state is off.
+    DISPLAY_STATE_OFF = 1;
+    // The display state is on.
+    DISPLAY_STATE_ON = 2;
+    // The display is dozing in a low power state; it is still on but is
+    // optimized for showing system-provided content while the device is
+    // non-interactive.
+    DISPLAY_STATE_DOZE = 3;
+    // The display is dozing in a suspended low power state; it is still on
+    // but is optimized for showing static system-provided content while the
+    // device is non-interactive.
+    DISPLAY_STATE_DOZE_SUSPEND = 4;
+    // The display is on and optimized for VR mode.
+    DISPLAY_STATE_VR = 5;
+    // The display is in a suspended full power state; it is still on but the
+    // CPU is not updating it.
+    DISPLAY_STATE_ON_SUSPEND = 6;
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 0861e710..b23a64b 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -580,6 +580,7 @@
     <protected-broadcast android:name="android.app.action.TRANSFER_OWNERSHIP_COMPLETE" />
     <protected-broadcast android:name="android.app.action.AFFILIATED_PROFILE_TRANSFER_OWNERSHIP_COMPLETE" />
     <protected-broadcast android:name="android.app.action.DATA_SHARING_RESTRICTION_CHANGED" />
+    <protected-broadcast android:name="android.app.action.STATSD_STARTED" />
 
     <!-- ====================================================================== -->
     <!--                          RUNTIME PERMISSIONS                           -->
@@ -3740,15 +3741,6 @@
     <permission android:name="android.permission.INSTANT_APP_FOREGROUND_SERVICE"
         android:protectionLevel="signature|development|instant|appop" />
 
-    <!-- Allows a regular application to use {@link android.app.Service#startForeground
-         Service.startForeground}.
-         <p>Protection level: normal
-    -->
-    <permission android:name="android.permission.FOREGROUND_SERVICE"
-        android:description="@string/permdesc_foregroundService"
-        android:label="@string/permlab_foregroundService"
-        android:protectionLevel="normal|instant" />
-
     <!-- @hide Allows system components to access all app shortcuts. -->
     <permission android:name="android.permission.ACCESS_SHORTCUTS"
         android:protectionLevel="signature" />
diff --git a/core/res/res/anim/cross_profile_apps_thumbnail_enter.xml b/core/res/res/anim/cross_profile_apps_thumbnail_enter.xml
index 3254ebb..6f3dc8c 100644
--- a/core/res/res/anim/cross_profile_apps_thumbnail_enter.xml
+++ b/core/res/res/anim/cross_profile_apps_thumbnail_enter.xml
@@ -20,19 +20,54 @@
 <set xmlns:android="http://schemas.android.com/apk/res/android"
      android:shareInterpolator="false" android:zAdjustment="top">
 
-    <alpha android:fromAlpha="0" android:toAlpha="1.0"
-           android:startOffset="300"
-           android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-           android:interpolator="@interpolator/decelerate_quart"
-           android:duration="167"/>
+    <alpha
+        android:fromAlpha="1"
+        android:toAlpha="1.0"
+        android:fillEnabled="true"
+        android:fillBefore="true"
+        android:fillAfter="true"
+        android:interpolator="@interpolator/linear"
+        android:startOffset="67"
+        android:duration="217"/>
 
-    <translate android:fromYDelta="110%" android:toYDelta="0"
-               android:startOffset="300"
-               android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
-               android:interpolator="@interpolator/decelerate_quint"
-               android:duration="417"/>
+    <translate
+        android:fromXDelta="-105%"
+        android:toXDelta="0"
+        android:fillEnabled="true"
+        android:fillBefore="true"
+        android:fillAfter="true"
+        android:interpolator="@interpolator/aggressive_ease"
+        android:startOffset="50"
+        android:duration="383"/>
 
-    <!-- To keep the thumbnail around longer -->
+    <scale
+        android:fromXScale="1.0526"
+        android:toXScale="1"
+        android:fromYScale="1.0526"
+        android:toYScale="1"
+        android:pivotX="50%"
+        android:pivotY="50%"
+        android:fillEnabled="true"
+        android:fillBefore="true"
+        android:fillAfter="true"
+        android:interpolator="@interpolator/fast_out_slow_in"
+        android:duration="283"/>
+
+    <scale
+        android:fromXScale="0.95"
+        android:toXScale="1"
+        android:fromYScale="0.95"
+        android:toYScale="1"
+        android:pivotX="50%"
+        android:pivotY="50%"
+        android:fillEnabled="true"
+        android:fillBefore="true"
+        android:fillAfter="true"
+        android:interpolator="@interpolator/fast_out_slow_in"
+        android:startOffset="283"
+        android:duration="317"/>
+
+    <!-- To keep the thumbnail around longer and fade out the thumbnail -->
     <alpha android:fromAlpha="1.0" android:toAlpha="0"
            android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
            android:interpolator="@interpolator/decelerate_quint"
diff --git a/core/res/res/anim/task_open_enter.xml b/core/res/res/anim/task_open_enter.xml
index 2ee7cd8..0e66eda 100644
--- a/core/res/res/anim/task_open_enter.xml
+++ b/core/res/res/anim/task_open_enter.xml
@@ -14,7 +14,9 @@
 ** See the License for the specific language governing permissions and
 ** limitations under the License.
 */
---><!-- This should in sync with task_open_enter_cross_profile_apps.xml -->
+-->
+<!-- This should in sync with task_open_enter_cross_profile_apps.xml -->
+<!-- This should in sync with cross_profile_apps_thumbnail_enter.xml -->
 <set xmlns:android="http://schemas.android.com/apk/res/android"
     android:shareInterpolator="false"
     android:zAdjustment="top">
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 354d658..5184dda 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -5878,6 +5878,13 @@
         <attr name="insetBottom" format="fraction|dimension" />
     </declare-styleable>
 
+    <!-- Drawable used to draw animated images (gif) -->
+    <declare-styleable name="AnimatedImageDrawable">
+        <!-- Identifier of the image file. This attribute is mandatory.
+             It must be an image file with multiple frames, e.g. gif or webp -->
+        <attr name="src" />
+    </declare-styleable>
+
     <!-- Drawable used to draw bitmaps. -->
     <declare-styleable name="BitmapDrawable">
         <!-- Identifier of the bitmap file. This attribute is mandatory. -->
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 69d96fc..549f9ad 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -916,11 +916,6 @@
     <string name="permdesc_persistentActivity" product="default">Allows the app to make parts of itself persistent in memory.  This can limit memory available to other apps slowing down the phone.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_foregroundService">run foreground service</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_foregroundService">Allows the app to make use of foreground services.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_getPackageSize">measure app storage space</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_getPackageSize">Allows the app to retrieve its code, data, and cache sizes</string>
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index 53c22f6..7d5c60a 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -51,7 +51,6 @@
     <uses-permission android:name="android.permission.CLEAR_APP_USER_DATA" />
     <uses-permission android:name="android.permission.DELETE_CACHE_FILES" />
     <uses-permission android:name="android.permission.DOWNLOAD_CACHE_NON_PURGEABLE" />
-    <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
     <uses-permission android:name="android.permission.GET_PACKAGE_SIZE" />
     <uses-permission android:name="android.permission.INTERNET" />
     <uses-permission android:name="android.permission.INJECT_EVENTS" />
diff --git a/docs/html/reference/images/text/style/clickablespan.png b/docs/html/reference/images/text/style/clickablespan.png
new file mode 100644
index 0000000..8e3e6bf
--- /dev/null
+++ b/docs/html/reference/images/text/style/clickablespan.png
Binary files differ
diff --git a/docs/html/reference/images/text/style/customquotespan.png b/docs/html/reference/images/text/style/customquotespan.png
new file mode 100644
index 0000000..27f521a
--- /dev/null
+++ b/docs/html/reference/images/text/style/customquotespan.png
Binary files differ
diff --git a/docs/html/reference/images/text/style/defaultquotespan.png b/docs/html/reference/images/text/style/defaultquotespan.png
new file mode 100644
index 0000000..6c5a41f
--- /dev/null
+++ b/docs/html/reference/images/text/style/defaultquotespan.png
Binary files differ
diff --git a/docs/html/reference/images/text/style/ltralignmentspan.png b/docs/html/reference/images/text/style/ltralignmentspan.png
new file mode 100644
index 0000000..6ee5943
--- /dev/null
+++ b/docs/html/reference/images/text/style/ltralignmentspan.png
Binary files differ
diff --git a/docs/html/reference/images/text/style/rtlalignmentspan.png b/docs/html/reference/images/text/style/rtlalignmentspan.png
new file mode 100644
index 0000000..952258d
--- /dev/null
+++ b/docs/html/reference/images/text/style/rtlalignmentspan.png
Binary files differ
diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java
index 3de050b..3ead591 100644
--- a/graphics/java/android/graphics/ImageDecoder.java
+++ b/graphics/java/android/graphics/ImageDecoder.java
@@ -339,6 +339,16 @@
         public String getMimeType() {
             return mDecoder.getMimeType();
         }
+
+        /**
+         * Whether the image is animated.
+         *
+         * <p>Calling {@link #decodeDrawable} will return an
+         * {@link AnimatedImageDrawable}.</p>
+         */
+        public boolean isAnimated() {
+            return mDecoder.mAnimated;
+        }
     };
 
     /**
@@ -454,6 +464,10 @@
                 mCloseGuard.warnIfOpen();
             }
 
+            // Avoid closing these in finalizer.
+            mInputStream = null;
+            mAssetFd = null;
+
             close();
         } finally {
             super.finalize();
diff --git a/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java b/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java
index 3034a10..0ec19f9 100644
--- a/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedImageDrawable.java
@@ -20,14 +20,26 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.res.AssetFileDescriptor;
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.view.InflateException;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
 import android.graphics.ImageDecoder;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
-import android.os.SystemClock;
+import android.os.Handler;
+import android.os.Looper;
 import android.util.DisplayMetrics;
+import android.util.TypedValue;
+
+import com.android.internal.R;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
 
 import libcore.io.IoUtils;
 import libcore.util.NativeAllocationRegistry;
@@ -35,17 +47,38 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.lang.Runnable;
+import java.util.ArrayList;
 
 /**
- * @hide
+ * {@link Drawable} for drawing animated images (like GIF).
+ *
+ * <p>Created by {@link ImageDecoder#decodeDrawable}. A user needs to call
+ * {@link #start} to start the animation.</p>
  */
-public class AnimatedImageDrawable extends Drawable implements Animatable {
-    private final long                mNativePtr;
-    private final InputStream         mInputStream;
-    private final AssetFileDescriptor mAssetFd;
+public class AnimatedImageDrawable extends Drawable implements Animatable2 {
+    private int mIntrinsicWidth;
+    private int mIntrinsicHeight;
 
-    private final int                 mIntrinsicWidth;
-    private final int                 mIntrinsicHeight;
+    private boolean mStarting;
+    private boolean mRunning;
+
+    private Handler mHandler;
+
+    private class State {
+        State(long nativePtr, InputStream is, AssetFileDescriptor afd) {
+            mNativePtr = nativePtr;
+            mInputStream = is;
+            mAssetFd = afd;
+        }
+
+        public  final long mNativePtr;
+
+        // These just keep references so the native code can continue using them.
+        private final InputStream mInputStream;
+        private final AssetFileDescriptor mAssetFd;
+    }
+
+    private State mState;
 
     private Runnable mRunnable = new Runnable() {
         @Override
@@ -55,6 +88,95 @@
     };
 
     /**
+     *  Pass this to {@link #setLoopCount} to loop infinitely.
+     *
+     *  <p>{@link Animatable2.AnimationCallback#onAnimationEnd} will never be
+     *  called unless there is an error.</p>
+     */
+    public static final int LOOP_INFINITE = -1;
+
+    /**
+     *  Specify the number of times to loop the animation.
+     *
+     *  <p>By default, the loop count in the encoded data is respected.</p>
+     */
+    public void setLoopCount(int loopCount) {
+        if (mState == null) {
+            throw new IllegalStateException("called setLoopCount on empty AnimatedImageDrawable");
+        }
+        nSetLoopCount(mState.mNativePtr, loopCount);
+    }
+
+    /**
+     * Create an empty AnimatedImageDrawable.
+     */
+    public AnimatedImageDrawable() {
+        mState = null;
+    }
+
+    @Override
+    public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
+            throws XmlPullParserException, IOException {
+        super.inflate(r, parser, attrs, theme);
+
+        final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.AnimatedImageDrawable);
+        updateStateFromTypedArray(a, mSrcDensityOverride);
+    }
+
+    private void updateStateFromTypedArray(TypedArray a, int srcDensityOverride)
+            throws XmlPullParserException {
+        final Resources r = a.getResources();
+        final int srcResId = a.getResourceId(R.styleable.AnimatedImageDrawable_src, 0);
+        if (srcResId != 0) {
+            // Follow the density handling in BitmapDrawable.
+            final TypedValue value = new TypedValue();
+            r.getValueForDensity(srcResId, srcDensityOverride, value, true);
+            if (srcDensityOverride > 0 && value.density > 0
+                    && value.density != TypedValue.DENSITY_NONE) {
+                if (value.density == srcDensityOverride) {
+                    value.density = r.getDisplayMetrics().densityDpi;
+                } else {
+                    value.density =
+                            (value.density * r.getDisplayMetrics().densityDpi) / srcDensityOverride;
+                }
+            }
+
+            int density = Bitmap.DENSITY_NONE;
+            if (value.density == TypedValue.DENSITY_DEFAULT) {
+                density = DisplayMetrics.DENSITY_DEFAULT;
+            } else if (value.density != TypedValue.DENSITY_NONE) {
+                density = value.density;
+            }
+
+            Drawable drawable = null;
+            try {
+                InputStream is = r.openRawResource(srcResId, value);
+                ImageDecoder.Source source = ImageDecoder.createSource(r, is, density);
+                drawable = ImageDecoder.decodeDrawable(source, (decoder, info, src) -> {
+                    if (!info.isAnimated()) {
+                        throw new IllegalArgumentException("image is not animated");
+                    }
+                });
+            } catch (IOException e) {
+                throw new XmlPullParserException(a.getPositionDescription() +
+                        ": <animated-image> requires a valid 'src' attribute", null, e);
+            }
+
+            if (!(drawable instanceof AnimatedImageDrawable)) {
+                throw new XmlPullParserException(a.getPositionDescription() +
+                        ": <animated-image> did not decode animated");
+            }
+
+            // Transfer the state of other to this one. other will be discarded.
+            AnimatedImageDrawable other = (AnimatedImageDrawable) drawable;
+            mState = other.mState;
+            other.mState = null;
+            mIntrinsicWidth =  other.mIntrinsicWidth;
+            mIntrinsicHeight = other.mIntrinsicHeight;
+        }
+    }
+
+    /**
      * @hide
      * This should only be called by ImageDecoder.
      *
@@ -80,30 +202,14 @@
             mIntrinsicHeight = cropRect.height();
         }
 
-        mNativePtr = nCreate(nativeImageDecoder, decoder, width, height, cropRect);
-        mInputStream = inputStream;
-        mAssetFd = afd;
+        mState = new State(nCreate(nativeImageDecoder, decoder, width, height, cropRect),
+                inputStream, afd);
 
         // FIXME: Use the right size for the native allocation.
         long nativeSize = 200;
         NativeAllocationRegistry registry = new NativeAllocationRegistry(
                 AnimatedImageDrawable.class.getClassLoader(), nGetNativeFinalizer(), nativeSize);
-        registry.registerNativeAllocation(this, mNativePtr);
-    }
-
-    @Override
-    protected void finalize() throws Throwable {
-        // FIXME: It's a shame that we have *both* a native finalizer and a Java
-        // one. The native one is necessary to report how much memory is being
-        // used natively, and this one is necessary to close the input. An
-        // alternative might be to read the entire stream ahead of time, so we
-        // can eliminate the Java finalizer.
-        try {
-            IoUtils.closeQuietly(mInputStream);
-            IoUtils.closeQuietly(mAssetFd);
-        } finally {
-            super.finalize();
-        }
+        registry.registerNativeAllocation(mState, mState.mNativePtr);
     }
 
     @Override
@@ -116,13 +222,34 @@
         return mIntrinsicHeight;
     }
 
+    // nDraw returns -2 if the animation is not running.
+    private static final int NOT_RUNNING = -2;
+
     @Override
     public void draw(@NonNull Canvas canvas) {
-        long nextUpdate = nDraw(mNativePtr, canvas.getNativeCanvasWrapper());
+        if (mState == null) {
+            throw new IllegalStateException("called draw on empty AnimatedImageDrawable");
+        }
+
+        if (mStarting) {
+            mStarting = false;
+
+            postOnAnimationStart();
+
+            mRunning = true;
+        }
+
+        long nextUpdate = nDraw(mState.mNativePtr, canvas.getNativeCanvasWrapper());
         // a value <= 0 indicates that the drawable is stopped or that renderThread
         // will manage the animation
         if (nextUpdate > 0) {
             scheduleSelf(mRunnable, nextUpdate);
+        } else if (nextUpdate == NOT_RUNNING) {
+            // -2 means the animation ended, when drawn in software mode.
+            if (mRunning) {
+                postOnAnimationEnd();
+                mRunning = false;
+            }
         }
     }
 
@@ -132,19 +259,31 @@
             throw new IllegalArgumentException("Alpha must be between 0 and"
                    + " 255! provided " + alpha);
         }
-        nSetAlpha(mNativePtr, alpha);
+
+        if (mState == null) {
+            throw new IllegalStateException("called setAlpha on empty AnimatedImageDrawable");
+        }
+
+        nSetAlpha(mState.mNativePtr, alpha);
         invalidateSelf();
     }
 
     @Override
     public int getAlpha() {
-        return nGetAlpha(mNativePtr);
+        if (mState == null) {
+            throw new IllegalStateException("called getAlpha on empty AnimatedImageDrawable");
+        }
+        return nGetAlpha(mState.mNativePtr);
     }
 
     @Override
     public void setColorFilter(@Nullable ColorFilter colorFilter) {
+        if (mState == null) {
+            throw new IllegalStateException("called setColorFilter on empty AnimatedImageDrawable");
+        }
+
         long nativeFilter = colorFilter == null ? 0 : colorFilter.getNativeInstance();
-        nSetColorFilter(mNativePtr, nativeFilter);
+        nSetColorFilter(mState.mNativePtr, nativeFilter);
         invalidateSelf();
     }
 
@@ -153,29 +292,116 @@
         return PixelFormat.TRANSLUCENT;
     }
 
-    // TODO: Add a Constant State?
-    // @Override
-    // public @Nullable ConstantState getConstantState() {}
-
-
     // Animatable overrides
+    /**
+     *  Return whether the animation is currently running.
+     *
+     *  <p>When this drawable is created, this will return {@code false}. A client
+     *  needs to call {@link #start} to start the animation.</p>
+     */
     @Override
     public boolean isRunning() {
-        return nIsRunning(mNativePtr);
+        return mRunning;
     }
 
+    /**
+     *  Start the animation.
+     *
+     *  <p>Does nothing if the animation is already running.
+     *
+     *  <p>If the animation starts, this will call
+     *  {@link Animatable2.AnimationCallback#onAnimationStart}.</p>
+     */
     @Override
     public void start() {
-        if (nStart(mNativePtr)) {
+        if (mState == null) {
+            throw new IllegalStateException("called start on empty AnimatedImageDrawable");
+        }
+
+        if (nStart(mState.mNativePtr)) {
+            mStarting = true;
             invalidateSelf();
         }
     }
 
+    /**
+     *  Stop the animation.
+     *
+     *  <p>If the animation is stopped, it will continue to display the frame
+     *  it was displaying when stopped.</p>
+     */
     @Override
     public void stop() {
-        nStop(mNativePtr);
+        if (mState == null) {
+            throw new IllegalStateException("called stop on empty AnimatedImageDrawable");
+        }
+        nStop(mState.mNativePtr);
+        mRunning = false;
     }
 
+    // Animatable2 overrides
+    private ArrayList<Animatable2.AnimationCallback> mAnimationCallbacks = null;
+
+    @Override
+    public void registerAnimationCallback(@NonNull AnimationCallback callback) {
+        if (callback == null) {
+            return;
+        }
+
+        if (mAnimationCallbacks == null) {
+            mAnimationCallbacks = new ArrayList<Animatable2.AnimationCallback>();
+            nSetOnAnimationEndListener(mState.mNativePtr, this);
+        }
+
+        mAnimationCallbacks.add(callback);
+    }
+
+    @Override
+    public boolean unregisterAnimationCallback(@NonNull AnimationCallback callback) {
+        if (callback == null || mAnimationCallbacks == null) {
+            return false;
+        }
+
+        return mAnimationCallbacks.remove(callback);
+    }
+
+    @Override
+    public void clearAnimationCallbacks() {
+        mAnimationCallbacks = null;
+    }
+
+    private void postOnAnimationStart() {
+        if (mAnimationCallbacks == null) {
+            return;
+        }
+
+        getHandler().post(() -> {
+            for (Animatable2.AnimationCallback callback : mAnimationCallbacks) {
+                callback.onAnimationStart(this);
+            }
+        });
+    }
+
+    private void postOnAnimationEnd() {
+        if (mAnimationCallbacks == null) {
+            return;
+        }
+
+        getHandler().post(() -> {
+            for (Animatable2.AnimationCallback callback : mAnimationCallbacks) {
+                callback.onAnimationEnd(this);
+            }
+        });
+    }
+
+    private Handler getHandler() {
+        if (mHandler == null) {
+            mHandler = new Handler(Looper.getMainLooper());
+        }
+        return mHandler;
+    }
+
+
     private static native long nCreate(long nativeImageDecoder,
             @Nullable ImageDecoder decoder, int width, int height, Rect cropRect)
         throws IOException;
@@ -185,7 +411,12 @@
     private static native int nGetAlpha(long nativePtr);
     private static native void nSetColorFilter(long nativePtr, long nativeFilter);
     private static native boolean nIsRunning(long nativePtr);
+    // Return whether the animation started.
     private static native boolean nStart(long nativePtr);
     private static native void nStop(long nativePtr);
+    private static native void nSetLoopCount(long nativePtr, int loopCount);
+    // Pass the drawable down to native so it can call onAnimationEnd.
+    private static native void nSetOnAnimationEndListener(long nativePtr,
+            @Nullable AnimatedImageDrawable drawable);
     private static native long nNativeByteSize(long nativePtr);
 }
diff --git a/graphics/java/android/graphics/drawable/DrawableInflater.java b/graphics/java/android/graphics/drawable/DrawableInflater.java
index eea7048..0ee9071 100644
--- a/graphics/java/android/graphics/drawable/DrawableInflater.java
+++ b/graphics/java/android/graphics/drawable/DrawableInflater.java
@@ -185,6 +185,8 @@
                 return new BitmapDrawable();
             case "nine-patch":
                 return new NinePatchDrawable();
+            case "animated-image":
+                return new AnimatedImageDrawable();
             default:
                 return null;
         }
diff --git a/libs/androidfw/Android.bp b/libs/androidfw/Android.bp
index 70d5216..251b2e7 100644
--- a/libs/androidfw/Android.bp
+++ b/libs/androidfw/Android.bp
@@ -145,7 +145,6 @@
         "tests/TypeWrappers_test.cpp",
         "tests/ZipUtils_test.cpp",
     ],
-    static_libs: ["libgmock"],
     target: {
         android: {
             srcs: [
@@ -172,7 +171,6 @@
 
         // Actual benchmarks.
         "tests/AssetManager2_bench.cpp",
-        "tests/AttributeResolution_bench.cpp",
         "tests/SparseEntry_bench.cpp",
         "tests/Theme_bench.cpp",
     ],
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
index 0485625..a5698af 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -73,6 +73,7 @@
 const char* AssetManager::RESOURCES_FILENAME = "resources.arsc";
 const char* AssetManager::IDMAP_BIN = "/system/bin/idmap";
 const char* AssetManager::OVERLAY_DIR = "/vendor/overlay";
+const char* AssetManager::PRODUCT_OVERLAY_DIR = "/product/overlay";
 const char* AssetManager::OVERLAY_THEME_DIR_PROPERTY = "ro.boot.vendor.overlay.theme";
 const char* AssetManager::TARGET_PACKAGE_NAME = "android";
 const char* AssetManager::TARGET_APK_PATH = "/system/framework/framework-res.apk";
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index a558ff7..415d3e3 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -36,31 +36,6 @@
 
 namespace android {
 
-struct FindEntryResult {
-  // A pointer to the resource table entry for this resource.
-  // If the size of the entry is > sizeof(ResTable_entry), it can be cast to
-  // a ResTable_map_entry and processed as a bag/map.
-  const ResTable_entry* entry;
-
-  // The configuration for which the resulting entry was defined. This is already swapped to host
-  // endianness.
-  ResTable_config config;
-
-  // The bitmask of configuration axis with which the resource value varies.
-  uint32_t type_flags;
-
-  // The dynamic package ID map for the package from which this resource came from.
-  const DynamicRefTable* dynamic_ref_table;
-
-  // The string pool reference to the type's name. This uses a different string pool than
-  // the global string pool, but this is hidden from the caller.
-  StringPoolRef type_string_ref;
-
-  // The string pool reference to the entry's name. This uses a different string pool than
-  // the global string pool, but this is hidden from the caller.
-  StringPoolRef entry_string_ref;
-};
-
 AssetManager2::AssetManager2() {
   memset(&configuration_, 0, sizeof(configuration_));
 }
@@ -69,7 +44,6 @@
                                  bool invalidate_caches) {
   apk_assets_ = apk_assets;
   BuildDynamicRefTable();
-  RebuildFilterList();
   if (invalidate_caches) {
     InvalidateCaches(static_cast<uint32_t>(-1));
   }
@@ -105,7 +79,7 @@
       PackageGroup* package_group = &package_groups_[idx];
 
       // Add the package and to the set of packages with the same ID.
-      package_group->packages_.push_back(ConfiguredPackage{package.get(), {}});
+      package_group->packages_.push_back(package.get());
       package_group->cookies_.push_back(static_cast<ApkAssetsCookie>(i));
 
       // Add the package name -> build time ID mappings.
@@ -120,7 +94,7 @@
   // Now assign the runtime IDs so that we have a build-time to runtime ID map.
   const auto package_groups_end = package_groups_.end();
   for (auto iter = package_groups_.begin(); iter != package_groups_end; ++iter) {
-    const std::string& package_name = iter->packages_[0].loaded_package_->GetPackageName();
+    const std::string& package_name = iter->packages_[0]->GetPackageName();
     for (auto iter2 = package_groups_.begin(); iter2 != package_groups_end; ++iter2) {
       iter2->dynamic_ref_table.addMapping(String16(package_name.c_str(), package_name.size()),
                                           iter->dynamic_ref_table.mAssignedPackageId);
@@ -134,20 +108,17 @@
   std::string list;
   for (size_t i = 0; i < package_ids_.size(); i++) {
     if (package_ids_[i] != 0xff) {
-      base::StringAppendF(&list, "%02x -> %d, ", (int)i, package_ids_[i]);
+      base::StringAppendF(&list, "%02x -> %d, ", (int) i, package_ids_[i]);
     }
   }
   LOG(INFO) << "Package ID map: " << list;
 
-  for (const auto& package_group : package_groups_) {
-    list = "";
-    for (const auto& package : package_group.packages_) {
-      base::StringAppendF(&list, "%s(%02x), ", package.loaded_package_->GetPackageName().c_str(),
-                          package.loaded_package_->GetPackageId());
-    }
-    LOG(INFO) << base::StringPrintf("PG (%02x): ",
-                                    package_group.dynamic_ref_table.mAssignedPackageId)
-              << list;
+  for (const auto& package_group: package_groups_) {
+      list = "";
+      for (const auto& package : package_group.packages_) {
+        base::StringAppendF(&list, "%s(%02x), ", package->GetPackageName().c_str(), package->GetPackageId());
+      }
+      LOG(INFO) << base::StringPrintf("PG (%02x): ", package_group.dynamic_ref_table.mAssignedPackageId) << list;
   }
 }
 
@@ -186,54 +157,52 @@
   configuration_ = configuration;
 
   if (diff) {
-    RebuildFilterList();
     InvalidateCaches(static_cast<uint32_t>(diff));
   }
 }
 
 std::set<ResTable_config> AssetManager2::GetResourceConfigurations(bool exclude_system,
-                                                                   bool exclude_mipmap) const {
+                                                                   bool exclude_mipmap) {
   ATRACE_CALL();
   std::set<ResTable_config> configurations;
   for (const PackageGroup& package_group : package_groups_) {
-    for (const ConfiguredPackage& package : package_group.packages_) {
-      if (exclude_system && package.loaded_package_->IsSystem()) {
+    for (const LoadedPackage* package : package_group.packages_) {
+      if (exclude_system && package->IsSystem()) {
         continue;
       }
-      package.loaded_package_->CollectConfigurations(exclude_mipmap, &configurations);
+      package->CollectConfigurations(exclude_mipmap, &configurations);
     }
   }
   return configurations;
 }
 
 std::set<std::string> AssetManager2::GetResourceLocales(bool exclude_system,
-                                                        bool merge_equivalent_languages) const {
+                                                        bool merge_equivalent_languages) {
   ATRACE_CALL();
   std::set<std::string> locales;
   for (const PackageGroup& package_group : package_groups_) {
-    for (const ConfiguredPackage& package : package_group.packages_) {
-      if (exclude_system && package.loaded_package_->IsSystem()) {
+    for (const LoadedPackage* package : package_group.packages_) {
+      if (exclude_system && package->IsSystem()) {
         continue;
       }
-      package.loaded_package_->CollectLocales(merge_equivalent_languages, &locales);
+      package->CollectLocales(merge_equivalent_languages, &locales);
     }
   }
   return locales;
 }
 
-std::unique_ptr<Asset> AssetManager2::Open(const std::string& filename,
-                                           Asset::AccessMode mode) const {
+std::unique_ptr<Asset> AssetManager2::Open(const std::string& filename, Asset::AccessMode mode) {
   const std::string new_path = "assets/" + filename;
   return OpenNonAsset(new_path, mode);
 }
 
 std::unique_ptr<Asset> AssetManager2::Open(const std::string& filename, ApkAssetsCookie cookie,
-                                           Asset::AccessMode mode) const {
+                                           Asset::AccessMode mode) {
   const std::string new_path = "assets/" + filename;
   return OpenNonAsset(new_path, cookie, mode);
 }
 
-std::unique_ptr<AssetDir> AssetManager2::OpenDir(const std::string& dirname) const {
+std::unique_ptr<AssetDir> AssetManager2::OpenDir(const std::string& dirname) {
   ATRACE_CALL();
 
   std::string full_path = "assets/" + dirname;
@@ -267,7 +236,7 @@
 // is inconsistent for split APKs.
 std::unique_ptr<Asset> AssetManager2::OpenNonAsset(const std::string& filename,
                                                    Asset::AccessMode mode,
-                                                   ApkAssetsCookie* out_cookie) const {
+                                                   ApkAssetsCookie* out_cookie) {
   ATRACE_CALL();
   for (int32_t i = apk_assets_.size() - 1; i >= 0; i--) {
     std::unique_ptr<Asset> asset = apk_assets_[i]->Open(filename, mode);
@@ -286,8 +255,7 @@
 }
 
 std::unique_ptr<Asset> AssetManager2::OpenNonAsset(const std::string& filename,
-                                                   ApkAssetsCookie cookie,
-                                                   Asset::AccessMode mode) const {
+                                                   ApkAssetsCookie cookie, Asset::AccessMode mode) {
   ATRACE_CALL();
   if (cookie < 0 || static_cast<size_t>(cookie) >= apk_assets_.size()) {
     return {};
@@ -296,13 +264,14 @@
 }
 
 ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_override,
-                                         bool /*stop_at_first_match*/,
-                                         FindEntryResult* out_entry) const {
+                                         bool stop_at_first_match, FindEntryResult* out_entry) {
+  ATRACE_CALL();
+
   // Might use this if density_override != 0.
   ResTable_config density_override_config;
 
   // Select our configuration or generate a density override configuration.
-  const ResTable_config* desired_config = &configuration_;
+  ResTable_config* desired_config = &configuration_;
   if (density_override != 0 && density_override != configuration_.density) {
     density_override_config = configuration_;
     density_override_config.density = density_override;
@@ -316,135 +285,53 @@
 
   const uint32_t package_id = get_package_id(resid);
   const uint8_t type_idx = get_type_id(resid) - 1;
-  const uint16_t entry_idx = get_entry_id(resid);
+  const uint16_t entry_id = get_entry_id(resid);
 
-  const uint8_t package_idx = package_ids_[package_id];
-  if (package_idx == 0xff) {
+  const uint8_t idx = package_ids_[package_id];
+  if (idx == 0xff) {
     LOG(ERROR) << base::StringPrintf("No package ID %02x found for ID 0x%08x.", package_id, resid);
     return kInvalidCookie;
   }
 
-  const PackageGroup& package_group = package_groups_[package_idx];
-  const size_t package_count = package_group.packages_.size();
-
+  FindEntryResult best_entry;
   ApkAssetsCookie best_cookie = kInvalidCookie;
-  const LoadedPackage* best_package = nullptr;
-  const ResTable_type* best_type = nullptr;
-  const ResTable_config* best_config = nullptr;
-  ResTable_config best_config_copy;
-  uint32_t best_offset = 0u;
-  uint32_t type_flags = 0u;
+  uint32_t cumulated_flags = 0u;
 
-  // If desired_config is the same as the set configuration, then we can use our filtered list
-  // and we don't need to match the configurations, since they already matched.
-  const bool use_fast_path = desired_config == &configuration_;
-
-  for (size_t pi = 0; pi < package_count; pi++) {
-    const ConfiguredPackage& loaded_package_impl = package_group.packages_[pi];
-    const LoadedPackage* loaded_package = loaded_package_impl.loaded_package_;
-    ApkAssetsCookie cookie = package_group.cookies_[pi];
-
-    // If the type IDs are offset in this package, we need to take that into account when searching
-    // for a type.
-    const TypeSpec* type_spec = loaded_package->GetTypeSpecByTypeIndex(type_idx);
-    if (UNLIKELY(type_spec == nullptr)) {
+  const PackageGroup& package_group = package_groups_[idx];
+  const size_t package_count = package_group.packages_.size();
+  FindEntryResult current_entry;
+  for (size_t i = 0; i < package_count; i++) {
+    const LoadedPackage* loaded_package = package_group.packages_[i];
+    if (!loaded_package->FindEntry(type_idx, entry_id, *desired_config, &current_entry)) {
       continue;
     }
 
-    uint16_t local_entry_idx = entry_idx;
+    cumulated_flags |= current_entry.type_flags;
 
-    // If there is an IDMAP supplied with this package, translate the entry ID.
-    if (type_spec->idmap_entries != nullptr) {
-      if (!LoadedIdmap::Lookup(type_spec->idmap_entries, local_entry_idx, &local_entry_idx)) {
-        // There is no mapping, so the resource is not meant to be in this overlay package.
-        continue;
-      }
-    }
-
-    type_flags |= type_spec->GetFlagsForEntryIndex(local_entry_idx);
-
-    // If the package is an overlay, then even configurations that are the same MUST be chosen.
-    const bool package_is_overlay = loaded_package->IsOverlay();
-
-    const FilteredConfigGroup& filtered_group = loaded_package_impl.filtered_configs_[type_idx];
-    if (use_fast_path) {
-      const std::vector<ResTable_config>& candidate_configs = filtered_group.configurations;
-      const size_t type_count = candidate_configs.size();
-      for (uint32_t i = 0; i < type_count; i++) {
-        const ResTable_config& this_config = candidate_configs[i];
-
-        // We can skip calling ResTable_config::match() because we know that all candidate
-        // configurations that do NOT match have been filtered-out.
-        if ((best_config == nullptr || this_config.isBetterThan(*best_config, desired_config)) ||
-            (package_is_overlay && this_config.compare(*best_config) == 0)) {
-          // The configuration matches and is better than the previous selection.
-          // Find the entry value if it exists for this configuration.
-          const ResTable_type* type_chunk = filtered_group.types[i];
-          const uint32_t offset = LoadedPackage::GetEntryOffset(type_chunk, local_entry_idx);
-          if (offset == ResTable_type::NO_ENTRY) {
-            continue;
-          }
-
-          best_cookie = cookie;
-          best_package = loaded_package;
-          best_type = type_chunk;
-          best_config = &this_config;
-          best_offset = offset;
-        }
-      }
-    } else {
-      // This is the slower path, which doesn't use the filtered list of configurations.
-      // Here we must read the ResTable_config from the mmapped APK, convert it to host endianness
-      // and fill in any new fields that did not exist when the APK was compiled.
-      // Furthermore when selecting configurations we can't just record the pointer to the
-      // ResTable_config, we must copy it.
-      const auto iter_end = type_spec->types + type_spec->type_count;
-      for (auto iter = type_spec->types; iter != iter_end; ++iter) {
-        ResTable_config this_config;
-        this_config.copyFromDtoH((*iter)->config);
-
-        if (this_config.match(*desired_config)) {
-          if ((best_config == nullptr || this_config.isBetterThan(*best_config, desired_config)) ||
-              (package_is_overlay && this_config.compare(*best_config) == 0)) {
-            // The configuration matches and is better than the previous selection.
-            // Find the entry value if it exists for this configuration.
-            const uint32_t offset = LoadedPackage::GetEntryOffset(*iter, local_entry_idx);
-            if (offset == ResTable_type::NO_ENTRY) {
-              continue;
-            }
-
-            best_cookie = cookie;
-            best_package = loaded_package;
-            best_type = *iter;
-            best_config_copy = this_config;
-            best_config = &best_config_copy;
-            best_offset = offset;
-          }
-        }
+    const ResTable_config* current_config = current_entry.config;
+    const ResTable_config* best_config = best_entry.config;
+    if (best_cookie == kInvalidCookie ||
+        current_config->isBetterThan(*best_config, desired_config) ||
+        (loaded_package->IsOverlay() && current_config->compare(*best_config) == 0)) {
+      best_entry = current_entry;
+      best_cookie = package_group.cookies_[i];
+      if (stop_at_first_match) {
+        break;
       }
     }
   }
 
-  if (UNLIKELY(best_cookie == kInvalidCookie)) {
+  if (best_cookie == kInvalidCookie) {
     return kInvalidCookie;
   }
 
-  const ResTable_entry* best_entry = LoadedPackage::GetEntryFromOffset(best_type, best_offset);
-  if (UNLIKELY(best_entry == nullptr)) {
-    return kInvalidCookie;
-  }
-
-  out_entry->entry = best_entry;
-  out_entry->config = *best_config;
-  out_entry->type_flags = type_flags;
-  out_entry->type_string_ref = StringPoolRef(best_package->GetTypeStringPool(), best_type->id - 1);
-  out_entry->entry_string_ref =
-      StringPoolRef(best_package->GetKeyStringPool(), best_entry->key.index);
+  *out_entry = best_entry;
   out_entry->dynamic_ref_table = &package_group.dynamic_ref_table;
+  out_entry->type_flags = cumulated_flags;
   return best_cookie;
 }
 
-bool AssetManager2::GetResourceName(uint32_t resid, ResourceName* out_name) const {
+bool AssetManager2::GetResourceName(uint32_t resid, ResourceName* out_name) {
   ATRACE_CALL();
 
   FindEntryResult entry;
@@ -454,8 +341,7 @@
     return false;
   }
 
-  const LoadedPackage* package =
-      apk_assets_[cookie]->GetLoadedArsc()->GetPackageById(get_package_id(resid));
+  const LoadedPackage* package = apk_assets_[cookie]->GetLoadedArsc()->GetPackageForId(resid);
   if (package == nullptr) {
     return false;
   }
@@ -483,7 +369,7 @@
   return true;
 }
 
-bool AssetManager2::GetResourceFlags(uint32_t resid, uint32_t* out_flags) const {
+bool AssetManager2::GetResourceFlags(uint32_t resid, uint32_t* out_flags) {
   FindEntryResult entry;
   ApkAssetsCookie cookie =
       FindEntry(resid, 0u /* density_override */, false /* stop_at_first_match */, &entry);
@@ -497,7 +383,7 @@
 ApkAssetsCookie AssetManager2::GetResource(uint32_t resid, bool may_be_bag,
                                            uint16_t density_override, Res_value* out_value,
                                            ResTable_config* out_selected_config,
-                                           uint32_t* out_flags) const {
+                                           uint32_t* out_flags) {
   ATRACE_CALL();
 
   FindEntryResult entry;
@@ -516,7 +402,7 @@
     // Create a reference since we can't represent this complex type as a Res_value.
     out_value->dataType = Res_value::TYPE_REFERENCE;
     out_value->data = resid;
-    *out_selected_config = entry.config;
+    *out_selected_config = *entry.config;
     *out_flags = entry.type_flags;
     return cookie;
   }
@@ -528,7 +414,7 @@
   // Convert the package ID to the runtime assigned package ID.
   entry.dynamic_ref_table->lookupResourceValue(out_value);
 
-  *out_selected_config = entry.config;
+  *out_selected_config = *entry.config;
   *out_flags = entry.type_flags;
   return cookie;
 }
@@ -536,14 +422,16 @@
 ApkAssetsCookie AssetManager2::ResolveReference(ApkAssetsCookie cookie, Res_value* in_out_value,
                                                 ResTable_config* in_out_selected_config,
                                                 uint32_t* in_out_flags,
-                                                uint32_t* out_last_reference) const {
+                                                uint32_t* out_last_reference) {
   ATRACE_CALL();
   constexpr const int kMaxIterations = 20;
 
   for (size_t iteration = 0u; in_out_value->dataType == Res_value::TYPE_REFERENCE &&
                               in_out_value->data != 0u && iteration < kMaxIterations;
        iteration++) {
-    *out_last_reference = in_out_value->data;
+    if (out_last_reference != nullptr) {
+      *out_last_reference = in_out_value->data;
+    }
     uint32_t new_flags = 0u;
     cookie = GetResource(in_out_value->data, true /*may_be_bag*/, 0u /*density_override*/,
                          in_out_value, in_out_selected_config, &new_flags);
@@ -604,8 +492,7 @@
         // Attributes, arrays, etc don't have a resource id as the name. They specify
         // other data, which would be wrong to change via a lookup.
         if (entry.dynamic_ref_table->lookupResourceId(&new_key) != NO_ERROR) {
-          LOG(ERROR) << base::StringPrintf("Failed to resolve key 0x%08x in bag 0x%08x.", new_key,
-                                           resid);
+          LOG(ERROR) << base::StringPrintf("Failed to resolve key 0x%08x in bag 0x%08x.", new_key, resid);
           return nullptr;
         }
       }
@@ -637,8 +524,7 @@
   const ResolvedBag* parent_bag = GetBag(parent_resid);
   if (parent_bag == nullptr) {
     // Failed to get the parent that should exist.
-    LOG(ERROR) << base::StringPrintf("Failed to find parent 0x%08x of bag 0x%08x.", parent_resid,
-                                     resid);
+    LOG(ERROR) << base::StringPrintf("Failed to find parent 0x%08x of bag 0x%08x.", parent_resid, resid);
     return nullptr;
   }
 
@@ -657,8 +543,7 @@
     uint32_t child_key = dtohl(map_entry->name.ident);
     if (!is_internal_resid(child_key)) {
       if (entry.dynamic_ref_table->lookupResourceId(&child_key) != NO_ERROR) {
-        LOG(ERROR) << base::StringPrintf("Failed to resolve key 0x%08x in bag 0x%08x.", child_key,
-                                         resid);
+        LOG(ERROR) << base::StringPrintf("Failed to resolve key 0x%08x in bag 0x%08x.", child_key, resid);
         return nullptr;
       }
     }
@@ -697,8 +582,7 @@
     uint32_t new_key = dtohl(map_entry->name.ident);
     if (!is_internal_resid(new_key)) {
       if (entry.dynamic_ref_table->lookupResourceId(&new_key) != NO_ERROR) {
-        LOG(ERROR) << base::StringPrintf("Failed to resolve key 0x%08x in bag 0x%08x.", new_key,
-                                         resid);
+        LOG(ERROR) << base::StringPrintf("Failed to resolve key 0x%08x in bag 0x%08x.", new_key, resid);
         return nullptr;
       }
     }
@@ -754,7 +638,7 @@
 
 uint32_t AssetManager2::GetResourceId(const std::string& resource_name,
                                       const std::string& fallback_type,
-                                      const std::string& fallback_package) const {
+                                      const std::string& fallback_package) {
   StringPiece package_name, type, entry;
   if (!ExtractResourceName(resource_name, &package_name, &type, &entry)) {
     return 0u;
@@ -786,8 +670,7 @@
   const static std::u16string kAttrPrivate16 = u"^attr-private";
 
   for (const PackageGroup& package_group : package_groups_) {
-    for (const ConfiguredPackage& package_impl : package_group.packages_) {
-      const LoadedPackage* package = package_impl.loaded_package_;
+    for (const LoadedPackage* package : package_group.packages_) {
       if (package_name != package->GetPackageName()) {
         // All packages in the same group are expected to have the same package name.
         break;
@@ -809,32 +692,6 @@
   return 0u;
 }
 
-void AssetManager2::RebuildFilterList() {
-  for (PackageGroup& group : package_groups_) {
-    for (ConfiguredPackage& impl : group.packages_) {
-      // Destroy it.
-      impl.filtered_configs_.~ByteBucketArray();
-
-      // Re-create it.
-      new (&impl.filtered_configs_) ByteBucketArray<FilteredConfigGroup>();
-
-      // Create the filters here.
-      impl.loaded_package_->ForEachTypeSpec([&](const TypeSpec* spec, uint8_t type_index) {
-        FilteredConfigGroup& group = impl.filtered_configs_.editItemAt(type_index);
-        const auto iter_end = spec->types + spec->type_count;
-        for (auto iter = spec->types; iter != iter_end; ++iter) {
-          ResTable_config this_config;
-          this_config.copyFromDtoH((*iter)->config);
-          if (this_config.match(configuration_)) {
-            group.configurations.push_back(this_config);
-            group.types.push_back(*iter);
-          }
-        }
-      });
-    }
-  }
-}
-
 void AssetManager2::InvalidateCaches(uint32_t diff) {
   if (diff == 0xffffffffu) {
     // Everything must go.
@@ -1015,7 +872,7 @@
 ApkAssetsCookie Theme::ResolveAttributeReference(ApkAssetsCookie cookie, Res_value* in_out_value,
                                                  ResTable_config* in_out_selected_config,
                                                  uint32_t* in_out_type_spec_flags,
-                                                 uint32_t* out_last_ref) const {
+                                                 uint32_t* out_last_ref) {
   if (in_out_value->dataType == Res_value::TYPE_ATTRIBUTE) {
     uint32_t new_flags;
     cookie = GetAttribute(in_out_value->data, in_out_value, &new_flags);
diff --git a/libs/androidfw/AttributeResolution.cpp b/libs/androidfw/AttributeResolution.cpp
index f912af4..60e3845 100644
--- a/libs/androidfw/AttributeResolution.cpp
+++ b/libs/androidfw/AttributeResolution.cpp
@@ -20,18 +20,13 @@
 
 #include <log/log.h>
 
-#include "androidfw/AssetManager2.h"
 #include "androidfw/AttributeFinder.h"
+#include "androidfw/ResourceTypes.h"
 
 constexpr bool kDebugStyles = false;
 
 namespace android {
 
-// Java asset cookies have 0 as an invalid cookie, but TypedArray expects < 0.
-static uint32_t ApkAssetsCookieToJavaCookie(ApkAssetsCookie cookie) {
-  return cookie != kInvalidCookie ? static_cast<uint32_t>(cookie + 1) : static_cast<uint32_t>(-1);
-}
-
 class XmlAttributeFinder
     : public BackTrackingAttributeFinder<XmlAttributeFinder, size_t> {
  public:
@@ -49,53 +44,58 @@
 };
 
 class BagAttributeFinder
-    : public BackTrackingAttributeFinder<BagAttributeFinder, const ResolvedBag::Entry*> {
+    : public BackTrackingAttributeFinder<BagAttributeFinder, const ResTable::bag_entry*> {
  public:
-  BagAttributeFinder(const ResolvedBag* bag)
-      : BackTrackingAttributeFinder(bag != nullptr ? bag->entries : nullptr,
-                                    bag != nullptr ? bag->entries + bag->entry_count : nullptr) {
-  }
+  BagAttributeFinder(const ResTable::bag_entry* start,
+                     const ResTable::bag_entry* end)
+      : BackTrackingAttributeFinder(start, end) {}
 
-  inline uint32_t GetAttribute(const ResolvedBag::Entry* entry) const {
-    return entry->key;
+  inline uint32_t GetAttribute(const ResTable::bag_entry* entry) const {
+    return entry->map.name.ident;
   }
 };
 
-bool ResolveAttrs(Theme* theme, uint32_t def_style_attr, uint32_t def_style_res,
-                  uint32_t* src_values, size_t src_values_length, uint32_t* attrs,
-                  size_t attrs_length, uint32_t* out_values, uint32_t* out_indices) {
+bool ResolveAttrs(ResTable::Theme* theme, uint32_t def_style_attr,
+                  uint32_t def_style_res, uint32_t* src_values,
+                  size_t src_values_length, uint32_t* attrs,
+                  size_t attrs_length, uint32_t* out_values,
+                  uint32_t* out_indices) {
   if (kDebugStyles) {
     ALOGI("APPLY STYLE: theme=0x%p defStyleAttr=0x%x defStyleRes=0x%x", theme,
           def_style_attr, def_style_res);
   }
 
-  AssetManager2* assetmanager = theme->GetAssetManager();
+  const ResTable& res = theme->getResTable();
   ResTable_config config;
   Res_value value;
 
   int indices_idx = 0;
 
   // Load default style from attribute, if specified...
-  uint32_t def_style_flags = 0u;
+  uint32_t def_style_bag_type_set_flags = 0;
   if (def_style_attr != 0) {
     Res_value value;
-    if (theme->GetAttribute(def_style_attr, &value, &def_style_flags) != kInvalidCookie) {
+    if (theme->getAttribute(def_style_attr, &value, &def_style_bag_type_set_flags) >= 0) {
       if (value.dataType == Res_value::TYPE_REFERENCE) {
         def_style_res = value.data;
       }
     }
   }
 
-  // Retrieve the default style bag, if requested.
-  const ResolvedBag* default_style_bag = nullptr;
-  if (def_style_res != 0) {
-    default_style_bag = assetmanager->GetBag(def_style_res);
-    if (default_style_bag != nullptr) {
-      def_style_flags |= default_style_bag->type_spec_flags;
-    }
-  }
+  // Now lock down the resource object and start pulling stuff from it.
+  res.lock();
 
-  BagAttributeFinder def_style_attr_finder(default_style_bag);
+  // Retrieve the default style bag, if requested.
+  const ResTable::bag_entry* def_style_start = nullptr;
+  uint32_t def_style_type_set_flags = 0;
+  ssize_t bag_off = def_style_res != 0
+                        ? res.getBagLocked(def_style_res, &def_style_start,
+                                           &def_style_type_set_flags)
+                        : -1;
+  def_style_type_set_flags |= def_style_bag_type_set_flags;
+  const ResTable::bag_entry* const def_style_end =
+      def_style_start + (bag_off >= 0 ? bag_off : 0);
+  BagAttributeFinder def_style_attr_finder(def_style_start, def_style_end);
 
   // Now iterate through all of the attributes that the client has requested,
   // filling in each with whatever data we can find.
@@ -106,7 +106,7 @@
       ALOGI("RETRIEVING ATTR 0x%08x...", cur_ident);
     }
 
-    ApkAssetsCookie cookie = kInvalidCookie;
+    ssize_t block = -1;
     uint32_t type_set_flags = 0;
 
     value.dataType = Res_value::TYPE_NULL;
@@ -122,14 +122,15 @@
       value.dataType = Res_value::TYPE_ATTRIBUTE;
       value.data = src_values[ii];
       if (kDebugStyles) {
-        ALOGI("-> From values: type=0x%x, data=0x%08x", value.dataType, value.data);
+        ALOGI("-> From values: type=0x%x, data=0x%08x", value.dataType,
+              value.data);
       }
     } else {
-      const ResolvedBag::Entry* const entry = def_style_attr_finder.Find(cur_ident);
-      if (entry != def_style_attr_finder.end()) {
-        cookie = entry->cookie;
-        type_set_flags = def_style_flags;
-        value = entry->value;
+      const ResTable::bag_entry* const def_style_entry = def_style_attr_finder.Find(cur_ident);
+      if (def_style_entry != def_style_end) {
+        block = def_style_entry->stringBlock;
+        type_set_flags = def_style_type_set_flags;
+        value = def_style_entry->map.value;
         if (kDebugStyles) {
           ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data);
         }
@@ -139,26 +140,22 @@
     uint32_t resid = 0;
     if (value.dataType != Res_value::TYPE_NULL) {
       // Take care of resolving the found resource to its final value.
-      ApkAssetsCookie new_cookie =
-          theme->ResolveAttributeReference(cookie, &value, &config, &type_set_flags, &resid);
-      if (new_cookie != kInvalidCookie) {
-        cookie = new_cookie;
-      }
+      ssize_t new_block =
+          theme->resolveAttributeReference(&value, block, &resid, &type_set_flags, &config);
+      if (new_block >= 0) block = new_block;
       if (kDebugStyles) {
         ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data);
       }
     } else if (value.data != Res_value::DATA_NULL_EMPTY) {
-      // If we still don't have a value for this attribute, try to find it in the theme!
-      ApkAssetsCookie new_cookie = theme->GetAttribute(cur_ident, &value, &type_set_flags);
-      if (new_cookie != kInvalidCookie) {
+      // If we still don't have a value for this attribute, try to find
+      // it in the theme!
+      ssize_t new_block = theme->getAttribute(cur_ident, &value, &type_set_flags);
+      if (new_block >= 0) {
         if (kDebugStyles) {
           ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data);
         }
-        new_cookie =
-            assetmanager->ResolveReference(new_cookie, &value, &config, &type_set_flags, &resid);
-        if (new_cookie != kInvalidCookie) {
-          cookie = new_cookie;
-        }
+        new_block = res.resolveReference(&value, new_block, &resid, &type_set_flags, &config);
+        if (new_block >= 0) block = new_block;
         if (kDebugStyles) {
           ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data);
         }
@@ -172,7 +169,7 @@
       }
       value.dataType = Res_value::TYPE_NULL;
       value.data = Res_value::DATA_NULL_UNDEFINED;
-      cookie = kInvalidCookie;
+      block = -1;
     }
 
     if (kDebugStyles) {
@@ -182,7 +179,9 @@
     // Write the final value back to Java.
     out_values[STYLE_TYPE] = value.dataType;
     out_values[STYLE_DATA] = value.data;
-    out_values[STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(cookie);
+    out_values[STYLE_ASSET_COOKIE] =
+        block != -1 ? static_cast<uint32_t>(res.getTableCookie(block))
+                    : static_cast<uint32_t>(-1);
     out_values[STYLE_RESOURCE_ID] = resid;
     out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags;
     out_values[STYLE_DENSITY] = config.density;
@@ -196,80 +195,90 @@
     out_values += STYLE_NUM_ENTRIES;
   }
 
+  res.unlock();
+
   if (out_indices != nullptr) {
     out_indices[0] = indices_idx;
   }
   return true;
 }
 
-void ApplyStyle(Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr,
-                uint32_t def_style_resid, const uint32_t* attrs, size_t attrs_length,
+void ApplyStyle(ResTable::Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr,
+                uint32_t def_style_res, const uint32_t* attrs, size_t attrs_length,
                 uint32_t* out_values, uint32_t* out_indices) {
   if (kDebugStyles) {
-    ALOGI("APPLY STYLE: theme=0x%p defStyleAttr=0x%x defStyleRes=0x%x xml=0x%p", theme,
-          def_style_attr, def_style_resid, xml_parser);
+    ALOGI("APPLY STYLE: theme=0x%p defStyleAttr=0x%x defStyleRes=0x%x xml=0x%p",
+          theme, def_style_attr, def_style_res, xml_parser);
   }
 
-  AssetManager2* assetmanager = theme->GetAssetManager();
+  const ResTable& res = theme->getResTable();
   ResTable_config config;
   Res_value value;
 
   int indices_idx = 0;
 
   // Load default style from attribute, if specified...
-  uint32_t def_style_flags = 0u;
+  uint32_t def_style_bag_type_set_flags = 0;
   if (def_style_attr != 0) {
     Res_value value;
-    if (theme->GetAttribute(def_style_attr, &value, &def_style_flags) != kInvalidCookie) {
+    if (theme->getAttribute(def_style_attr, &value,
+                            &def_style_bag_type_set_flags) >= 0) {
       if (value.dataType == Res_value::TYPE_REFERENCE) {
-        def_style_resid = value.data;
+        def_style_res = value.data;
       }
     }
   }
 
-  // Retrieve the style resource ID associated with the current XML tag's style attribute.
-  uint32_t style_resid = 0u;
-  uint32_t style_flags = 0u;
+  // Retrieve the style class associated with the current XML tag.
+  int style = 0;
+  uint32_t style_bag_type_set_flags = 0;
   if (xml_parser != nullptr) {
     ssize_t idx = xml_parser->indexOfStyle();
     if (idx >= 0 && xml_parser->getAttributeValue(idx, &value) >= 0) {
       if (value.dataType == value.TYPE_ATTRIBUTE) {
-        // Resolve the attribute with out theme.
-        if (theme->GetAttribute(value.data, &value, &style_flags) == kInvalidCookie) {
+        if (theme->getAttribute(value.data, &value, &style_bag_type_set_flags) < 0) {
           value.dataType = Res_value::TYPE_NULL;
         }
       }
-
       if (value.dataType == value.TYPE_REFERENCE) {
-        style_resid = value.data;
+        style = value.data;
       }
     }
   }
 
-  // Retrieve the default style bag, if requested.
-  const ResolvedBag* default_style_bag = nullptr;
-  if (def_style_resid != 0) {
-    default_style_bag = assetmanager->GetBag(def_style_resid);
-    if (default_style_bag != nullptr) {
-      def_style_flags |= default_style_bag->type_spec_flags;
-    }
-  }
+  // Now lock down the resource object and start pulling stuff from it.
+  res.lock();
 
-  BagAttributeFinder def_style_attr_finder(default_style_bag);
+  // Retrieve the default style bag, if requested.
+  const ResTable::bag_entry* def_style_attr_start = nullptr;
+  uint32_t def_style_type_set_flags = 0;
+  ssize_t bag_off = def_style_res != 0
+                        ? res.getBagLocked(def_style_res, &def_style_attr_start,
+                                           &def_style_type_set_flags)
+                        : -1;
+  def_style_type_set_flags |= def_style_bag_type_set_flags;
+  const ResTable::bag_entry* const def_style_attr_end =
+      def_style_attr_start + (bag_off >= 0 ? bag_off : 0);
+  BagAttributeFinder def_style_attr_finder(def_style_attr_start,
+                                           def_style_attr_end);
 
   // Retrieve the style class bag, if requested.
-  const ResolvedBag* xml_style_bag = nullptr;
-  if (style_resid != 0) {
-    xml_style_bag = assetmanager->GetBag(style_resid);
-    if (xml_style_bag != nullptr) {
-      style_flags |= xml_style_bag->type_spec_flags;
-    }
-  }
-
-  BagAttributeFinder xml_style_attr_finder(xml_style_bag);
+  const ResTable::bag_entry* style_attr_start = nullptr;
+  uint32_t style_type_set_flags = 0;
+  bag_off =
+      style != 0
+          ? res.getBagLocked(style, &style_attr_start, &style_type_set_flags)
+          : -1;
+  style_type_set_flags |= style_bag_type_set_flags;
+  const ResTable::bag_entry* const style_attr_end =
+      style_attr_start + (bag_off >= 0 ? bag_off : 0);
+  BagAttributeFinder style_attr_finder(style_attr_start, style_attr_end);
 
   // Retrieve the XML attributes, if requested.
+  static const ssize_t kXmlBlock = 0x10000000;
   XmlAttributeFinder xml_attr_finder(xml_parser);
+  const size_t xml_attr_end =
+      xml_parser != nullptr ? xml_parser->getAttributeCount() : 0;
 
   // Now iterate through all of the attributes that the client has requested,
   // filling in each with whatever data we can find.
@@ -280,8 +289,8 @@
       ALOGI("RETRIEVING ATTR 0x%08x...", cur_ident);
     }
 
-    ApkAssetsCookie cookie = kInvalidCookie;
-    uint32_t type_set_flags = 0u;
+    ssize_t block = kXmlBlock;
+    uint32_t type_set_flags = 0;
 
     value.dataType = Res_value::TYPE_NULL;
     value.data = Res_value::DATA_NULL_UNDEFINED;
@@ -293,7 +302,7 @@
 
     // Walk through the xml attributes looking for the requested attribute.
     const size_t xml_attr_idx = xml_attr_finder.Find(cur_ident);
-    if (xml_attr_idx != xml_attr_finder.end()) {
+    if (xml_attr_idx != xml_attr_end) {
       // We found the attribute we were looking for.
       xml_parser->getAttributeValue(xml_attr_idx, &value);
       if (kDebugStyles) {
@@ -303,12 +312,12 @@
 
     if (value.dataType == Res_value::TYPE_NULL && value.data != Res_value::DATA_NULL_EMPTY) {
       // Walk through the style class values looking for the requested attribute.
-      const ResolvedBag::Entry* entry = xml_style_attr_finder.Find(cur_ident);
-      if (entry != xml_style_attr_finder.end()) {
+      const ResTable::bag_entry* const style_attr_entry = style_attr_finder.Find(cur_ident);
+      if (style_attr_entry != style_attr_end) {
         // We found the attribute we were looking for.
-        cookie = entry->cookie;
-        type_set_flags = style_flags;
-        value = entry->value;
+        block = style_attr_entry->stringBlock;
+        type_set_flags = style_type_set_flags;
+        value = style_attr_entry->map.value;
         if (kDebugStyles) {
           ALOGI("-> From style: type=0x%x, data=0x%08x", value.dataType, value.data);
         }
@@ -317,25 +326,25 @@
 
     if (value.dataType == Res_value::TYPE_NULL && value.data != Res_value::DATA_NULL_EMPTY) {
       // Walk through the default style values looking for the requested attribute.
-      const ResolvedBag::Entry* entry = def_style_attr_finder.Find(cur_ident);
-      if (entry != def_style_attr_finder.end()) {
+      const ResTable::bag_entry* const def_style_attr_entry = def_style_attr_finder.Find(cur_ident);
+      if (def_style_attr_entry != def_style_attr_end) {
         // We found the attribute we were looking for.
-        cookie = entry->cookie;
-        type_set_flags = def_style_flags;
-        value = entry->value;
+        block = def_style_attr_entry->stringBlock;
+        type_set_flags = style_type_set_flags;
+        value = def_style_attr_entry->map.value;
         if (kDebugStyles) {
           ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data);
         }
       }
     }
 
-    uint32_t resid = 0u;
+    uint32_t resid = 0;
     if (value.dataType != Res_value::TYPE_NULL) {
       // Take care of resolving the found resource to its final value.
-      ApkAssetsCookie new_cookie =
-          theme->ResolveAttributeReference(cookie, &value, &config, &type_set_flags, &resid);
-      if (new_cookie != kInvalidCookie) {
-        cookie = new_cookie;
+      ssize_t new_block =
+          theme->resolveAttributeReference(&value, block, &resid, &type_set_flags, &config);
+      if (new_block >= 0) {
+        block = new_block;
       }
 
       if (kDebugStyles) {
@@ -343,15 +352,14 @@
       }
     } else if (value.data != Res_value::DATA_NULL_EMPTY) {
       // If we still don't have a value for this attribute, try to find it in the theme!
-      ApkAssetsCookie new_cookie = theme->GetAttribute(cur_ident, &value, &type_set_flags);
-      if (new_cookie != kInvalidCookie) {
+      ssize_t new_block = theme->getAttribute(cur_ident, &value, &type_set_flags);
+      if (new_block >= 0) {
         if (kDebugStyles) {
           ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data);
         }
-        new_cookie =
-            assetmanager->ResolveReference(new_cookie, &value, &config, &type_set_flags, &resid);
-        if (new_cookie != kInvalidCookie) {
-          cookie = new_cookie;
+        new_block = res.resolveReference(&value, new_block, &resid, &type_set_flags, &config);
+        if (new_block >= 0) {
+          block = new_block;
         }
 
         if (kDebugStyles) {
@@ -367,7 +375,7 @@
       }
       value.dataType = Res_value::TYPE_NULL;
       value.data = Res_value::DATA_NULL_UNDEFINED;
-      cookie = kInvalidCookie;
+      block = kXmlBlock;
     }
 
     if (kDebugStyles) {
@@ -377,7 +385,9 @@
     // Write the final value back to Java.
     out_values[STYLE_TYPE] = value.dataType;
     out_values[STYLE_DATA] = value.data;
-    out_values[STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(cookie);
+    out_values[STYLE_ASSET_COOKIE] =
+        block != kXmlBlock ? static_cast<uint32_t>(res.getTableCookie(block))
+                           : static_cast<uint32_t>(-1);
     out_values[STYLE_RESOURCE_ID] = resid;
     out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags;
     out_values[STYLE_DENSITY] = config.density;
@@ -392,28 +402,36 @@
     out_values += STYLE_NUM_ENTRIES;
   }
 
+  res.unlock();
+
   // out_indices must NOT be nullptr.
   out_indices[0] = indices_idx;
 }
 
-bool RetrieveAttributes(AssetManager2* assetmanager, ResXMLParser* xml_parser, uint32_t* attrs,
-                        size_t attrs_length, uint32_t* out_values, uint32_t* out_indices) {
+bool RetrieveAttributes(const ResTable* res, ResXMLParser* xml_parser,
+                        uint32_t* attrs, size_t attrs_length,
+                        uint32_t* out_values, uint32_t* out_indices) {
   ResTable_config config;
   Res_value value;
 
   int indices_idx = 0;
 
+  // Now lock down the resource object and start pulling stuff from it.
+  res->lock();
+
   // Retrieve the XML attributes, if requested.
   const size_t xml_attr_count = xml_parser->getAttributeCount();
   size_t ix = 0;
   uint32_t cur_xml_attr = xml_parser->getAttributeNameResID(ix);
 
+  static const ssize_t kXmlBlock = 0x10000000;
+
   // Now iterate through all of the attributes that the client has requested,
   // filling in each with whatever data we can find.
   for (size_t ii = 0; ii < attrs_length; ii++) {
     const uint32_t cur_ident = attrs[ii];
-    ApkAssetsCookie cookie = kInvalidCookie;
-    uint32_t type_set_flags = 0u;
+    ssize_t block = kXmlBlock;
+    uint32_t type_set_flags = 0;
 
     value.dataType = Res_value::TYPE_NULL;
     value.data = Res_value::DATA_NULL_UNDEFINED;
@@ -432,27 +450,28 @@
       cur_xml_attr = xml_parser->getAttributeNameResID(ix);
     }
 
-    uint32_t resid = 0u;
+    uint32_t resid = 0;
     if (value.dataType != Res_value::TYPE_NULL) {
       // Take care of resolving the found resource to its final value.
-      ApkAssetsCookie new_cookie =
-          assetmanager->ResolveReference(cookie, &value, &config, &type_set_flags, &resid);
-      if (new_cookie != kInvalidCookie) {
-        cookie = new_cookie;
-      }
+      // printf("Resolving attribute reference\n");
+      ssize_t new_block = res->resolveReference(&value, block, &resid,
+                                                &type_set_flags, &config);
+      if (new_block >= 0) block = new_block;
     }
 
     // Deal with the special @null value -- it turns back to TYPE_NULL.
     if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
       value.dataType = Res_value::TYPE_NULL;
       value.data = Res_value::DATA_NULL_UNDEFINED;
-      cookie = kInvalidCookie;
+      block = kXmlBlock;
     }
 
     // Write the final value back to Java.
     out_values[STYLE_TYPE] = value.dataType;
     out_values[STYLE_DATA] = value.data;
-    out_values[STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(cookie);
+    out_values[STYLE_ASSET_COOKIE] =
+        block != kXmlBlock ? static_cast<uint32_t>(res->getTableCookie(block))
+                           : static_cast<uint32_t>(-1);
     out_values[STYLE_RESOURCE_ID] = resid;
     out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags;
     out_values[STYLE_DENSITY] = config.density;
@@ -466,6 +485,8 @@
     out_values += STYLE_NUM_ENTRIES;
   }
 
+  res->unlock();
+
   if (out_indices != nullptr) {
     out_indices[0] = indices_idx;
   }
diff --git a/libs/androidfw/LoadedArsc.cpp b/libs/androidfw/LoadedArsc.cpp
index 1d2c597..28548e2 100644
--- a/libs/androidfw/LoadedArsc.cpp
+++ b/libs/androidfw/LoadedArsc.cpp
@@ -44,6 +44,44 @@
 
 constexpr const static int kAppPackageId = 0x7f;
 
+// Element of a TypeSpec array. See TypeSpec.
+struct Type {
+  // The configuration for which this type defines entries.
+  // This is already converted to host endianness.
+  ResTable_config configuration;
+
+  // Pointer to the mmapped data where entry definitions are kept.
+  const ResTable_type* type;
+};
+
+// TypeSpec is going to be immediately proceeded by
+// an array of Type structs, all in the same block of memory.
+struct TypeSpec {
+  // Pointer to the mmapped data where flags are kept.
+  // Flags denote whether the resource entry is public
+  // and under which configurations it varies.
+  const ResTable_typeSpec* type_spec;
+
+  // Pointer to the mmapped data where the IDMAP mappings for this type
+  // exist. May be nullptr if no IDMAP exists.
+  const IdmapEntry_header* idmap_entries;
+
+  // The number of types that follow this struct.
+  // There is a type for each configuration
+  // that entries are defined for.
+  size_t type_count;
+
+  // Trick to easily access a variable number of Type structs
+  // proceeding this struct, and to ensure their alignment.
+  const Type types[0];
+};
+
+// TypeSpecPtr points to the block of memory that holds
+// a TypeSpec struct, followed by an array of Type structs.
+// TypeSpecPtr is a managed pointer that knows how to delete
+// itself.
+using TypeSpecPtr = util::unique_cptr<TypeSpec>;
+
 namespace {
 
 // Builder that helps accumulate Type structs and then create a single
@@ -57,22 +95,21 @@
   }
 
   void AddType(const ResTable_type* type) {
-    types_.push_back(type);
+    ResTable_config config;
+    config.copyFromDtoH(type->config);
+    types_.push_back(Type{config, type});
   }
 
   TypeSpecPtr Build() {
     // Check for overflow.
-    using ElementType = const ResTable_type*;
-    if ((std::numeric_limits<size_t>::max() - sizeof(TypeSpec)) / sizeof(ElementType) <
-        types_.size()) {
+    if ((std::numeric_limits<size_t>::max() - sizeof(TypeSpec)) / sizeof(Type) < types_.size()) {
       return {};
     }
-    TypeSpec* type_spec =
-        (TypeSpec*)::malloc(sizeof(TypeSpec) + (types_.size() * sizeof(ElementType)));
+    TypeSpec* type_spec = (TypeSpec*)::malloc(sizeof(TypeSpec) + (types_.size() * sizeof(Type)));
     type_spec->type_spec = header_;
     type_spec->idmap_entries = idmap_header_;
     type_spec->type_count = types_.size();
-    memcpy(type_spec + 1, types_.data(), types_.size() * sizeof(ElementType));
+    memcpy(type_spec + 1, types_.data(), types_.size() * sizeof(Type));
     return TypeSpecPtr(type_spec);
   }
 
@@ -81,7 +118,7 @@
 
   const ResTable_typeSpec* header_;
   const IdmapEntry_header* idmap_header_;
-  std::vector<const ResTable_type*> types_;
+  std::vector<Type> types_;
 };
 
 }  // namespace
@@ -125,17 +162,18 @@
   return true;
 }
 
-static bool VerifyResTableEntry(const ResTable_type* type, uint32_t entry_offset) {
+static bool VerifyResTableEntry(const ResTable_type* type, uint32_t entry_offset,
+                                size_t entry_idx) {
   // Check that the offset is aligned.
   if (entry_offset & 0x03) {
-    LOG(ERROR) << "Entry at offset " << entry_offset << " is not 4-byte aligned.";
+    LOG(ERROR) << "Entry offset at index " << entry_idx << " is not 4-byte aligned.";
     return false;
   }
 
   // Check that the offset doesn't overflow.
   if (entry_offset > std::numeric_limits<uint32_t>::max() - dtohl(type->entriesStart)) {
     // Overflow in offset.
-    LOG(ERROR) << "Entry at offset " << entry_offset << " is too large.";
+    LOG(ERROR) << "Entry offset at index " << entry_idx << " is too large.";
     return false;
   }
 
@@ -143,7 +181,7 @@
 
   entry_offset += dtohl(type->entriesStart);
   if (entry_offset > chunk_size - sizeof(ResTable_entry)) {
-    LOG(ERROR) << "Entry at offset " << entry_offset
+    LOG(ERROR) << "Entry offset at index " << entry_idx
                << " is too large. No room for ResTable_entry.";
     return false;
   }
@@ -153,13 +191,13 @@
 
   const size_t entry_size = dtohs(entry->size);
   if (entry_size < sizeof(*entry)) {
-    LOG(ERROR) << "ResTable_entry size " << entry_size << " at offset " << entry_offset
+    LOG(ERROR) << "ResTable_entry size " << entry_size << " at index " << entry_idx
                << " is too small.";
     return false;
   }
 
   if (entry_size > chunk_size || entry_offset > chunk_size - entry_size) {
-    LOG(ERROR) << "ResTable_entry size " << entry_size << " at offset " << entry_offset
+    LOG(ERROR) << "ResTable_entry size " << entry_size << " at index " << entry_idx
                << " is too large.";
     return false;
   }
@@ -167,7 +205,7 @@
   if (entry_size < sizeof(ResTable_map_entry)) {
     // There needs to be room for one Res_value struct.
     if (entry_offset + entry_size > chunk_size - sizeof(Res_value)) {
-      LOG(ERROR) << "No room for Res_value after ResTable_entry at offset " << entry_offset
+      LOG(ERROR) << "No room for Res_value after ResTable_entry at index " << entry_idx
                  << " for type " << (int)type->id << ".";
       return false;
     }
@@ -176,12 +214,12 @@
         reinterpret_cast<const Res_value*>(reinterpret_cast<const uint8_t*>(entry) + entry_size);
     const size_t value_size = dtohs(value->size);
     if (value_size < sizeof(Res_value)) {
-      LOG(ERROR) << "Res_value at offset " << entry_offset << " is too small.";
+      LOG(ERROR) << "Res_value at index " << entry_idx << " is too small.";
       return false;
     }
 
     if (value_size > chunk_size || entry_offset + entry_size > chunk_size - value_size) {
-      LOG(ERROR) << "Res_value size " << value_size << " at offset " << entry_offset
+      LOG(ERROR) << "Res_value size " << value_size << " at index " << entry_idx
                  << " is too large.";
       return false;
     }
@@ -190,76 +228,119 @@
     const size_t map_entry_count = dtohl(map->count);
     size_t map_entries_start = entry_offset + entry_size;
     if (map_entries_start & 0x03) {
-      LOG(ERROR) << "Map entries at offset " << entry_offset << " start at unaligned offset.";
+      LOG(ERROR) << "Map entries at index " << entry_idx << " start at unaligned offset.";
       return false;
     }
 
     // Each entry is sizeof(ResTable_map) big.
     if (map_entry_count > ((chunk_size - map_entries_start) / sizeof(ResTable_map))) {
-      LOG(ERROR) << "Too many map entries in ResTable_map_entry at offset " << entry_offset << ".";
+      LOG(ERROR) << "Too many map entries in ResTable_map_entry at index " << entry_idx << ".";
       return false;
     }
   }
   return true;
 }
 
-const ResTable_entry* LoadedPackage::GetEntry(const ResTable_type* type_chunk,
-                                              uint16_t entry_index) {
-  uint32_t entry_offset = GetEntryOffset(type_chunk, entry_index);
-  if (entry_offset == ResTable_type::NO_ENTRY) {
-    return nullptr;
-  }
-  return GetEntryFromOffset(type_chunk, entry_offset);
-}
+bool LoadedPackage::FindEntry(const TypeSpecPtr& type_spec_ptr, uint16_t entry_idx,
+                              const ResTable_config& config, FindEntryResult* out_entry) const {
+  const ResTable_config* best_config = nullptr;
+  const ResTable_type* best_type = nullptr;
+  uint32_t best_offset = 0;
 
-uint32_t LoadedPackage::GetEntryOffset(const ResTable_type* type_chunk, uint16_t entry_index) {
-  // The configuration matches and is better than the previous selection.
-  // Find the entry value if it exists for this configuration.
-  const size_t entry_count = dtohl(type_chunk->entryCount);
-  const size_t offsets_offset = dtohs(type_chunk->header.headerSize);
+  for (uint32_t i = 0; i < type_spec_ptr->type_count; i++) {
+    const Type* type = &type_spec_ptr->types[i];
+    const ResTable_type* type_chunk = type->type;
 
-  // Check if there is the desired entry in this type.
+    if (type->configuration.match(config) &&
+        (best_config == nullptr || type->configuration.isBetterThan(*best_config, &config))) {
+      // The configuration matches and is better than the previous selection.
+      // Find the entry value if it exists for this configuration.
+      const size_t entry_count = dtohl(type_chunk->entryCount);
+      const size_t offsets_offset = dtohs(type_chunk->header.headerSize);
 
-  if (type_chunk->flags & ResTable_type::FLAG_SPARSE) {
-    // This is encoded as a sparse map, so perform a binary search.
-    const ResTable_sparseTypeEntry* sparse_indices =
-        reinterpret_cast<const ResTable_sparseTypeEntry*>(
+      // Check if there is the desired entry in this type.
+
+      if (type_chunk->flags & ResTable_type::FLAG_SPARSE) {
+        // This is encoded as a sparse map, so perform a binary search.
+        const ResTable_sparseTypeEntry* sparse_indices =
+            reinterpret_cast<const ResTable_sparseTypeEntry*>(
+                reinterpret_cast<const uint8_t*>(type_chunk) + offsets_offset);
+        const ResTable_sparseTypeEntry* sparse_indices_end = sparse_indices + entry_count;
+        const ResTable_sparseTypeEntry* result =
+            std::lower_bound(sparse_indices, sparse_indices_end, entry_idx,
+                             [](const ResTable_sparseTypeEntry& entry, uint16_t entry_idx) {
+                               return dtohs(entry.idx) < entry_idx;
+                             });
+
+        if (result == sparse_indices_end || dtohs(result->idx) != entry_idx) {
+          // No entry found.
+          continue;
+        }
+
+        // Extract the offset from the entry. Each offset must be a multiple of 4 so we store it as
+        // the real offset divided by 4.
+        best_offset = uint32_t{dtohs(result->offset)} * 4u;
+      } else {
+        if (entry_idx >= entry_count) {
+          // This entry cannot be here.
+          continue;
+        }
+
+        const uint32_t* entry_offsets = reinterpret_cast<const uint32_t*>(
             reinterpret_cast<const uint8_t*>(type_chunk) + offsets_offset);
-    const ResTable_sparseTypeEntry* sparse_indices_end = sparse_indices + entry_count;
-    const ResTable_sparseTypeEntry* result =
-        std::lower_bound(sparse_indices, sparse_indices_end, entry_index,
-                         [](const ResTable_sparseTypeEntry& entry, uint16_t entry_idx) {
-                           return dtohs(entry.idx) < entry_idx;
-                         });
+        const uint32_t offset = dtohl(entry_offsets[entry_idx]);
+        if (offset == ResTable_type::NO_ENTRY) {
+          continue;
+        }
 
-    if (result == sparse_indices_end || dtohs(result->idx) != entry_index) {
-      // No entry found.
-      return ResTable_type::NO_ENTRY;
+        // There is an entry for this resource, record it.
+        best_offset = offset;
+      }
+
+      best_config = &type->configuration;
+      best_type = type_chunk;
     }
-
-    // Extract the offset from the entry. Each offset must be a multiple of 4 so we store it as
-    // the real offset divided by 4.
-    return uint32_t{dtohs(result->offset)} * 4u;
   }
 
-  // This type is encoded as a dense array.
-  if (entry_index >= entry_count) {
-    // This entry cannot be here.
-    return ResTable_type::NO_ENTRY;
+  if (best_type == nullptr) {
+    return false;
   }
 
-  const uint32_t* entry_offsets = reinterpret_cast<const uint32_t*>(
-      reinterpret_cast<const uint8_t*>(type_chunk) + offsets_offset);
-  return dtohl(entry_offsets[entry_index]);
+  if (UNLIKELY(!VerifyResTableEntry(best_type, best_offset, entry_idx))) {
+    return false;
+  }
+
+  const ResTable_entry* best_entry = reinterpret_cast<const ResTable_entry*>(
+      reinterpret_cast<const uint8_t*>(best_type) + best_offset + dtohl(best_type->entriesStart));
+
+  const uint32_t* flags = reinterpret_cast<const uint32_t*>(type_spec_ptr->type_spec + 1);
+  out_entry->type_flags = dtohl(flags[entry_idx]);
+  out_entry->entry = best_entry;
+  out_entry->config = best_config;
+  out_entry->type_string_ref = StringPoolRef(&type_string_pool_, best_type->id - 1);
+  out_entry->entry_string_ref = StringPoolRef(&key_string_pool_, dtohl(best_entry->key.index));
+  return true;
 }
 
-const ResTable_entry* LoadedPackage::GetEntryFromOffset(const ResTable_type* type_chunk,
-                                                        uint32_t offset) {
-  if (UNLIKELY(!VerifyResTableEntry(type_chunk, offset))) {
-    return nullptr;
+bool LoadedPackage::FindEntry(uint8_t type_idx, uint16_t entry_idx, const ResTable_config& config,
+                              FindEntryResult* out_entry) const {
+  ATRACE_CALL();
+
+  // If the type IDs are offset in this package, we need to take that into account when searching
+  // for a type.
+  const TypeSpecPtr& ptr = type_specs_[type_idx - type_id_offset_];
+  if (UNLIKELY(ptr == nullptr)) {
+    return false;
   }
-  return reinterpret_cast<const ResTable_entry*>(reinterpret_cast<const uint8_t*>(type_chunk) +
-                                                 offset + dtohl(type_chunk->entriesStart));
+
+  // If there is an IDMAP supplied with this package, translate the entry ID.
+  if (ptr->idmap_entries != nullptr) {
+    if (!LoadedIdmap::Lookup(ptr->idmap_entries, entry_idx, &entry_idx)) {
+      // There is no mapping, so the resource is not meant to be in this overlay package.
+      return false;
+    }
+  }
+  return FindEntry(ptr, entry_idx, config, out_entry);
 }
 
 void LoadedPackage::CollectConfigurations(bool exclude_mipmap,
@@ -267,7 +348,7 @@
   const static std::u16string kMipMap = u"mipmap";
   const size_t type_count = type_specs_.size();
   for (size_t i = 0; i < type_count; i++) {
-    const TypeSpecPtr& type_spec = type_specs_[i];
+    const util::unique_cptr<TypeSpec>& type_spec = type_specs_[i];
     if (type_spec != nullptr) {
       if (exclude_mipmap) {
         const int type_idx = type_spec->type_spec->id - 1;
@@ -288,11 +369,8 @@
         }
       }
 
-      const auto iter_end = type_spec->types + type_spec->type_count;
-      for (auto iter = type_spec->types; iter != iter_end; ++iter) {
-        ResTable_config config;
-        config.copyFromDtoH((*iter)->config);
-        out_configs->insert(config);
+      for (size_t j = 0; j < type_spec->type_count; j++) {
+        out_configs->insert(type_spec->types[j].configuration);
       }
     }
   }
@@ -302,12 +380,10 @@
   char temp_locale[RESTABLE_MAX_LOCALE_LEN];
   const size_t type_count = type_specs_.size();
   for (size_t i = 0; i < type_count; i++) {
-    const TypeSpecPtr& type_spec = type_specs_[i];
+    const util::unique_cptr<TypeSpec>& type_spec = type_specs_[i];
     if (type_spec != nullptr) {
-      const auto iter_end = type_spec->types + type_spec->type_count;
-      for (auto iter = type_spec->types; iter != iter_end; ++iter) {
-        ResTable_config configuration;
-        configuration.copyFromDtoH((*iter)->config);
+      for (size_t j = 0; j < type_spec->type_count; j++) {
+        const ResTable_config& configuration = type_spec->types[j].configuration;
         if (configuration.locale != 0) {
           configuration.getBcp47Locale(temp_locale, canonicalize);
           std::string locale(temp_locale);
@@ -335,17 +411,17 @@
     return 0u;
   }
 
-  const auto iter_end = type_spec->types + type_spec->type_count;
-  for (auto iter = type_spec->types; iter != iter_end; ++iter) {
-    const ResTable_type* type = *iter;
-    size_t entry_count = dtohl(type->entryCount);
+  for (size_t ti = 0; ti < type_spec->type_count; ti++) {
+    const Type* type = &type_spec->types[ti];
+    size_t entry_count = dtohl(type->type->entryCount);
     for (size_t entry_idx = 0; entry_idx < entry_count; entry_idx++) {
       const uint32_t* entry_offsets = reinterpret_cast<const uint32_t*>(
-          reinterpret_cast<const uint8_t*>(type) + dtohs(type->header.headerSize));
+          reinterpret_cast<const uint8_t*>(type->type) + dtohs(type->type->header.headerSize));
       const uint32_t offset = dtohl(entry_offsets[entry_idx]);
       if (offset != ResTable_type::NO_ENTRY) {
-        const ResTable_entry* entry = reinterpret_cast<const ResTable_entry*>(
-            reinterpret_cast<const uint8_t*>(type) + dtohl(type->entriesStart) + offset);
+        const ResTable_entry* entry =
+            reinterpret_cast<const ResTable_entry*>(reinterpret_cast<const uint8_t*>(type->type) +
+                                                    dtohl(type->type->entriesStart) + offset);
         if (dtohl(entry->key.index) == static_cast<uint32_t>(key_idx)) {
           // The package ID will be overridden by the caller (due to runtime assignment of package
           // IDs for shared libraries).
@@ -357,7 +433,8 @@
   return 0u;
 }
 
-const LoadedPackage* LoadedArsc::GetPackageById(uint8_t package_id) const {
+const LoadedPackage* LoadedArsc::GetPackageForId(uint32_t resid) const {
+  const uint8_t package_id = get_package_id(resid);
   for (const auto& loaded_package : packages_) {
     if (loaded_package->GetPackageId() == package_id) {
       return loaded_package.get();
@@ -605,6 +682,26 @@
   return std::move(loaded_package);
 }
 
+bool LoadedArsc::FindEntry(uint32_t resid, const ResTable_config& config,
+                           FindEntryResult* out_entry) const {
+  ATRACE_CALL();
+
+  const uint8_t package_id = get_package_id(resid);
+  const uint8_t type_id = get_type_id(resid);
+  const uint16_t entry_id = get_entry_id(resid);
+
+  if (UNLIKELY(type_id == 0)) {
+    LOG(ERROR) << base::StringPrintf("Invalid ID 0x%08x.", resid);
+    return false;
+  }
+
+  for (const auto& loaded_package : packages_) {
+    if (loaded_package->GetPackageId() == package_id) {
+      return loaded_package->FindEntry(type_id - 1, entry_id, config, out_entry);
+    }
+  }
+  return false;
+}
 
 bool LoadedArsc::LoadTable(const Chunk& chunk, const LoadedIdmap* loaded_idmap,
                            bool load_as_shared_library) {
diff --git a/libs/androidfw/include/androidfw/AssetManager.h b/libs/androidfw/include/androidfw/AssetManager.h
index ecc5dc1..08da731 100644
--- a/libs/androidfw/include/androidfw/AssetManager.h
+++ b/libs/androidfw/include/androidfw/AssetManager.h
@@ -60,6 +60,7 @@
     static const char* RESOURCES_FILENAME;
     static const char* IDMAP_BIN;
     static const char* OVERLAY_DIR;
+    static const char* PRODUCT_OVERLAY_DIR;
     /*
      * If OVERLAY_THEME_DIR_PROPERTY is set, search for runtime resource overlay
      * APKs in OVERLAY_DIR/<value of OVERLAY_THEME_DIR_PROPERTY> in addition to
diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h
index ef08897..b033137 100644
--- a/libs/androidfw/include/androidfw/AssetManager2.h
+++ b/libs/androidfw/include/androidfw/AssetManager2.h
@@ -69,8 +69,6 @@
   Entry entries[0];
 };
 
-struct FindEntryResult;
-
 // AssetManager2 is the main entry point for accessing assets and resources.
 // AssetManager2 provides caching of resources retrieved via the underlying ApkAssets.
 class AssetManager2 {
@@ -129,7 +127,7 @@
   // If `exclude_mipmap` is set to true, resource configurations defined for resource type 'mipmap'
   // will be excluded from the list.
   std::set<ResTable_config> GetResourceConfigurations(bool exclude_system = false,
-                                                      bool exclude_mipmap = false) const;
+                                                      bool exclude_mipmap = false);
 
   // Returns all the locales for which there are resources defined. This includes resource
   // locales in all the ApkAssets set for this AssetManager.
@@ -138,24 +136,24 @@
   // If `merge_equivalent_languages` is set to true, resource locales will be canonicalized
   // and de-duped in the resulting list.
   std::set<std::string> GetResourceLocales(bool exclude_system = false,
-                                           bool merge_equivalent_languages = false) const;
+                                           bool merge_equivalent_languages = false);
 
   // Searches the set of APKs loaded by this AssetManager and opens the first one found located
   // in the assets/ directory.
   // `mode` controls how the file is opened.
   //
   // NOTE: The loaded APKs are searched in reverse order.
-  std::unique_ptr<Asset> Open(const std::string& filename, Asset::AccessMode mode) const;
+  std::unique_ptr<Asset> Open(const std::string& filename, Asset::AccessMode mode);
 
   // Opens a file within the assets/ directory of the APK specified by `cookie`.
   // `mode` controls how the file is opened.
   std::unique_ptr<Asset> Open(const std::string& filename, ApkAssetsCookie cookie,
-                              Asset::AccessMode mode) const;
+                              Asset::AccessMode mode);
 
   // Opens the directory specified by `dirname`. The result is an AssetDir that is the combination
   // of all directories matching `dirname` under the assets/ directory of every ApkAssets loaded.
   // The entries are sorted by their ASCII name.
-  std::unique_ptr<AssetDir> OpenDir(const std::string& dirname) const;
+  std::unique_ptr<AssetDir> OpenDir(const std::string& dirname);
 
   // Searches the set of APKs loaded by this AssetManager and opens the first one found.
   // `mode` controls how the file is opened.
@@ -163,24 +161,24 @@
   //
   // NOTE: The loaded APKs are searched in reverse order.
   std::unique_ptr<Asset> OpenNonAsset(const std::string& filename, Asset::AccessMode mode,
-                                      ApkAssetsCookie* out_cookie = nullptr) const;
+                                      ApkAssetsCookie* out_cookie = nullptr);
 
   // Opens a file in the APK specified by `cookie`. `mode` controls how the file is opened.
   // This is typically used to open a specific AndroidManifest.xml, or a binary XML file
   // referenced by a resource lookup with GetResource().
   std::unique_ptr<Asset> OpenNonAsset(const std::string& filename, ApkAssetsCookie cookie,
-                                      Asset::AccessMode mode) const;
+                                      Asset::AccessMode mode);
 
   // Populates the `out_name` parameter with resource name information.
   // Utf8 strings are preferred, and only if they are unavailable are
   // the Utf16 variants populated.
   // Returns false if the resource was not found or the name was missing/corrupt.
-  bool GetResourceName(uint32_t resid, ResourceName* out_name) const;
+  bool GetResourceName(uint32_t resid, ResourceName* out_name);
 
   // Populates `out_flags` with the bitmask of configuration axis that this resource varies with.
   // See ResTable_config for the list of configuration axis.
   // Returns false if the resource was not found.
-  bool GetResourceFlags(uint32_t resid, uint32_t* out_flags) const;
+  bool GetResourceFlags(uint32_t resid, uint32_t* out_flags);
 
   // Finds the resource ID assigned to `resource_name`.
   // `resource_name` must be of the form '[package:][type/]entry'.
@@ -188,7 +186,7 @@
   // If no type is specified in `resource_name`, then `fallback_type` is used as the type.
   // Returns 0x0 if no resource by that name was found.
   uint32_t GetResourceId(const std::string& resource_name, const std::string& fallback_type = {},
-                         const std::string& fallback_package = {}) const;
+                         const std::string& fallback_package = {});
 
   // Retrieves the best matching resource with ID `resid`. The resource value is filled into
   // `out_value` and the configuration for the selected value is populated in `out_selected_config`.
@@ -201,7 +199,7 @@
   // this function logs if the resource was a map/bag type before returning kInvalidCookie.
   ApkAssetsCookie GetResource(uint32_t resid, bool may_be_bag, uint16_t density_override,
                               Res_value* out_value, ResTable_config* out_selected_config,
-                              uint32_t* out_flags) const;
+                              uint32_t* out_flags);
 
   // Resolves the resource reference in `in_out_value` if the data type is
   // Res_value::TYPE_REFERENCE.
@@ -217,7 +215,7 @@
   // it was not found.
   ApkAssetsCookie ResolveReference(ApkAssetsCookie cookie, Res_value* in_out_value,
                                    ResTable_config* in_out_selected_config, uint32_t* in_out_flags,
-                                   uint32_t* out_last_reference) const;
+                                   uint32_t* out_last_reference);
 
   // Retrieves the best matching bag/map resource with ID `resid`.
   // This method will resolve all parent references for this bag and merge keys with the child.
@@ -235,9 +233,9 @@
   std::unique_ptr<Theme> NewTheme();
 
   template <typename Func>
-  void ForEachPackage(Func func) const {
+  void ForEachPackage(Func func) {
     for (const PackageGroup& package_group : package_groups_) {
-      func(package_group.packages_.front().loaded_package_->GetPackageName(),
+      func(package_group.packages_.front()->GetPackageName(),
            package_group.dynamic_ref_table.mAssignedPackageId);
     }
   }
@@ -262,7 +260,7 @@
   // NOTE: FindEntry takes care of ensuring that structs within FindEntryResult have been properly
   // bounds-checked. Callers of FindEntry are free to trust the data if this method succeeds.
   ApkAssetsCookie FindEntry(uint32_t resid, uint16_t density_override, bool stop_at_first_match,
-                            FindEntryResult* out_entry) const;
+                            FindEntryResult* out_entry);
 
   // Assigns package IDs to all shared library ApkAssets.
   // Should be called whenever the ApkAssets are changed.
@@ -272,43 +270,13 @@
   // bitmask `diff`.
   void InvalidateCaches(uint32_t diff);
 
-  // Triggers the re-construction of lists of types that match the set configuration.
-  // This should always be called when mutating the AssetManager's configuration or ApkAssets set.
-  void RebuildFilterList();
-
   // The ordered list of ApkAssets to search. These are not owned by the AssetManager, and must
   // have a longer lifetime.
   std::vector<const ApkAssets*> apk_assets_;
 
-  // A collection of configurations and their associated ResTable_type that match the current
-  // AssetManager configuration.
-  struct FilteredConfigGroup {
-    std::vector<ResTable_config> configurations;
-    std::vector<const ResTable_type*> types;
-  };
-
-  // Represents an single package.
-  struct ConfiguredPackage {
-    // A pointer to the immutable, loaded package info.
-    const LoadedPackage* loaded_package_;
-
-    // A mutable AssetManager-specific list of configurations that match the AssetManager's
-    // current configuration. This is used as an optimization to avoid checking every single
-    // candidate configuration when looking up resources.
-    ByteBucketArray<FilteredConfigGroup> filtered_configs_;
-  };
-
-  // Represents a logical package, which can be made up of many individual packages. Each package
-  // in a PackageGroup shares the same package name and package ID.
   struct PackageGroup {
-    // The set of packages that make-up this group.
-    std::vector<ConfiguredPackage> packages_;
-
-    // The cookies associated with each package in the group. They share the same order as
-    // packages_.
+    std::vector<const LoadedPackage*> packages_;
     std::vector<ApkAssetsCookie> cookies_;
-
-    // A library reference table that contains build-package ID to runtime-package ID mappings.
     DynamicRefTable dynamic_ref_table;
   };
 
@@ -382,7 +350,7 @@
   ApkAssetsCookie ResolveAttributeReference(ApkAssetsCookie cookie, Res_value* in_out_value,
                                             ResTable_config* in_out_selected_config = nullptr,
                                             uint32_t* in_out_type_spec_flags = nullptr,
-                                            uint32_t* out_last_ref = nullptr) const;
+                                            uint32_t* out_last_ref = nullptr);
 
  private:
   DISALLOW_COPY_AND_ASSIGN(Theme);
diff --git a/libs/androidfw/include/androidfw/AttributeFinder.h b/libs/androidfw/include/androidfw/AttributeFinder.h
index 03fad49..f281921 100644
--- a/libs/androidfw/include/androidfw/AttributeFinder.h
+++ b/libs/androidfw/include/androidfw/AttributeFinder.h
@@ -58,7 +58,6 @@
   BackTrackingAttributeFinder(const Iterator& begin, const Iterator& end);
 
   Iterator Find(uint32_t attr);
-  inline Iterator end();
 
  private:
   void JumpToClosestAttribute(uint32_t package_id);
@@ -202,11 +201,6 @@
   return end_;
 }
 
-template <typename Derived, typename Iterator>
-Iterator BackTrackingAttributeFinder<Derived, Iterator>::end() {
-  return end_;
-}
-
 }  // namespace android
 
 #endif  // ANDROIDFW_ATTRIBUTE_FINDER_H
diff --git a/libs/androidfw/include/androidfw/AttributeResolution.h b/libs/androidfw/include/androidfw/AttributeResolution.h
index 35ef98d..69b76041 100644
--- a/libs/androidfw/include/androidfw/AttributeResolution.h
+++ b/libs/androidfw/include/androidfw/AttributeResolution.h
@@ -17,8 +17,7 @@
 #ifndef ANDROIDFW_ATTRIBUTERESOLUTION_H
 #define ANDROIDFW_ATTRIBUTERESOLUTION_H
 
-#include "androidfw/AssetManager2.h"
-#include "androidfw/ResourceTypes.h"
+#include <androidfw/ResourceTypes.h>
 
 namespace android {
 
@@ -43,19 +42,19 @@
 
 // `out_values` must NOT be nullptr.
 // `out_indices` may be nullptr.
-bool ResolveAttrs(Theme* theme, uint32_t def_style_attr, uint32_t def_style_resid,
+bool ResolveAttrs(ResTable::Theme* theme, uint32_t def_style_attr, uint32_t def_style_res,
                   uint32_t* src_values, size_t src_values_length, uint32_t* attrs,
                   size_t attrs_length, uint32_t* out_values, uint32_t* out_indices);
 
 // `out_values` must NOT be nullptr.
 // `out_indices` is NOT optional and must NOT be nullptr.
-void ApplyStyle(Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr,
-                uint32_t def_style_resid, const uint32_t* attrs, size_t attrs_length,
+void ApplyStyle(ResTable::Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr,
+                uint32_t def_style_res, const uint32_t* attrs, size_t attrs_length,
                 uint32_t* out_values, uint32_t* out_indices);
 
 // `out_values` must NOT be nullptr.
 // `out_indices` may be nullptr.
-bool RetrieveAttributes(AssetManager2* assetmanager, ResXMLParser* xml_parser, uint32_t* attrs,
+bool RetrieveAttributes(const ResTable* res, ResXMLParser* xml_parser, uint32_t* attrs,
                         size_t attrs_length, uint32_t* out_values, uint32_t* out_indices);
 
 }  // namespace android
diff --git a/libs/androidfw/include/androidfw/LoadedArsc.h b/libs/androidfw/include/androidfw/LoadedArsc.h
index 35ae5fc..965e2db 100644
--- a/libs/androidfw/include/androidfw/LoadedArsc.h
+++ b/libs/androidfw/include/androidfw/LoadedArsc.h
@@ -41,40 +41,32 @@
   int package_id = 0;
 };
 
-// TypeSpec is going to be immediately proceeded by
-// an array of Type structs, all in the same block of memory.
-struct TypeSpec {
-  // Pointer to the mmapped data where flags are kept.
-  // Flags denote whether the resource entry is public
-  // and under which configurations it varies.
-  const ResTable_typeSpec* type_spec;
+struct FindEntryResult {
+  // A pointer to the resource table entry for this resource.
+  // If the size of the entry is > sizeof(ResTable_entry), it can be cast to
+  // a ResTable_map_entry and processed as a bag/map.
+  const ResTable_entry* entry = nullptr;
 
-  // Pointer to the mmapped data where the IDMAP mappings for this type
-  // exist. May be nullptr if no IDMAP exists.
-  const IdmapEntry_header* idmap_entries;
+  // The configuration for which the resulting entry was defined.
+  const ResTable_config* config = nullptr;
 
-  // The number of types that follow this struct.
-  // There is a type for each configuration that entries are defined for.
-  size_t type_count;
+  // Stores the resulting bitmask of configuration axis with which the resource value varies.
+  uint32_t type_flags = 0u;
 
-  // Trick to easily access a variable number of Type structs
-  // proceeding this struct, and to ensure their alignment.
-  const ResTable_type* types[0];
+  // The dynamic package ID map for the package from which this resource came from.
+  const DynamicRefTable* dynamic_ref_table = nullptr;
 
-  inline uint32_t GetFlagsForEntryIndex(uint16_t entry_index) const {
-    if (entry_index >= dtohl(type_spec->entryCount)) {
-      return 0u;
-    }
+  // The string pool reference to the type's name. This uses a different string pool than
+  // the global string pool, but this is hidden from the caller.
+  StringPoolRef type_string_ref;
 
-    const uint32_t* flags = reinterpret_cast<const uint32_t*>(type_spec + 1);
-    return flags[entry_index];
-  }
+  // The string pool reference to the entry's name. This uses a different string pool than
+  // the global string pool, but this is hidden from the caller.
+  StringPoolRef entry_string_ref;
 };
 
-// TypeSpecPtr points to a block of memory that holds a TypeSpec struct, followed by an array of
-// ResTable_type pointers.
-// TypeSpecPtr is a managed pointer that knows how to delete itself.
-using TypeSpecPtr = util::unique_cptr<TypeSpec>;
+struct TypeSpec;
+class LoadedArsc;
 
 class LoadedPackage {
  public:
@@ -84,6 +76,9 @@
 
   ~LoadedPackage();
 
+  bool FindEntry(uint8_t type_idx, uint16_t entry_idx, const ResTable_config& config,
+                 FindEntryResult* out_entry) const;
+
   // Finds the entry with the specified type name and entry name. The names are in UTF-16 because
   // the underlying ResStringPool API expects this. For now this is acceptable, but since
   // the default policy in AAPT2 is to build UTF-8 string pools, this needs to change.
@@ -91,12 +86,6 @@
   // for patching the correct package ID to the resource ID.
   uint32_t FindEntryByName(const std::u16string& type_name, const std::u16string& entry_name) const;
 
-  static const ResTable_entry* GetEntry(const ResTable_type* type_chunk, uint16_t entry_index);
-
-  static uint32_t GetEntryOffset(const ResTable_type* type_chunk, uint16_t entry_index);
-
-  static const ResTable_entry* GetEntryFromOffset(const ResTable_type* type_chunk, uint32_t offset);
-
   // Returns the string pool where type names are stored.
   inline const ResStringPool* GetTypeStringPool() const {
     return &type_string_pool_;
@@ -146,32 +135,14 @@
   // before being inserted into the set. This may cause some equivalent locales to de-dupe.
   void CollectLocales(bool canonicalize, std::set<std::string>* out_locales) const;
 
-  // type_idx is TT - 1 from 0xPPTTEEEE.
-  inline const TypeSpec* GetTypeSpecByTypeIndex(uint8_t type_index) const {
-    // If the type IDs are offset in this package, we need to take that into account when searching
-    // for a type.
-    return type_specs_[type_index - type_id_offset_].get();
-  }
-
-  template <typename Func>
-  void ForEachTypeSpec(Func f) const {
-    for (size_t i = 0; i < type_specs_.size(); i++) {
-      const TypeSpecPtr& ptr = type_specs_[i];
-      if (ptr != nullptr) {
-        uint8_t type_id = ptr->type_spec->id;
-        if (ptr->idmap_entries != nullptr) {
-          type_id = ptr->idmap_entries->target_type_id;
-        }
-        f(ptr.get(), type_id - 1);
-      }
-    }
-  }
-
  private:
   DISALLOW_COPY_AND_ASSIGN(LoadedPackage);
 
   LoadedPackage();
 
+  bool FindEntry(const util::unique_cptr<TypeSpec>& type_spec_ptr, uint16_t entry_idx,
+                 const ResTable_config& config, FindEntryResult* out_entry) const;
+
   ResStringPool type_string_pool_;
   ResStringPool key_string_pool_;
   std::string package_name_;
@@ -181,7 +152,7 @@
   bool system_ = false;
   bool overlay_ = false;
 
-  ByteBucketArray<TypeSpecPtr> type_specs_;
+  ByteBucketArray<util::unique_cptr<TypeSpec>> type_specs_;
   std::vector<DynamicPackageEntry> dynamic_package_map_;
 };
 
@@ -209,20 +180,25 @@
     return &global_string_pool_;
   }
 
-  // Gets a pointer to the package with the specified package ID, or nullptr if no such package
-  // exists.
-  const LoadedPackage* GetPackageById(uint8_t package_id) const;
+  // Finds the resource with ID `resid` with the best value for configuration `config`.
+  // The parameter `out_entry` will be filled with the resulting resource entry.
+  // The resource entry can be a simple entry (ResTable_entry) or a complex bag
+  // (ResTable_entry_map).
+  bool FindEntry(uint32_t resid, const ResTable_config& config, FindEntryResult* out_entry) const;
 
-  // Returns a vector of LoadedPackage pointers, representing the packages in this LoadedArsc.
-  inline const std::vector<std::unique_ptr<const LoadedPackage>>& GetPackages() const {
-    return packages_;
-  }
+  // Gets a pointer to the name of the package in `resid`, or nullptr if the package doesn't exist.
+  const LoadedPackage* GetPackageForId(uint32_t resid) const;
 
   // Returns true if this is a system provided resource.
   inline bool IsSystem() const {
     return system_;
   }
 
+  // Returns a vector of LoadedPackage pointers, representing the packages in this LoadedArsc.
+  inline const std::vector<std::unique_ptr<const LoadedPackage>>& GetPackages() const {
+    return packages_;
+  }
+
  private:
   DISALLOW_COPY_AND_ASSIGN(LoadedArsc);
 
diff --git a/libs/androidfw/include/androidfw/MutexGuard.h b/libs/androidfw/include/androidfw/MutexGuard.h
deleted file mode 100644
index 64924f4..0000000
--- a/libs/androidfw/include/androidfw/MutexGuard.h
+++ /dev/null
@@ -1,101 +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.
- */
-
-#ifndef ANDROIDFW_MUTEXGUARD_H
-#define ANDROIDFW_MUTEXGUARD_H
-
-#include <mutex>
-#include <type_traits>
-
-#include "android-base/macros.h"
-
-namespace android {
-
-template <typename T>
-class ScopedLock;
-
-// Owns the guarded object and protects access to it via a mutex.
-// The guarded object is inaccessible via this class.
-// The mutex is locked and the object accessed via the ScopedLock<T> class.
-//
-// NOTE: The template parameter T should not be a raw pointer, since ownership
-// is ambiguous and error-prone. Instead use an std::unique_ptr<>.
-//
-// Example use:
-//
-//   Guarded<std::string> shared_string("hello");
-//   {
-//     ScopedLock<std::string> locked_string(shared_string);
-//     *locked_string += " world";
-//   }
-//
-template <typename T>
-class Guarded {
-  static_assert(!std::is_pointer<T>::value, "T must not be a raw pointer");
-
- public:
-  explicit Guarded() : guarded_() {
-  }
-
-  template <typename U = T>
-  explicit Guarded(const T& guarded,
-                   typename std::enable_if<std::is_copy_constructible<U>::value>::type = void())
-      : guarded_(guarded) {
-  }
-
-  template <typename U = T>
-  explicit Guarded(T&& guarded,
-                   typename std::enable_if<std::is_move_constructible<U>::value>::type = void())
-      : guarded_(std::move(guarded)) {
-  }
-
- private:
-  friend class ScopedLock<T>;
-
-  DISALLOW_COPY_AND_ASSIGN(Guarded);
-
-  std::mutex lock_;
-  T guarded_;
-};
-
-template <typename T>
-class ScopedLock {
- public:
-  explicit ScopedLock(Guarded<T>& guarded) : lock_(guarded.lock_), guarded_(guarded.guarded_) {
-  }
-
-  T& operator*() {
-    return guarded_;
-  }
-
-  T* operator->() {
-    return &guarded_;
-  }
-
-  T* get() {
-    return &guarded_;
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(ScopedLock);
-
-  std::lock_guard<std::mutex> lock_;
-  T& guarded_;
-};
-
-}  // namespace android
-
-#endif  // ANDROIDFW_MUTEXGUARD_H
diff --git a/libs/androidfw/tests/ApkAssets_test.cpp b/libs/androidfw/tests/ApkAssets_test.cpp
index e2b9f00..6c43a67 100644
--- a/libs/androidfw/tests/ApkAssets_test.cpp
+++ b/libs/androidfw/tests/ApkAssets_test.cpp
@@ -26,56 +26,58 @@
 
 using ::android::base::unique_fd;
 using ::com::android::basic::R;
-using ::testing::Eq;
-using ::testing::Ge;
-using ::testing::NotNull;
-using ::testing::SizeIs;
-using ::testing::StrEq;
 
 namespace android {
 
 TEST(ApkAssetsTest, LoadApk) {
   std::unique_ptr<const ApkAssets> loaded_apk =
       ApkAssets::Load(GetTestDataPath() + "/basic/basic.apk");
-  ASSERT_THAT(loaded_apk, NotNull());
+  ASSERT_NE(nullptr, loaded_apk);
 
   const LoadedArsc* loaded_arsc = loaded_apk->GetLoadedArsc();
-  ASSERT_THAT(loaded_arsc, NotNull());
-  ASSERT_THAT(loaded_arsc->GetPackageById(0x7fu), NotNull());
-  ASSERT_THAT(loaded_apk->Open("res/layout/main.xml"), NotNull());
+  ASSERT_NE(nullptr, loaded_arsc);
+
+  const LoadedPackage* loaded_package = loaded_arsc->GetPackageForId(0x7f010000);
+  ASSERT_NE(nullptr, loaded_package);
+
+  std::unique_ptr<Asset> asset = loaded_apk->Open("res/layout/main.xml");
+  ASSERT_NE(nullptr, asset);
 }
 
 TEST(ApkAssetsTest, LoadApkFromFd) {
   const std::string path = GetTestDataPath() + "/basic/basic.apk";
   unique_fd fd(::open(path.c_str(), O_RDONLY | O_BINARY));
-  ASSERT_THAT(fd.get(), Ge(0));
+  ASSERT_GE(fd.get(), 0);
 
   std::unique_ptr<const ApkAssets> loaded_apk =
       ApkAssets::LoadFromFd(std::move(fd), path, false /*system*/, false /*force_shared_lib*/);
-  ASSERT_THAT(loaded_apk, NotNull());
+  ASSERT_NE(nullptr, loaded_apk);
 
   const LoadedArsc* loaded_arsc = loaded_apk->GetLoadedArsc();
-  ASSERT_THAT(loaded_arsc, NotNull());
-  ASSERT_THAT(loaded_arsc->GetPackageById(0x7fu), NotNull());
-  ASSERT_THAT(loaded_apk->Open("res/layout/main.xml"), NotNull());
+  ASSERT_NE(nullptr, loaded_arsc);
+
+  const LoadedPackage* loaded_package = loaded_arsc->GetPackageForId(0x7f010000);
+  ASSERT_NE(nullptr, loaded_package);
+
+  std::unique_ptr<Asset> asset = loaded_apk->Open("res/layout/main.xml");
+  ASSERT_NE(nullptr, asset);
 }
 
 TEST(ApkAssetsTest, LoadApkAsSharedLibrary) {
   std::unique_ptr<const ApkAssets> loaded_apk =
       ApkAssets::Load(GetTestDataPath() + "/appaslib/appaslib.apk");
-  ASSERT_THAT(loaded_apk, NotNull());
-
+  ASSERT_NE(nullptr, loaded_apk);
   const LoadedArsc* loaded_arsc = loaded_apk->GetLoadedArsc();
-  ASSERT_THAT(loaded_arsc, NotNull());
-  ASSERT_THAT(loaded_arsc->GetPackages(), SizeIs(1u));
+  ASSERT_NE(nullptr, loaded_arsc);
+  ASSERT_EQ(1u, loaded_arsc->GetPackages().size());
   EXPECT_FALSE(loaded_arsc->GetPackages()[0]->IsDynamic());
 
   loaded_apk = ApkAssets::LoadAsSharedLibrary(GetTestDataPath() + "/appaslib/appaslib.apk");
-  ASSERT_THAT(loaded_apk, NotNull());
+  ASSERT_NE(nullptr, loaded_apk);
 
   loaded_arsc = loaded_apk->GetLoadedArsc();
-  ASSERT_THAT(loaded_arsc, NotNull());
-  ASSERT_THAT(loaded_arsc->GetPackages(), SizeIs(1u));
+  ASSERT_NE(nullptr, loaded_arsc);
+  ASSERT_EQ(1u, loaded_arsc->GetPackages().size());
   EXPECT_TRUE(loaded_arsc->GetPackages()[0]->IsDynamic());
 }
 
@@ -84,22 +86,19 @@
   ResTable target_table;
   const std::string target_path = GetTestDataPath() + "/basic/basic.apk";
   ASSERT_TRUE(ReadFileFromZipToString(target_path, "resources.arsc", &contents));
-  ASSERT_THAT(target_table.add(contents.data(), contents.size(), 0, true /*copyData*/),
-              Eq(NO_ERROR));
+  ASSERT_EQ(NO_ERROR, target_table.add(contents.data(), contents.size(), 0, true /*copyData*/));
 
   ResTable overlay_table;
   const std::string overlay_path = GetTestDataPath() + "/overlay/overlay.apk";
   ASSERT_TRUE(ReadFileFromZipToString(overlay_path, "resources.arsc", &contents));
-  ASSERT_THAT(overlay_table.add(contents.data(), contents.size(), 0, true /*copyData*/),
-              Eq(NO_ERROR));
+  ASSERT_EQ(NO_ERROR, overlay_table.add(contents.data(), contents.size(), 0, true /*copyData*/));
 
   util::unique_cptr<void> idmap_data;
   void* temp_data;
   size_t idmap_len;
 
-  ASSERT_THAT(target_table.createIdmap(overlay_table, 0u, 0u, target_path.c_str(),
-                                       overlay_path.c_str(), &temp_data, &idmap_len),
-              Eq(NO_ERROR));
+  ASSERT_EQ(NO_ERROR, target_table.createIdmap(overlay_table, 0u, 0u, target_path.c_str(),
+                                               overlay_path.c_str(), &temp_data, &idmap_len));
   idmap_data.reset(temp_data);
 
   TemporaryFile tf;
@@ -109,30 +108,37 @@
   // Open something so that the destructor of TemporaryFile closes a valid fd.
   tf.fd = open("/dev/null", O_WRONLY);
 
-  ASSERT_THAT(ApkAssets::LoadOverlay(tf.path), NotNull());
+  std::unique_ptr<const ApkAssets> loaded_overlay_apk = ApkAssets::LoadOverlay(tf.path);
+  ASSERT_NE(nullptr, loaded_overlay_apk);
 }
 
 TEST(ApkAssetsTest, CreateAndDestroyAssetKeepsApkAssetsOpen) {
   std::unique_ptr<const ApkAssets> loaded_apk =
       ApkAssets::Load(GetTestDataPath() + "/basic/basic.apk");
-  ASSERT_THAT(loaded_apk, NotNull());
+  ASSERT_NE(nullptr, loaded_apk);
 
-  { ASSERT_THAT(loaded_apk->Open("res/layout/main.xml", Asset::ACCESS_BUFFER), NotNull()); }
+  {
+    std::unique_ptr<Asset> assets = loaded_apk->Open("res/layout/main.xml", Asset::ACCESS_BUFFER);
+    ASSERT_NE(nullptr, assets);
+  }
 
-  { ASSERT_THAT(loaded_apk->Open("res/layout/main.xml", Asset::ACCESS_BUFFER), NotNull()); }
+  {
+    std::unique_ptr<Asset> assets = loaded_apk->Open("res/layout/main.xml", Asset::ACCESS_BUFFER);
+    ASSERT_NE(nullptr, assets);
+  }
 }
 
 TEST(ApkAssetsTest, OpenUncompressedAssetFd) {
   std::unique_ptr<const ApkAssets> loaded_apk =
       ApkAssets::Load(GetTestDataPath() + "/basic/basic.apk");
-  ASSERT_THAT(loaded_apk, NotNull());
+  ASSERT_NE(nullptr, loaded_apk);
 
   auto asset = loaded_apk->Open("assets/uncompressed.txt", Asset::ACCESS_UNKNOWN);
-  ASSERT_THAT(asset, NotNull());
+  ASSERT_NE(nullptr, asset);
 
   off64_t start, length;
   unique_fd fd(asset->openFileDescriptor(&start, &length));
-  ASSERT_THAT(fd.get(), Ge(0));
+  EXPECT_GE(fd.get(), 0);
 
   lseek64(fd.get(), start, SEEK_SET);
 
@@ -140,7 +146,7 @@
   buffer.resize(length);
   ASSERT_TRUE(base::ReadFully(fd.get(), &*buffer.begin(), length));
 
-  EXPECT_THAT(buffer, StrEq("This should be uncompressed.\n\n"));
+  EXPECT_EQ("This should be uncompressed.\n\n", buffer);
 }
 
 }  // namespace android
diff --git a/libs/androidfw/tests/AssetManager2_bench.cpp b/libs/androidfw/tests/AssetManager2_bench.cpp
index 437e147..85e8f25 100644
--- a/libs/androidfw/tests/AssetManager2_bench.cpp
+++ b/libs/androidfw/tests/AssetManager2_bench.cpp
@@ -81,18 +81,17 @@
 }
 BENCHMARK(BM_AssetManagerLoadFrameworkAssetsOld);
 
-static void BM_AssetManagerGetResource(benchmark::State& state, uint32_t resid) {
-  GetResourceBenchmark({GetTestDataPath() + "/basic/basic.apk"}, nullptr /*config*/, resid, state);
+static void BM_AssetManagerGetResource(benchmark::State& state) {
+  GetResourceBenchmark({GetTestDataPath() + "/basic/basic.apk"}, nullptr /*config*/,
+                       basic::R::integer::number1, state);
 }
-BENCHMARK_CAPTURE(BM_AssetManagerGetResource, number1, basic::R::integer::number1);
-BENCHMARK_CAPTURE(BM_AssetManagerGetResource, deep_ref, basic::R::integer::deep_ref);
+BENCHMARK(BM_AssetManagerGetResource);
 
-static void BM_AssetManagerGetResourceOld(benchmark::State& state, uint32_t resid) {
-  GetResourceBenchmarkOld({GetTestDataPath() + "/basic/basic.apk"}, nullptr /*config*/, resid,
-                          state);
+static void BM_AssetManagerGetResourceOld(benchmark::State& state) {
+  GetResourceBenchmarkOld({GetTestDataPath() + "/basic/basic.apk"}, nullptr /*config*/,
+                          basic::R::integer::number1, state);
 }
-BENCHMARK_CAPTURE(BM_AssetManagerGetResourceOld, number1, basic::R::integer::number1);
-BENCHMARK_CAPTURE(BM_AssetManagerGetResourceOld, deep_ref, basic::R::integer::deep_ref);
+BENCHMARK(BM_AssetManagerGetResourceOld);
 
 static void BM_AssetManagerGetLibraryResource(benchmark::State& state) {
   GetResourceBenchmark(
@@ -197,7 +196,7 @@
 static void BM_AssetManagerGetResourceLocalesOld(benchmark::State& state) {
   AssetManager assets;
   if (!assets.addAssetPath(String8(kFrameworkPath), nullptr /*cookie*/, false /*appAsLib*/,
-                           true /*isSystemAssets*/)) {
+                           false /*isSystemAssets*/)) {
     state.SkipWithError("Failed to load assets");
     return;
   }
@@ -212,44 +211,4 @@
 }
 BENCHMARK(BM_AssetManagerGetResourceLocalesOld);
 
-static void BM_AssetManagerSetConfigurationFramework(benchmark::State& state) {
-  std::unique_ptr<const ApkAssets> apk = ApkAssets::Load(kFrameworkPath);
-  if (apk == nullptr) {
-    state.SkipWithError("Failed to load assets");
-    return;
-  }
-
-  AssetManager2 assets;
-  assets.SetApkAssets({apk.get()});
-
-  ResTable_config config;
-  memset(&config, 0, sizeof(config));
-
-  while (state.KeepRunning()) {
-    config.sdkVersion = ~config.sdkVersion;
-    assets.SetConfiguration(config);
-  }
-}
-BENCHMARK(BM_AssetManagerSetConfigurationFramework);
-
-static void BM_AssetManagerSetConfigurationFrameworkOld(benchmark::State& state) {
-  AssetManager assets;
-  if (!assets.addAssetPath(String8(kFrameworkPath), nullptr /*cookie*/, false /*appAsLib*/,
-                           true /*isSystemAssets*/)) {
-    state.SkipWithError("Failed to load assets");
-    return;
-  }
-
-  const ResTable& table = assets.getResources(true);
-
-  ResTable_config config;
-  memset(&config, 0, sizeof(config));
-
-  while (state.KeepRunning()) {
-    config.sdkVersion = ~config.sdkVersion;
-    assets.setConfiguration(config);
-  }
-}
-BENCHMARK(BM_AssetManagerSetConfigurationFrameworkOld);
-
 }  // namespace android
diff --git a/libs/androidfw/tests/AttributeResolution_bench.cpp b/libs/androidfw/tests/AttributeResolution_bench.cpp
deleted file mode 100644
index fa300c5..0000000
--- a/libs/androidfw/tests/AttributeResolution_bench.cpp
+++ /dev/null
@@ -1,175 +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 "benchmark/benchmark.h"
-
-//#include "android-base/stringprintf.h"
-#include "androidfw/ApkAssets.h"
-#include "androidfw/AssetManager.h"
-#include "androidfw/AssetManager2.h"
-#include "androidfw/AttributeResolution.h"
-#include "androidfw/ResourceTypes.h"
-
-#include "BenchmarkHelpers.h"
-#include "data/basic/R.h"
-#include "data/styles/R.h"
-
-namespace app = com::android::app;
-namespace basic = com::android::basic;
-
-namespace android {
-
-constexpr const static char* kFrameworkPath = "/system/framework/framework-res.apk";
-constexpr const static uint32_t Theme_Material_Light = 0x01030237u;
-
-static void BM_ApplyStyle(benchmark::State& state) {
-  std::unique_ptr<const ApkAssets> styles_apk =
-      ApkAssets::Load(GetTestDataPath() + "/styles/styles.apk");
-  if (styles_apk == nullptr) {
-    state.SkipWithError("failed to load assets");
-    return;
-  }
-
-  AssetManager2 assetmanager;
-  assetmanager.SetApkAssets({styles_apk.get()});
-
-  std::unique_ptr<Asset> asset =
-      assetmanager.OpenNonAsset("res/layout/layout.xml", Asset::ACCESS_BUFFER);
-  if (asset == nullptr) {
-    state.SkipWithError("failed to load layout");
-    return;
-  }
-
-  ResXMLTree xml_tree;
-  if (xml_tree.setTo(asset->getBuffer(true), asset->getLength(), false /*copyData*/) != NO_ERROR) {
-    state.SkipWithError("corrupt xml layout");
-    return;
-  }
-
-  // Skip to the first tag.
-  while (xml_tree.next() != ResXMLParser::START_TAG) {
-  }
-
-  std::unique_ptr<Theme> theme = assetmanager.NewTheme();
-  theme->ApplyStyle(app::R::style::StyleTwo);
-
-  std::array<uint32_t, 6> attrs{{app::R::attr::attr_one, app::R::attr::attr_two,
-                                 app::R::attr::attr_three, app::R::attr::attr_four,
-                                 app::R::attr::attr_five, app::R::attr::attr_empty}};
-  std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values;
-  std::array<uint32_t, attrs.size() + 1> indices;
-
-  while (state.KeepRunning()) {
-    ApplyStyle(theme.get(), &xml_tree, 0u /*def_style_attr*/, 0u /*def_style_res*/, attrs.data(),
-               attrs.size(), values.data(), indices.data());
-  }
-}
-BENCHMARK(BM_ApplyStyle);
-
-static void BM_ApplyStyleFramework(benchmark::State& state) {
-  std::unique_ptr<const ApkAssets> framework_apk = ApkAssets::Load(kFrameworkPath);
-  if (framework_apk == nullptr) {
-    state.SkipWithError("failed to load framework assets");
-    return;
-  }
-
-  std::unique_ptr<const ApkAssets> basic_apk =
-      ApkAssets::Load(GetTestDataPath() + "/basic/basic.apk");
-  if (basic_apk == nullptr) {
-    state.SkipWithError("failed to load assets");
-    return;
-  }
-
-  AssetManager2 assetmanager;
-  assetmanager.SetApkAssets({framework_apk.get(), basic_apk.get()});
-
-  ResTable_config device_config;
-  memset(&device_config, 0, sizeof(device_config));
-  device_config.language[0] = 'e';
-  device_config.language[1] = 'n';
-  device_config.country[0] = 'U';
-  device_config.country[1] = 'S';
-  device_config.orientation = ResTable_config::ORIENTATION_PORT;
-  device_config.smallestScreenWidthDp = 700;
-  device_config.screenWidthDp = 700;
-  device_config.screenHeightDp = 1024;
-  device_config.sdkVersion = 27;
-
-  Res_value value;
-  ResTable_config config;
-  uint32_t flags = 0u;
-  ApkAssetsCookie cookie =
-      assetmanager.GetResource(basic::R::layout::layoutt, false /*may_be_bag*/,
-                               0u /*density_override*/, &value, &config, &flags);
-  if (cookie == kInvalidCookie) {
-    state.SkipWithError("failed to find R.layout.layout");
-    return;
-  }
-
-  size_t len = 0u;
-  const char* layout_path =
-      assetmanager.GetStringPoolForCookie(cookie)->string8At(value.data, &len);
-  if (layout_path == nullptr || len == 0u) {
-    state.SkipWithError("failed to lookup layout path");
-    return;
-  }
-
-  std::unique_ptr<Asset> asset = assetmanager.OpenNonAsset(
-      StringPiece(layout_path, len).to_string(), cookie, Asset::ACCESS_BUFFER);
-  if (asset == nullptr) {
-    state.SkipWithError("failed to load layout");
-    return;
-  }
-
-  ResXMLTree xml_tree;
-  if (xml_tree.setTo(asset->getBuffer(true), asset->getLength(), false /*copyData*/) != NO_ERROR) {
-    state.SkipWithError("corrupt xml layout");
-    return;
-  }
-
-  // Skip to the first tag.
-  while (xml_tree.next() != ResXMLParser::START_TAG) {
-  }
-
-  std::unique_ptr<Theme> theme = assetmanager.NewTheme();
-  theme->ApplyStyle(Theme_Material_Light);
-
-  std::array<uint32_t, 92> attrs{
-      {0x0101000e, 0x01010034, 0x01010095, 0x01010096, 0x01010097, 0x01010098, 0x01010099,
-       0x0101009a, 0x0101009b, 0x010100ab, 0x010100af, 0x010100b0, 0x010100b1, 0x0101011f,
-       0x01010120, 0x0101013f, 0x01010140, 0x0101014e, 0x0101014f, 0x01010150, 0x01010151,
-       0x01010152, 0x01010153, 0x01010154, 0x01010155, 0x01010156, 0x01010157, 0x01010158,
-       0x01010159, 0x0101015a, 0x0101015b, 0x0101015c, 0x0101015d, 0x0101015e, 0x0101015f,
-       0x01010160, 0x01010161, 0x01010162, 0x01010163, 0x01010164, 0x01010165, 0x01010166,
-       0x01010167, 0x01010168, 0x01010169, 0x0101016a, 0x0101016b, 0x0101016c, 0x0101016d,
-       0x0101016e, 0x0101016f, 0x01010170, 0x01010171, 0x01010217, 0x01010218, 0x0101021d,
-       0x01010220, 0x01010223, 0x01010224, 0x01010264, 0x01010265, 0x01010266, 0x010102c5,
-       0x010102c6, 0x010102c7, 0x01010314, 0x01010315, 0x01010316, 0x0101035e, 0x0101035f,
-       0x01010362, 0x01010374, 0x0101038c, 0x01010392, 0x01010393, 0x010103ac, 0x0101045d,
-       0x010104b6, 0x010104b7, 0x010104d6, 0x010104d7, 0x010104dd, 0x010104de, 0x010104df,
-       0x01010535, 0x01010536, 0x01010537, 0x01010538, 0x01010546, 0x01010567, 0x011100c9,
-       0x011100ca}};
-
-  std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values;
-  std::array<uint32_t, attrs.size() + 1> indices;
-  while (state.KeepRunning()) {
-    ApplyStyle(theme.get(), &xml_tree, 0x01010084u /*def_style_attr*/, 0u /*def_style_res*/,
-               attrs.data(), attrs.size(), values.data(), indices.data());
-  }
-}
-BENCHMARK(BM_ApplyStyleFramework);
-
-}  // namespace android
diff --git a/libs/androidfw/tests/AttributeResolution_test.cpp b/libs/androidfw/tests/AttributeResolution_test.cpp
index cc30537..2d73ce8 100644
--- a/libs/androidfw/tests/AttributeResolution_test.cpp
+++ b/libs/androidfw/tests/AttributeResolution_test.cpp
@@ -21,7 +21,6 @@
 #include "android-base/file.h"
 #include "android-base/logging.h"
 #include "android-base/macros.h"
-#include "androidfw/AssetManager2.h"
 
 #include "TestHelpers.h"
 #include "data/styles/R.h"
@@ -33,14 +32,15 @@
 class AttributeResolutionTest : public ::testing::Test {
  public:
   virtual void SetUp() override {
-    styles_assets_ = ApkAssets::Load(GetTestDataPath() + "/styles/styles.apk");
-    ASSERT_NE(nullptr, styles_assets_);
-    assetmanager_.SetApkAssets({styles_assets_.get()});
+    std::string contents;
+    ASSERT_TRUE(ReadFileFromZipToString(
+        GetTestDataPath() + "/styles/styles.apk", "resources.arsc", &contents));
+    ASSERT_EQ(NO_ERROR, table_.add(contents.data(), contents.size(),
+                                   1 /*cookie*/, true /*copyData*/));
   }
 
  protected:
-  std::unique_ptr<const ApkAssets> styles_assets_;
-  AssetManager2 assetmanager_;
+  ResTable table_;
 };
 
 class AttributeResolutionXmlTest : public AttributeResolutionTest {
@@ -48,12 +48,13 @@
   virtual void SetUp() override {
     AttributeResolutionTest::SetUp();
 
-    std::unique_ptr<Asset> asset =
-        assetmanager_.OpenNonAsset("res/layout/layout.xml", Asset::ACCESS_BUFFER);
-    ASSERT_NE(nullptr, asset);
+    std::string contents;
+    ASSERT_TRUE(
+        ReadFileFromZipToString(GetTestDataPath() + "/styles/styles.apk",
+                                "res/layout/layout.xml", &contents));
 
-    ASSERT_EQ(NO_ERROR,
-              xml_parser_.setTo(asset->getBuffer(true), asset->getLength(), true /*copyData*/));
+    ASSERT_EQ(NO_ERROR, xml_parser_.setTo(contents.data(), contents.size(),
+                                          true /*copyData*/));
 
     // Skip to the first tag.
     while (xml_parser_.next() != ResXMLParser::START_TAG) {
@@ -65,14 +66,14 @@
 };
 
 TEST_F(AttributeResolutionTest, Theme) {
-  std::unique_ptr<Theme> theme = assetmanager_.NewTheme();
-  ASSERT_TRUE(theme->ApplyStyle(R::style::StyleTwo));
+  ResTable::Theme theme(table_);
+  ASSERT_EQ(NO_ERROR, theme.applyStyle(R::style::StyleTwo));
 
   std::array<uint32_t, 5> attrs{{R::attr::attr_one, R::attr::attr_two, R::attr::attr_three,
                                  R::attr::attr_four, R::attr::attr_empty}};
   std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values;
 
-  ASSERT_TRUE(ResolveAttrs(theme.get(), 0u /*def_style_attr*/, 0u /*def_style_res*/,
+  ASSERT_TRUE(ResolveAttrs(&theme, 0 /*def_style_attr*/, 0 /*def_style_res*/,
                            nullptr /*src_values*/, 0 /*src_values_length*/, attrs.data(),
                            attrs.size(), values.data(), nullptr /*out_indices*/));
 
@@ -125,8 +126,8 @@
                                  R::attr::attr_four, R::attr::attr_empty}};
   std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values;
 
-  ASSERT_TRUE(RetrieveAttributes(&assetmanager_, &xml_parser_, attrs.data(), attrs.size(),
-                                 values.data(), nullptr /*out_indices*/));
+  ASSERT_TRUE(RetrieveAttributes(&table_, &xml_parser_, attrs.data(), attrs.size(), values.data(),
+                                 nullptr /*out_indices*/));
 
   uint32_t* values_cursor = values.data();
   EXPECT_EQ(Res_value::TYPE_NULL, values_cursor[STYLE_TYPE]);
@@ -170,15 +171,15 @@
 }
 
 TEST_F(AttributeResolutionXmlTest, ThemeAndXmlParser) {
-  std::unique_ptr<Theme> theme = assetmanager_.NewTheme();
-  ASSERT_TRUE(theme->ApplyStyle(R::style::StyleTwo));
+  ResTable::Theme theme(table_);
+  ASSERT_EQ(NO_ERROR, theme.applyStyle(R::style::StyleTwo));
 
   std::array<uint32_t, 6> attrs{{R::attr::attr_one, R::attr::attr_two, R::attr::attr_three,
                                  R::attr::attr_four, R::attr::attr_five, R::attr::attr_empty}};
   std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values;
   std::array<uint32_t, attrs.size() + 1> indices;
 
-  ApplyStyle(theme.get(), &xml_parser_, 0u /*def_style_attr*/, 0u /*def_style_res*/, attrs.data(),
+  ApplyStyle(&theme, &xml_parser_, 0 /*def_style_attr*/, 0 /*def_style_res*/, attrs.data(),
              attrs.size(), values.data(), indices.data());
 
   const uint32_t public_flag = ResTable_typeSpec::SPEC_PUBLIC;
diff --git a/libs/androidfw/tests/BenchmarkHelpers.cpp b/libs/androidfw/tests/BenchmarkHelpers.cpp
index faddfe5..7149bee 100644
--- a/libs/androidfw/tests/BenchmarkHelpers.cpp
+++ b/libs/androidfw/tests/BenchmarkHelpers.cpp
@@ -33,21 +33,19 @@
     }
   }
 
-  // Make sure to force creation of the ResTable first, or else the configuration doesn't get set.
-  const ResTable& table = assetmanager.getResources(true);
   if (config != nullptr) {
     assetmanager.setConfiguration(*config);
   }
 
+  const ResTable& table = assetmanager.getResources(true);
+
   Res_value value;
   ResTable_config selected_config;
   uint32_t flags;
-  uint32_t last_ref = 0u;
 
   while (state.KeepRunning()) {
-    ssize_t block = table.getResource(resid, &value, false /*may_be_bag*/, 0u /*density*/, &flags,
-                                      &selected_config);
-    table.resolveReference(&value, block, &last_ref, &flags, &selected_config);
+    table.getResource(resid, &value, false /*may_be_bag*/, 0u /*density*/, &flags,
+                      &selected_config);
   }
 }
 
@@ -74,12 +72,10 @@
   Res_value value;
   ResTable_config selected_config;
   uint32_t flags;
-  uint32_t last_id = 0u;
 
   while (state.KeepRunning()) {
-    ApkAssetsCookie cookie = assetmanager.GetResource(
-        resid, false /* may_be_bag */, 0u /* density_override */, &value, &selected_config, &flags);
-    assetmanager.ResolveReference(cookie, &value, &selected_config, &flags, &last_id);
+    assetmanager.GetResource(resid, false /* may_be_bag */, 0u /* density_override */, &value,
+                             &selected_config, &flags);
   }
 }
 
diff --git a/libs/androidfw/tests/LoadedArsc_test.cpp b/libs/androidfw/tests/LoadedArsc_test.cpp
index bedebd6..37ddafb 100644
--- a/libs/androidfw/tests/LoadedArsc_test.cpp
+++ b/libs/androidfw/tests/LoadedArsc_test.cpp
@@ -16,8 +16,6 @@
 
 #include "androidfw/LoadedArsc.h"
 
-#include "androidfw/ResourceUtils.h"
-
 #include "TestHelpers.h"
 #include "data/basic/R.h"
 #include "data/libclient/R.h"
@@ -29,13 +27,6 @@
 namespace libclient = com::android::libclient;
 namespace sparse = com::android::sparse;
 
-using ::testing::Eq;
-using ::testing::Ge;
-using ::testing::IsNull;
-using ::testing::NotNull;
-using ::testing::SizeIs;
-using ::testing::StrEq;
-
 namespace android {
 
 TEST(LoadedArscTest, LoadSinglePackageArsc) {
@@ -44,24 +35,39 @@
                                       &contents));
 
   std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
-  ASSERT_THAT(loaded_arsc, NotNull());
+  ASSERT_NE(nullptr, loaded_arsc);
 
-  const LoadedPackage* package =
-      loaded_arsc->GetPackageById(get_package_id(app::R::string::string_one));
-  ASSERT_THAT(package, NotNull());
-  EXPECT_THAT(package->GetPackageName(), StrEq("com.android.app"));
-  EXPECT_THAT(package->GetPackageId(), Eq(0x7f));
+  const std::vector<std::unique_ptr<const LoadedPackage>>& packages = loaded_arsc->GetPackages();
+  ASSERT_EQ(1u, packages.size());
+  EXPECT_EQ(std::string("com.android.app"), packages[0]->GetPackageName());
+  EXPECT_EQ(0x7f, packages[0]->GetPackageId());
 
-  const uint8_t type_index = get_type_id(app::R::string::string_one) - 1;
-  const uint16_t entry_index = get_entry_id(app::R::string::string_one);
+  ResTable_config config;
+  memset(&config, 0, sizeof(config));
+  config.sdkVersion = 24;
 
-  const TypeSpec* type_spec = package->GetTypeSpecByTypeIndex(type_index);
-  ASSERT_THAT(type_spec, NotNull());
-  ASSERT_THAT(type_spec->type_count, Ge(1u));
+  FindEntryResult entry;
 
-  const ResTable_type* type = type_spec->types[0];
-  ASSERT_THAT(type, NotNull());
-  ASSERT_THAT(LoadedPackage::GetEntry(type, entry_index), NotNull());
+  ASSERT_TRUE(loaded_arsc->FindEntry(app::R::string::string_one, config, &entry));
+  ASSERT_NE(nullptr, entry.entry);
+}
+
+TEST(LoadedArscTest, FindDefaultEntry) {
+  std::string contents;
+  ASSERT_TRUE(
+      ReadFileFromZipToString(GetTestDataPath() + "/basic/basic.apk", "resources.arsc", &contents));
+
+  std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
+  ASSERT_NE(nullptr, loaded_arsc);
+
+  ResTable_config desired_config;
+  memset(&desired_config, 0, sizeof(desired_config));
+  desired_config.language[0] = 'd';
+  desired_config.language[1] = 'e';
+
+  FindEntryResult entry;
+  ASSERT_TRUE(loaded_arsc->FindEntry(basic::R::string::test1, desired_config, &entry));
+  ASSERT_NE(nullptr, entry.entry);
 }
 
 TEST(LoadedArscTest, LoadSparseEntryApp) {
@@ -70,22 +76,15 @@
                                       &contents));
 
   std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
-  ASSERT_THAT(loaded_arsc, NotNull());
+  ASSERT_NE(nullptr, loaded_arsc);
 
-  const LoadedPackage* package =
-      loaded_arsc->GetPackageById(get_package_id(sparse::R::integer::foo_9));
-  ASSERT_THAT(package, NotNull());
+  ResTable_config config;
+  memset(&config, 0, sizeof(config));
+  config.sdkVersion = 26;
 
-  const uint8_t type_index = get_type_id(sparse::R::integer::foo_9) - 1;
-  const uint16_t entry_index = get_entry_id(sparse::R::integer::foo_9);
-
-  const TypeSpec* type_spec = package->GetTypeSpecByTypeIndex(type_index);
-  ASSERT_THAT(type_spec, NotNull());
-  ASSERT_THAT(type_spec->type_count, Ge(1u));
-
-  const ResTable_type* type = type_spec->types[0];
-  ASSERT_THAT(type, NotNull());
-  ASSERT_THAT(LoadedPackage::GetEntry(type, entry_index), NotNull());
+  FindEntryResult entry;
+  ASSERT_TRUE(loaded_arsc->FindEntry(sparse::R::integer::foo_9, config, &entry));
+  ASSERT_NE(nullptr, entry.entry);
 }
 
 TEST(LoadedArscTest, LoadSharedLibrary) {
@@ -94,13 +93,14 @@
                                       &contents));
 
   std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
-  ASSERT_THAT(loaded_arsc, NotNull());
+  ASSERT_NE(nullptr, loaded_arsc);
 
   const auto& packages = loaded_arsc->GetPackages();
-  ASSERT_THAT(packages, SizeIs(1u));
+  ASSERT_EQ(1u, packages.size());
+
   EXPECT_TRUE(packages[0]->IsDynamic());
-  EXPECT_THAT(packages[0]->GetPackageName(), StrEq("com.android.lib_one"));
-  EXPECT_THAT(packages[0]->GetPackageId(), Eq(0));
+  EXPECT_EQ(std::string("com.android.lib_one"), packages[0]->GetPackageName());
+  EXPECT_EQ(0, packages[0]->GetPackageId());
 
   const auto& dynamic_pkg_map = packages[0]->GetDynamicPackageMap();
 
@@ -114,23 +114,25 @@
                                       "resources.arsc", &contents));
 
   std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
-  ASSERT_THAT(loaded_arsc, NotNull());
+  ASSERT_NE(nullptr, loaded_arsc);
 
   const auto& packages = loaded_arsc->GetPackages();
-  ASSERT_THAT(packages, SizeIs(1u));
+  ASSERT_EQ(1u, packages.size());
+
   EXPECT_FALSE(packages[0]->IsDynamic());
-  EXPECT_THAT(packages[0]->GetPackageName(), StrEq("com.android.libclient"));
-  EXPECT_THAT(packages[0]->GetPackageId(), Eq(0x7f));
+  EXPECT_EQ(std::string("com.android.libclient"), packages[0]->GetPackageName());
+  EXPECT_EQ(0x7f, packages[0]->GetPackageId());
 
   const auto& dynamic_pkg_map = packages[0]->GetDynamicPackageMap();
 
   // The library has two dependencies.
-  ASSERT_THAT(dynamic_pkg_map, SizeIs(2u));
-  EXPECT_THAT(dynamic_pkg_map[0].package_name, StrEq("com.android.lib_one"));
-  EXPECT_THAT(dynamic_pkg_map[0].package_id, Eq(0x02));
+  ASSERT_EQ(2u, dynamic_pkg_map.size());
 
-  EXPECT_THAT(dynamic_pkg_map[1].package_name, StrEq("com.android.lib_two"));
-  EXPECT_THAT(dynamic_pkg_map[1].package_id, Eq(0x03));
+  EXPECT_EQ(std::string("com.android.lib_one"), dynamic_pkg_map[0].package_name);
+  EXPECT_EQ(0x02, dynamic_pkg_map[0].package_id);
+
+  EXPECT_EQ(std::string("com.android.lib_two"), dynamic_pkg_map[1].package_name);
+  EXPECT_EQ(0x03, dynamic_pkg_map[1].package_id);
 }
 
 TEST(LoadedArscTest, LoadAppAsSharedLibrary) {
@@ -141,12 +143,13 @@
   std::unique_ptr<const LoadedArsc> loaded_arsc =
       LoadedArsc::Load(StringPiece(contents), nullptr /*loaded_idmap*/, false /*system*/,
                        true /*load_as_shared_library*/);
-  ASSERT_THAT(loaded_arsc, NotNull());
+  ASSERT_NE(nullptr, loaded_arsc);
 
   const auto& packages = loaded_arsc->GetPackages();
-  ASSERT_THAT(packages, SizeIs(1u));
+  ASSERT_EQ(1u, packages.size());
+
   EXPECT_TRUE(packages[0]->IsDynamic());
-  EXPECT_THAT(packages[0]->GetPackageId(), Eq(0x7f));
+  EXPECT_EQ(0x7f, packages[0]->GetPackageId());
 }
 
 TEST(LoadedArscTest, LoadFeatureSplit) {
@@ -154,27 +157,21 @@
   ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/feature/feature.apk", "resources.arsc",
                                       &contents));
   std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
-  ASSERT_THAT(loaded_arsc, NotNull());
+  ASSERT_NE(nullptr, loaded_arsc);
 
-  const LoadedPackage* package =
-      loaded_arsc->GetPackageById(get_package_id(basic::R::string::test3));
-  ASSERT_THAT(package, NotNull());
+  ResTable_config desired_config;
+  memset(&desired_config, 0, sizeof(desired_config));
 
-  uint8_t type_index = get_type_id(basic::R::string::test3) - 1;
-  uint8_t entry_index = get_entry_id(basic::R::string::test3);
-
-  const TypeSpec* type_spec = package->GetTypeSpecByTypeIndex(type_index);
-  ASSERT_THAT(type_spec, NotNull());
-  ASSERT_THAT(type_spec->type_count, Ge(1u));
-  ASSERT_THAT(type_spec->types[0], NotNull());
+  FindEntryResult entry;
+  ASSERT_TRUE(loaded_arsc->FindEntry(basic::R::string::test3, desired_config, &entry));
 
   size_t len;
-  const char16_t* type_name16 =
-      package->GetTypeStringPool()->stringAt(type_spec->type_spec->id - 1, &len);
-  ASSERT_THAT(type_name16, NotNull());
-  EXPECT_THAT(util::Utf16ToUtf8(StringPiece16(type_name16, len)), StrEq("string"));
+  const char16_t* type_name16 = entry.type_string_ref.string16(&len);
+  ASSERT_NE(nullptr, type_name16);
+  ASSERT_NE(0u, len);
 
-  ASSERT_THAT(LoadedPackage::GetEntry(type_spec->types[0], entry_index), NotNull());
+  std::string type_name = util::Utf16ToUtf8(StringPiece16(type_name16, len));
+  EXPECT_EQ(std::string("string"), type_name);
 }
 
 class MockLoadedIdmap : public LoadedIdmap {
@@ -202,33 +199,23 @@
 };
 
 TEST(LoadedArscTest, LoadOverlay) {
-  std::string contents;
+  std::string contents, overlay_contents;
+  ASSERT_TRUE(
+      ReadFileFromZipToString(GetTestDataPath() + "/basic/basic.apk", "resources.arsc", &contents));
   ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/overlay/overlay.apk", "resources.arsc",
-                                      &contents));
+                                      &overlay_contents));
 
   MockLoadedIdmap loaded_idmap;
 
   std::unique_ptr<const LoadedArsc> loaded_arsc =
-      LoadedArsc::Load(StringPiece(contents), &loaded_idmap);
-  ASSERT_THAT(loaded_arsc, NotNull());
+      LoadedArsc::Load(StringPiece(overlay_contents), &loaded_idmap);
+  ASSERT_NE(nullptr, loaded_arsc);
 
-  const LoadedPackage* package = loaded_arsc->GetPackageById(0x08u);
-  ASSERT_THAT(package, NotNull());
+  ResTable_config desired_config;
+  memset(&desired_config, 0, sizeof(desired_config));
 
-  const TypeSpec* type_spec = package->GetTypeSpecByTypeIndex(0x03u - 1);
-  ASSERT_THAT(type_spec, NotNull());
-  ASSERT_THAT(type_spec->type_count, Ge(1u));
-  ASSERT_THAT(type_spec->types[0], NotNull());
-
-  // The entry being overlaid doesn't exist at the original entry index.
-  ASSERT_THAT(LoadedPackage::GetEntry(type_spec->types[0], 0x0001u), IsNull());
-
-  // Since this is an overlay, the actual entry ID must be mapped.
-  ASSERT_THAT(type_spec->idmap_entries, NotNull());
-  uint16_t target_entry_id = 0u;
-  ASSERT_TRUE(LoadedIdmap::Lookup(type_spec->idmap_entries, 0x0001u, &target_entry_id));
-  ASSERT_THAT(target_entry_id, Eq(0x0u));
-  ASSERT_THAT(LoadedPackage::GetEntry(type_spec->types[0], 0x0000), NotNull());
+  FindEntryResult entry;
+  ASSERT_TRUE(loaded_arsc->FindEntry(0x08030001u, desired_config, &entry));
 }
 
 // structs with size fields (like Res_value, ResTable_entry) should be
diff --git a/libs/androidfw/tests/TestHelpers.h b/libs/androidfw/tests/TestHelpers.h
index df0c642..43a9955 100644
--- a/libs/androidfw/tests/TestHelpers.h
+++ b/libs/androidfw/tests/TestHelpers.h
@@ -20,7 +20,6 @@
 #include <string>
 
 #include "androidfw/ResourceTypes.h"
-#include "gmock/gmock.h"
 #include "gtest/gtest.h"
 
 #include "CommonHelpers.h"
diff --git a/libs/androidfw/tests/data/basic/R.h b/libs/androidfw/tests/data/basic/R.h
index b7e814f..94a2a14 100644
--- a/libs/androidfw/tests/data/basic/R.h
+++ b/libs/androidfw/tests/data/basic/R.h
@@ -34,7 +34,6 @@
   struct layout {
     enum : uint32_t {
       main = 0x7f020000,
-      layoutt = 0x7f020001,
     };
   };
 
@@ -56,7 +55,6 @@
       number2 = 0x7f040001,
       ref1 = 0x7f040002,
       ref2 = 0x7f040003,
-      deep_ref = 0x7f040004,
 
       // From feature
       number3 = 0x80030000,
diff --git a/libs/androidfw/tests/data/basic/basic.apk b/libs/androidfw/tests/data/basic/basic.apk
index 1733b6a..18ef75e 100644
--- a/libs/androidfw/tests/data/basic/basic.apk
+++ b/libs/androidfw/tests/data/basic/basic.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/basic/res/values/values.xml b/libs/androidfw/tests/data/basic/res/values/values.xml
index b343562..6c47459 100644
--- a/libs/androidfw/tests/data/basic/res/values/values.xml
+++ b/libs/androidfw/tests/data/basic/res/values/values.xml
@@ -22,7 +22,6 @@
     <attr name="attr2" format="reference|integer" />
 
     <public type="layout" name="main" id="0x7f020000" />
-    <public type="layout" name="layout" id="0x7f020001" />
 
     <public type="string" name="test1" id="0x7f030000" />
     <string name="test1">test1</string>
@@ -44,18 +43,6 @@
     <public type="integer" name="ref2" id="0x7f040003" />
     <integer name="ref2">12000</integer>
 
-    <public type="integer" name="deep_ref" id="0x7f040004" />
-    <integer name="deep_ref">@integer/deep_ref_1</integer>
-    <integer name="deep_ref_1">@integer/deep_ref_2</integer>
-    <integer name="deep_ref_2">@integer/deep_ref_3</integer>
-    <integer name="deep_ref_3">@integer/deep_ref_4</integer>
-    <integer name="deep_ref_4">@integer/deep_ref_5</integer>
-    <integer name="deep_ref_5">@integer/deep_ref_6</integer>
-    <integer name="deep_ref_6">@integer/deep_ref_7</integer>
-    <integer name="deep_ref_7">@integer/deep_ref_8</integer>
-    <integer name="deep_ref_8">@integer/deep_ref_9</integer>
-    <integer name="deep_ref_9">100</integer>
-
     <public type="style" name="Theme1" id="0x7f050000" />
     <style name="Theme1">
         <item name="com.android.basic:attr1">100</item>
diff --git a/libs/hwui/hwui/AnimatedImageDrawable.h b/libs/hwui/hwui/AnimatedImageDrawable.h
index 1ebb585..df8a5e4 100644
--- a/libs/hwui/hwui/AnimatedImageDrawable.h
+++ b/libs/hwui/hwui/AnimatedImageDrawable.h
@@ -33,6 +33,13 @@
 class TaskManager;
 }
 
+class OnAnimationEndListener {
+public:
+    virtual ~OnAnimationEndListener() {}
+
+    virtual void onAnimationEnd() = 0;
+};
+
 /**
  * Native component of android.graphics.drawable.AnimatedImageDrawables.java.  This class can be
  * drawn into Canvas.h and maintains the state needed to drive the animation from the RenderThread.
@@ -62,6 +69,13 @@
     bool start();
     void stop();
     bool isRunning();
+    void setRepetitionCount(int count) {
+        mSkAnimatedImage->setRepetitionCount(count);
+    }
+
+    void setOnAnimationEndListener(std::unique_ptr<OnAnimationEndListener> listener) {
+        mEndListener = std::move(listener);
+    }
 
     void scheduleUpdate(uirenderer::TaskManager* taskManager);
 
@@ -87,6 +101,8 @@
     class AnimatedImageTaskProcessor;
     sp<AnimatedImageTask> mDecodeTask;
     sp<AnimatedImageTaskProcessor> mDecodeTaskProcessor;
+
+    std::unique_ptr<OnAnimationEndListener> mEndListener;
 };
 
 };  // namespace android
diff --git a/media/java/android/media/AudioDeviceInfo.java b/media/java/android/media/AudioDeviceInfo.java
index 1a97b6b..41f9f09 100644
--- a/media/java/android/media/AudioDeviceInfo.java
+++ b/media/java/android/media/AudioDeviceInfo.java
@@ -142,7 +142,8 @@
             TYPE_LINE_DIGITAL,
             TYPE_FM,
             TYPE_AUX_LINE,
-            TYPE_IP }
+            TYPE_IP,
+            TYPE_BUS }
     )
     @Retention(RetentionPolicy.SOURCE)
     public @interface AudioDeviceTypeOut {}
@@ -168,6 +169,7 @@
             case TYPE_FM:
             case TYPE_AUX_LINE:
             case TYPE_IP:
+            case TYPE_BUS:
                 return true;
             default:
                 return false;
diff --git a/media/java/android/media/IMediaSession2.aidl b/media/java/android/media/IMediaSession2.aidl
index b10a40b..f79711a 100644
--- a/media/java/android/media/IMediaSession2.aidl
+++ b/media/java/android/media/IMediaSession2.aidl
@@ -42,6 +42,8 @@
     // send command
     //////////////////////////////////////////////////////////////////////////////////////////////
     oneway void sendCommand(IMediaSession2Callback caller, in Bundle command, in Bundle args);
+    oneway void sendTransportControlCommand(IMediaSession2Callback caller,
+            int commandCode, long arg);
 
     Bundle getPlaybackState();
 
diff --git a/media/java/android/media/IMediaSession2Callback.aidl b/media/java/android/media/IMediaSession2Callback.aidl
index eb02fa7..45d40e6 100644
--- a/media/java/android/media/IMediaSession2Callback.aidl
+++ b/media/java/android/media/IMediaSession2Callback.aidl
@@ -30,6 +30,7 @@
  */
 oneway interface IMediaSession2Callback {
     void onPlaybackStateChanged(in Bundle state);
+    void onPlaylistParamsChanged(in Bundle params);
 
     /**
      * Called only when the controller is created with service's token.
diff --git a/media/java/android/media/MediaActionSound.java b/media/java/android/media/MediaActionSound.java
index 983ca75..dcd4dce 100644
--- a/media/java/android/media/MediaActionSound.java
+++ b/media/java/android/media/MediaActionSound.java
@@ -47,11 +47,16 @@
     private SoundPool mSoundPool;
     private SoundState[] mSounds;
 
+    private static final String[] SOUND_DIRS = {
+        "/product/media/audio/ui/",
+        "/system/media/audio/ui/",
+    };
+
     private static final String[] SOUND_FILES = {
-        "/system/media/audio/ui/camera_click.ogg",
-        "/system/media/audio/ui/camera_focus.ogg",
-        "/system/media/audio/ui/VideoRecord.ogg",
-        "/system/media/audio/ui/VideoStop.ogg"
+        "camera_click.ogg",
+        "camera_focus.ogg",
+        "VideoRecord.ogg",
+        "VideoStop.ogg"
     };
 
     private static final String TAG = "MediaActionSound";
@@ -132,12 +137,16 @@
     }
 
     private int loadSound(SoundState sound) {
-        int id = mSoundPool.load(SOUND_FILES[sound.name], 1);
-        if (id > 0) {
-            sound.state = STATE_LOADING;
-            sound.id = id;
+        final String soundFileName = SOUND_FILES[sound.name];
+        for (String soundDir : SOUND_DIRS) {
+            int id = mSoundPool.load(soundDir + soundFileName, 1);
+            if (id > 0) {
+                sound.state = STATE_LOADING;
+                sound.id = id;
+                return id;
+            }
         }
-        return id;
+        return 0;
     }
 
     /**
diff --git a/media/java/android/media/MediaController2.java b/media/java/android/media/MediaController2.java
index 6064ec4..e2d5c5d 100644
--- a/media/java/android/media/MediaController2.java
+++ b/media/java/android/media/MediaController2.java
@@ -138,6 +138,13 @@
          * @param state
          */
         public void onPlaybackStateChanged(@NonNull PlaybackState2 state) { }
+
+        /**
+         * Called when the playlist parameters are changed.
+         *
+         * @param params The new play list parameters.
+         */
+        public void onPlaylistParamsChanged(@NonNull PlaylistParams params) { }
     }
 
     /**
@@ -359,6 +366,17 @@
     }
 
     /**
+     * Sets the {@link PlaylistParams} for the current play list. Repeat/shuffle mode and metadata
+     * for the list can be set by calling this method.
+     *
+     * @param params A {@link PlaylistParams} object to set.
+     * @throws IllegalArgumentException if given {@param param} is null.
+     */
+    public void setPlaylistParams(PlaylistParams params) {
+        mProvider.setPlaylistParams_impl(params);
+    }
+
+    /**
      * @hide
      */
     public void skipForward() {
diff --git a/media/java/android/media/MediaExtractor.java b/media/java/android/media/MediaExtractor.java
index 2c1b4b3..174d6a3 100644
--- a/media/java/android/media/MediaExtractor.java
+++ b/media/java/android/media/MediaExtractor.java
@@ -626,6 +626,12 @@
      */
     public native long getSampleTime();
 
+    /**
+     * @return size of the current sample in bytes or -1 if no more
+     * samples are available.
+     */
+    public native long getSampleSize();
+
     // Keep these in sync with their equivalents in NuMediaExtractor.h
     /**
      * The sample is a sync sample (or in {@link MediaCodec}'s terminology
diff --git a/media/java/android/media/MediaLibraryService2.java b/media/java/android/media/MediaLibraryService2.java
index 5dadcb5..94ada13 100644
--- a/media/java/android/media/MediaLibraryService2.java
+++ b/media/java/android/media/MediaLibraryService2.java
@@ -66,7 +66,7 @@
     public class MediaLibrarySession extends MediaSession2 {
         private final MediaLibrarySessionProvider mProvider;
 
-        MediaLibrarySession(Context context, MediaPlayerBase player, String id,
+        MediaLibrarySession(Context context, MediaPlayerInterface player, String id,
                 VolumeProvider volumeProvider, int ratingType, PendingIntent sessionActivity,
                 Executor callbackExecutor, SessionCallback callback) {
             super(context, player, id, volumeProvider, ratingType, sessionActivity,
@@ -75,9 +75,10 @@
         }
 
         @Override
-        MediaSession2Provider createProvider(Context context, MediaPlayerBase player, String id,
-                VolumeProvider volumeProvider, int ratingType, PendingIntent sessionActivity,
-                Executor callbackExecutor, SessionCallback callback) {
+        MediaSession2Provider createProvider(Context context, MediaPlayerInterface player,
+                String id, VolumeProvider volumeProvider, int ratingType,
+                PendingIntent sessionActivity, Executor callbackExecutor,
+                SessionCallback callback) {
             return ApiLoader.getProvider(context)
                     .createMediaLibraryService2MediaLibrarySession(context, this, player, id,
                             volumeProvider, ratingType, sessionActivity,
@@ -206,7 +207,7 @@
     public class MediaLibrarySessionBuilder
             extends BuilderBase<MediaLibrarySessionBuilder, MediaLibrarySessionCallback> {
         public MediaLibrarySessionBuilder(
-                @NonNull Context context, @NonNull MediaPlayerBase player,
+                @NonNull Context context, @NonNull MediaPlayerInterface player,
                 @NonNull @CallbackExecutor Executor callbackExecutor,
                 @NonNull MediaLibrarySessionCallback callback) {
             super(context, player);
diff --git a/media/java/android/media/MediaPlayerBase.java b/media/java/android/media/MediaPlayerInterface.java
similarity index 63%
rename from media/java/android/media/MediaPlayerBase.java
rename to media/java/android/media/MediaPlayerInterface.java
index 0efec901..51bcd9b 100644
--- a/media/java/android/media/MediaPlayerBase.java
+++ b/media/java/android/media/MediaPlayerInterface.java
@@ -25,32 +25,35 @@
  * Base interfaces for all media players that want media session.
  * @hide
  */
-public abstract class MediaPlayerBase {
+public interface MediaPlayerInterface {
     /**
      * Listens change in {@link PlaybackState2}.
      */
-    public interface PlaybackListener {
+    interface PlaybackListener {
         /**
          * Called when {@link PlaybackState2} for this player is changed.
          */
         void onPlaybackChanged(PlaybackState2 state);
     }
 
-    public abstract void play();
-    public abstract void prepare();
-    public abstract void pause();
-    public abstract void stop();
-    public abstract void skipToPrevious();
-    public abstract void skipToNext();
-    public abstract void seekTo(long pos);
-    public abstract void fastFoward();
-    public abstract void rewind();
+    // Transport controls that session will send command directly to this player.
+    void play();
+    void prepare();
+    void pause();
+    void stop();
+    void skipToPrevious();
+    void skipToNext();
+    void seekTo(long pos);
+    void fastForward();
+    void rewind();
 
-    public abstract PlaybackState2 getPlaybackState();
-    public abstract AudioAttributes getAudioAttributes();
+    PlaybackState2 getPlaybackState();
+    AudioAttributes getAudioAttributes();
 
-    public abstract void setPlaylist(List<MediaItem2> item, PlaylistParams param);
-    public abstract void setCurrentPlaylistItem(int index);
+    void setPlaylist(List<MediaItem2> item, PlaylistParams param);
+    void setCurrentPlaylistItem(int index);
+    void setPlaylistParams(PlaylistParams params);
+    PlaylistParams getPlaylistParams();
 
     /**
      * Add a {@link PlaybackListener} to be invoked when the playback state is changed.
@@ -58,12 +61,12 @@
      * @param executor the Handler that will receive the listener
      * @param listener the listener that will be run
      */
-    public abstract void addPlaybackListener(Executor executor, PlaybackListener listener);
+    void addPlaybackListener(Executor executor, PlaybackListener listener);
 
     /**
      * Remove previously added {@link PlaybackListener}.
      *
      * @param listener the listener to be removed
      */
-    public abstract void removePlaybackListener(PlaybackListener listener);
+    void removePlaybackListener(PlaybackListener listener);
 }
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index cb4e46f..c309038 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -158,6 +158,7 @@
     public static final String SCANNED_BUILD_PREFS_NAME = "MediaScanBuild";
     public static final String LAST_INTERNAL_SCAN_FINGERPRINT = "lastScanFingerprint";
     private static final String SYSTEM_SOUNDS_DIR = "/system/media/audio";
+    private static final String PRODUCT_SOUNDS_DIR = "/product/media/audio";
     private static String sLastInternalScanFingerprint;
 
     private static final String[] ID3_GENRES = {
@@ -1153,7 +1154,10 @@
     private static boolean isSystemSoundWithMetadata(String path) {
         if (path.startsWith(SYSTEM_SOUNDS_DIR + ALARMS_DIR)
                 || path.startsWith(SYSTEM_SOUNDS_DIR + RINGTONES_DIR)
-                || path.startsWith(SYSTEM_SOUNDS_DIR + NOTIFICATIONS_DIR)) {
+                || path.startsWith(SYSTEM_SOUNDS_DIR + NOTIFICATIONS_DIR)
+                || path.startsWith(PRODUCT_SOUNDS_DIR + ALARMS_DIR)
+                || path.startsWith(PRODUCT_SOUNDS_DIR + RINGTONES_DIR)
+                || path.startsWith(PRODUCT_SOUNDS_DIR + NOTIFICATIONS_DIR)) {
             return true;
         }
         return false;
diff --git a/media/java/android/media/MediaSession2.java b/media/java/android/media/MediaSession2.java
index 7dffd40..365c356 100644
--- a/media/java/android/media/MediaSession2.java
+++ b/media/java/android/media/MediaSession2.java
@@ -24,7 +24,7 @@
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
-import android.media.MediaPlayerBase.PlaybackListener;
+import android.media.MediaPlayerInterface.PlaybackListener;
 import android.media.session.MediaSession;
 import android.media.session.MediaSession.Callback;
 import android.media.session.PlaybackState;
@@ -67,7 +67,8 @@
  * session.
  * <p>
  * When a session receive transport control commands, the session sends the commands directly to
- * the the underlying media player set by {@link Builder} or {@link #setPlayer(MediaPlayerBase)}.
+ * the the underlying media player set by {@link Builder} or
+ * {@link #setPlayer(MediaPlayerInterface)}.
  * <p>
  * When an app is finished performing playback it must call {@link #close()} to clean up the session
  * and notify any controllers.
@@ -229,6 +230,11 @@
             mCommands.add(new Command(COMMAND_CODE_PLAYBACK_STOP));
             mCommands.add(new Command(COMMAND_CODE_PLAYBACK_SKIP_NEXT_ITEM));
             mCommands.add(new Command(COMMAND_CODE_PLAYBACK_SKIP_PREV_ITEM));
+            mCommands.add(new Command(COMMAND_CODE_PLAYBACK_PREPARE));
+            mCommands.add(new Command(COMMAND_CODE_PLAYBACK_FAST_FORWARD));
+            mCommands.add(new Command(COMMAND_CODE_PLAYBACK_REWIND));
+            mCommands.add(new Command(COMMAND_CODE_PLAYBACK_SEEK_TO));
+            mCommands.add(new Command(COMMAND_CODE_PLAYBACK_SET_CURRENT_PLAYLIST_ITEM));
         }
 
         public void removeCommand(Command command) {
@@ -457,7 +463,7 @@
     static abstract class BuilderBase
             <T extends MediaSession2.BuilderBase<T, C>, C extends SessionCallback> {
         final Context mContext;
-        final MediaPlayerBase mPlayer;
+        final MediaPlayerInterface mPlayer;
         String mId;
         Executor mCallbackExecutor;
         C mCallback;
@@ -474,7 +480,7 @@
          *      {@link MediaSession2} or {@link MediaController2}.
          */
         // TODO(jaewan): Also need executor
-        public BuilderBase(@NonNull Context context, @NonNull MediaPlayerBase player) {
+        public BuilderBase(@NonNull Context context, @NonNull MediaPlayerInterface player) {
             if (context == null) {
                 throw new IllegalArgumentException("context shouldn't be null");
             }
@@ -589,12 +595,15 @@
     // TODO(jaewan): Add setRatingType()
     // TODO(jaewan): Add setSessionActivity()
     public static final class Builder extends BuilderBase<Builder, SessionCallback> {
-        public Builder(Context context, @NonNull MediaPlayerBase player) {
+        public Builder(Context context, @NonNull MediaPlayerInterface player) {
             super(context, player);
         }
 
         @Override
         public MediaSession2 build() {
+            if (mCallbackExecutor == null) {
+                mCallbackExecutor = mContext.getMainExecutor();
+            }
             if (mCallback == null) {
                 mCallback = new SessionCallback();
             }
@@ -845,7 +854,6 @@
     /**
      * Parameter for the playlist.
      */
-    // TODO(jaewan): add fromBundle()/toBundle()
     public static class PlaylistParams {
         /**
          * @hide
@@ -901,6 +909,16 @@
          */
         public static final int SHUFFLE_MODE_GROUP = 2;
 
+        /**
+         * Keys used for converting a PlaylistParams object to a bundle object and vice versa.
+         */
+        private static final String KEY_REPEAT_MODE =
+                "android.media.session2.playlistparams2.repeat_mode";
+        private static final String KEY_SHUFFLE_MODE =
+                "android.media.session2.playlistparams2.shuffle_mode";
+        private static final String KEY_MEDIA_METADATA2_BUNDLE =
+                "android.media.session2.playlistparams2.metadata2_bundle";
+
         private @RepeatMode int mRepeatMode;
         private @ShuffleMode int mShuffleMode;
 
@@ -924,6 +942,47 @@
         public MediaMetadata2 getPlaylistMetadata() {
             return mPlaylistMetadata;
         }
+
+        /**
+         * Returns this object as a bundle to share between processes.
+         *
+         * @hide
+         */
+        public Bundle toBundle() {
+            Bundle bundle = new Bundle();
+            bundle.putInt(KEY_REPEAT_MODE, mRepeatMode);
+            bundle.putInt(KEY_SHUFFLE_MODE, mShuffleMode);
+            if (mPlaylistMetadata != null) {
+                bundle.putBundle(KEY_MEDIA_METADATA2_BUNDLE, mPlaylistMetadata.getBundle());
+            }
+            return bundle;
+        }
+
+        /**
+         * Creates an instance from a bundle which is previously created by {@link #toBundle()}.
+         *
+         * @param bundle A bundle created by {@link #toBundle()}.
+         * @return A new {@link PlaylistParams} instance. Returns {@code null} if the given
+         *         {@param bundle} is null, or if the {@param bundle} has no playlist parameters.
+         * @hide
+         */
+        public static PlaylistParams fromBundle(Bundle bundle) {
+            if (bundle == null) {
+                return null;
+            }
+            if (!bundle.containsKey(KEY_REPEAT_MODE) || !bundle.containsKey(KEY_SHUFFLE_MODE)) {
+                return null;
+            }
+
+            Bundle metadataBundle = bundle.getBundle(KEY_MEDIA_METADATA2_BUNDLE);
+            MediaMetadata2 metadata =
+                    metadataBundle == null ? null : new MediaMetadata2(metadataBundle);
+
+            return new PlaylistParams(
+                    bundle.getInt(KEY_REPEAT_MODE),
+                    bundle.getInt(KEY_SHUFFLE_MODE),
+                    metadata);
+        }
     }
 
     /**
@@ -941,16 +1000,16 @@
      * @hide
      */
 
-    MediaSession2(Context context, MediaPlayerBase player, String id, VolumeProvider volumeProvider,
-            int ratingType, PendingIntent sessionActivity, Executor callbackExecutor,
-            SessionCallback callback) {
+    MediaSession2(Context context, MediaPlayerInterface player, String id,
+            VolumeProvider volumeProvider, int ratingType, PendingIntent sessionActivity,
+            Executor callbackExecutor, SessionCallback callback) {
         super();
         mProvider = createProvider(context, player, id, volumeProvider, ratingType, sessionActivity,
                 callbackExecutor, callback
         );
     }
 
-    MediaSession2Provider createProvider(Context context, MediaPlayerBase player, String id,
+    MediaSession2Provider createProvider(Context context, MediaPlayerInterface player, String id,
             VolumeProvider volumeProvider, int ratingType, PendingIntent sessionActivity,
             Executor callbackExecutor, SessionCallback callback) {
         return ApiLoader.getProvider(context)
@@ -964,8 +1023,8 @@
     }
 
     /**
-     * Set the underlying {@link MediaPlayerBase} for this session to dispatch incoming event to.
-     * Events from the {@link MediaController2} will be sent directly to the underlying
+     * Set the underlying {@link MediaPlayerInterface} for this session to dispatch incoming event
+     * to. Events from the {@link MediaController2} will be sent directly to the underlying
      * player on the {@link Handler} where the session is created on.
      * <p>
      * If the new player is successfully set, {@link PlaybackListener}
@@ -974,22 +1033,23 @@
      * You can also specify a volume provider. If so, playback in the player is considered as
      * remote playback.
      *
-     * @param player a {@link MediaPlayerBase} that handles actual media playback in your app.
+     * @param player a {@link MediaPlayerInterface} that handles actual media playback in your app.
      * @throws IllegalArgumentException if the player is {@code null}.
      */
-    public void setPlayer(@NonNull MediaPlayerBase player) {
+    public void setPlayer(@NonNull MediaPlayerInterface player) {
         mProvider.setPlayer_impl(player);
     }
 
     /**
-     * Set the underlying {@link MediaPlayerBase} with the volume provider for remote playback.
+     * Set the underlying {@link MediaPlayerInterface} with the volume provider for remote playback.
      *
-     * @param player a {@link MediaPlayerBase} that handles actual media playback in your app.
+     * @param player a {@link MediaPlayerInterface} that handles actual media playback in your app.
      * @param volumeProvider a volume provider
-     * @see #setPlayer(MediaPlayerBase)
+     * @see #setPlayer(MediaPlayerInterface)
      * @see Builder#setVolumeProvider(VolumeProvider)
      */
-    public void setPlayer(@NonNull MediaPlayerBase player, @NonNull VolumeProvider volumeProvider) {
+    public void setPlayer(@NonNull MediaPlayerInterface player,
+            @NonNull VolumeProvider volumeProvider) {
         mProvider.setPlayer_impl(player, volumeProvider);
     }
 
@@ -1001,7 +1061,8 @@
     /**
      * @return player
      */
-    public @Nullable MediaPlayerBase getPlayer() {
+    public @Nullable
+    MediaPlayerInterface getPlayer() {
         return mProvider.getPlayer_impl();
     }
 
@@ -1208,4 +1269,23 @@
     public void setPlaylist(@NonNull List<MediaItem2> playlist, @NonNull PlaylistParams param) {
         mProvider.setPlaylist_impl(playlist, param);
     }
+
+    /**
+     * Sets the {@link PlaylistParams} for the current play list. Repeat/shuffle mode and metadata
+     * for the list can be set by calling this method.
+     *
+     * @param params A {@link PlaylistParams} object to set.
+     * @throws IllegalArgumentException if given {@param param} is null.
+     */
+    public void setPlaylistParams(PlaylistParams params) {
+        mProvider.setPlaylistParams_impl(params);
+    }
+
+    /**
+     * Returns the {@link PlaylistParams} for the current play list.
+     * Returns {@code null} if not set.
+     */
+    public PlaylistParams getPlaylistParams() {
+        return mProvider.getPlaylistParams_impl();
+    }
 }
diff --git a/media/java/android/media/PlaybackState2.java b/media/java/android/media/PlaybackState2.java
index 04f211d..7688fbc 100644
--- a/media/java/android/media/PlaybackState2.java
+++ b/media/java/android/media/PlaybackState2.java
@@ -23,7 +23,7 @@
 import java.lang.annotation.RetentionPolicy;
 
 /**
- * Playback state for a {@link MediaPlayerBase}, to be shared between {@link MediaSession2} and
+ * Playback state for a {@link MediaPlayerInterface}, to be shared between {@link MediaSession2} and
  * {@link MediaController2}. This includes a playback state {@link #STATE_PLAYING},
  * the current playback position and extra.
  * @hide
@@ -31,8 +31,6 @@
 public final class PlaybackState2 {
     private static final String TAG = "PlaybackState2";
 
-    private static final String KEY_STATE = "android.media.playbackstate2.state";
-
     // TODO(jaewan): Replace states from MediaPlayer2
     /**
      * @hide
@@ -90,13 +88,25 @@
      */
     public final static long PLAYBACK_POSITION_UNKNOWN = -1;
 
+    /**
+     * Keys used for converting a PlaybackState2 to a bundle object and vice versa.
+     */
+    private static final String KEY_STATE = "android.media.playbackstate2.state";
+    private static final String KEY_POSITION = "android.media.playbackstate2.position";
+    private static final String KEY_BUFFERED_POSITION =
+            "android.media.playbackstate2.buffered_position";
+    private static final String KEY_SPEED = "android.media.playbackstate2.speed";
+    private static final String KEY_ERROR_MESSAGE = "android.media.playbackstate2.error_message";
+    private static final String KEY_UPDATE_TIME = "android.media.playbackstate2.update_time";
+    private static final String KEY_ACTIVE_ITEM_ID = "android.media.playbackstate2.active_item_id";
+
     private final int mState;
     private final long mPosition;
-    private final long mBufferedPosition;
-    private final float mSpeed;
-    private final CharSequence mErrorMessage;
     private final long mUpdateTime;
+    private final float mSpeed;
+    private final long mBufferedPosition;
     private final long mActiveItemId;
+    private final CharSequence mErrorMessage;
 
     public PlaybackState2(int state, long position, long updateTime, float speed,
             long bufferedPosition, long activeItemId, CharSequence error) {
@@ -194,22 +204,49 @@
     }
 
     /**
-     * @return Bundle object for this to share between processes.
+     * Returns this object as a bundle to share between processes.
      */
     public Bundle toBundle() {
-        // TODO(jaewan): Include other variables.
         Bundle bundle = new Bundle();
         bundle.putInt(KEY_STATE, mState);
+        bundle.putLong(KEY_POSITION, mPosition);
+        bundle.putLong(KEY_UPDATE_TIME, mUpdateTime);
+        bundle.putFloat(KEY_SPEED, mSpeed);
+        bundle.putLong(KEY_BUFFERED_POSITION, mBufferedPosition);
+        bundle.putLong(KEY_ACTIVE_ITEM_ID, mActiveItemId);
+        bundle.putCharSequence(KEY_ERROR_MESSAGE, mErrorMessage);
         return bundle;
     }
 
     /**
-     * @param bundle input
-     * @return
+     * Creates an instance from a bundle which is previously created by {@link #toBundle()}.
+     *
+     * @param bundle A bundle created by {@link #toBundle()}.
+     * @return A new {@link PlaybackState2} instance. Returns {@code null} if the given
+     *         {@param bundle} is null, or if the {@param bundle} has no playback state parameters.
      */
     public static PlaybackState2 fromBundle(Bundle bundle) {
-        // TODO(jaewan): Include other variables.
-        final int state = bundle.getInt(KEY_STATE);
-        return new PlaybackState2(state, 0, 0, 0, 0, 0, null);
+        if (bundle == null) {
+            return null;
+        }
+
+        if (!bundle.containsKey(KEY_STATE)
+                || !bundle.containsKey(KEY_POSITION)
+                || !bundle.containsKey(KEY_UPDATE_TIME)
+                || !bundle.containsKey(KEY_SPEED)
+                || !bundle.containsKey(KEY_BUFFERED_POSITION)
+                || !bundle.containsKey(KEY_ACTIVE_ITEM_ID)
+                || !bundle.containsKey(KEY_ERROR_MESSAGE)) {
+            return null;
+        }
+
+        return new PlaybackState2(
+                bundle.getInt(KEY_STATE),
+                bundle.getLong(KEY_POSITION),
+                bundle.getLong(KEY_UPDATE_TIME),
+                bundle.getFloat(KEY_SPEED),
+                bundle.getLong(KEY_BUFFERED_POSITION),
+                bundle.getLong(KEY_ACTIVE_ITEM_ID),
+                bundle.getCharSequence(KEY_ERROR_MESSAGE));
     }
 }
\ No newline at end of file
diff --git a/media/java/android/media/update/MediaController2Provider.java b/media/java/android/media/update/MediaController2Provider.java
index 8dfb892..cf35358 100644
--- a/media/java/android/media/update/MediaController2Provider.java
+++ b/media/java/android/media/update/MediaController2Provider.java
@@ -61,5 +61,6 @@
     void addPlaylistItem_impl(int index, MediaItem2 item);
 
     PlaylistParams getPlaylistParam_impl();
+    void setPlaylistParams_impl(PlaylistParams params);
     PlaybackState2 getPlaybackState_impl();
 }
diff --git a/media/java/android/media/update/MediaSession2Provider.java b/media/java/android/media/update/MediaSession2Provider.java
index d32b741..801bdeb 100644
--- a/media/java/android/media/update/MediaSession2Provider.java
+++ b/media/java/android/media/update/MediaSession2Provider.java
@@ -16,10 +16,9 @@
 
 package android.media.update;
 
-import android.annotation.SystemApi;
 import android.media.AudioAttributes;
 import android.media.MediaItem2;
-import android.media.MediaPlayerBase;
+import android.media.MediaPlayerInterface;
 import android.media.MediaSession2.Command;
 import android.media.MediaSession2.CommandButton;
 import android.media.MediaSession2.CommandGroup;
@@ -37,9 +36,9 @@
  */
 public interface MediaSession2Provider extends TransportControlProvider {
     void close_impl();
-    void setPlayer_impl(MediaPlayerBase player);
-    void setPlayer_impl(MediaPlayerBase player, VolumeProvider volumeProvider);
-    MediaPlayerBase getPlayer_impl();
+    void setPlayer_impl(MediaPlayerInterface player);
+    void setPlayer_impl(MediaPlayerInterface player, VolumeProvider volumeProvider);
+    MediaPlayerInterface getPlayer_impl();
     SessionToken2 getToken_impl();
     List<ControllerInfo> getConnectedControllers_impl();
     void setCustomLayout_impl(ControllerInfo controller, List<CommandButton> layout);
@@ -52,6 +51,8 @@
             ResultReceiver receiver);
     void sendCustomCommand_impl(Command command, Bundle args);
     void setPlaylist_impl(List<MediaItem2> playlist, PlaylistParams param);
+    void setPlaylistParams_impl(PlaylistParams params);
+    PlaylistParams getPlaylistParams_impl();
 
     interface ControllerInfoProvider {
         String getPackageName_impl();
diff --git a/media/java/android/media/update/StaticProvider.java b/media/java/android/media/update/StaticProvider.java
index 3cd1a99..7faac95 100644
--- a/media/java/android/media/update/StaticProvider.java
+++ b/media/java/android/media/update/StaticProvider.java
@@ -17,7 +17,6 @@
 package android.media.update;
 
 import android.annotation.Nullable;
-import android.annotation.SystemApi;
 import android.app.PendingIntent;
 import android.content.Context;
 import android.media.MediaBrowser2;
@@ -27,7 +26,7 @@
 import android.media.MediaLibraryService2;
 import android.media.MediaLibraryService2.MediaLibrarySession;
 import android.media.MediaLibraryService2.MediaLibrarySessionCallback;
-import android.media.MediaPlayerBase;
+import android.media.MediaPlayerInterface;
 import android.media.MediaSession2;
 import android.media.MediaSession2.SessionCallback;
 import android.media.MediaSessionService2;
@@ -57,7 +56,7 @@
             @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes);
 
     MediaSession2Provider createMediaSession2(Context context, MediaSession2 instance,
-            MediaPlayerBase player, String id, VolumeProvider volumeProvider, int ratingType,
+            MediaPlayerInterface player, String id, VolumeProvider volumeProvider, int ratingType,
             PendingIntent sessionActivity, Executor executor, SessionCallback callback);
     ControllerInfoProvider createMediaSession2ControllerInfoProvider(Context context,
             MediaSession2.ControllerInfo instance, int uid, int pid,
@@ -69,7 +68,7 @@
     MediaSessionService2Provider createMediaSessionService2(MediaSessionService2 instance);
     MediaSessionService2Provider createMediaLibraryService2(MediaLibraryService2 instance);
     MediaLibrarySessionProvider createMediaLibraryService2MediaLibrarySession(Context context,
-            MediaLibrarySession instance, MediaPlayerBase player, String id,
+            MediaLibrarySession instance, MediaPlayerInterface player, String id,
             VolumeProvider volumeProvider, int ratingType, PendingIntent sessionActivity,
             Executor executor, MediaLibrarySessionCallback callback);
 }
diff --git a/media/java/android/media/update/VideoView2Provider.java b/media/java/android/media/update/VideoView2Provider.java
index 416ea98..322a4f63 100644
--- a/media/java/android/media/update/VideoView2Provider.java
+++ b/media/java/android/media/update/VideoView2Provider.java
@@ -17,7 +17,9 @@
 package android.media.update;
 
 import android.media.AudioAttributes;
-import android.media.MediaPlayerBase;
+import android.media.MediaPlayerInterface;
+import android.media.session.MediaController;
+import android.media.session.PlaybackState;
 import android.net.Uri;
 import android.widget.MediaControlView2;
 import android.widget.VideoView2;
@@ -41,29 +43,23 @@
 // TODO @SystemApi
 public interface VideoView2Provider extends ViewProvider {
     void setMediaControlView2_impl(MediaControlView2 mediaControlView);
+    MediaController getMediaController_impl();
     MediaControlView2 getMediaControlView2_impl();
-    void start_impl();
-    void pause_impl();
-    int getDuration_impl();
-    int getCurrentPosition_impl();
-    void seekTo_impl(int msec);
-    boolean isPlaying_impl();
-    int getBufferPercentage_impl();
-    int getAudioSessionId_impl();
     void showSubtitle_impl();
     void hideSubtitle_impl();
     void setFullScreen_impl(boolean fullScreen);
+    // TODO: remove setSpeed_impl once MediaController2 is ready.
     void setSpeed_impl(float speed);
-    float getSpeed_impl();
     void setAudioFocusRequest_impl(int focusGain);
     void setAudioAttributes_impl(AudioAttributes attributes);
-    void setRouteAttributes_impl(List<String> routeCategories, MediaPlayerBase player);
+    void setRouteAttributes_impl(List<String> routeCategories, MediaPlayerInterface player);
     void setVideoPath_impl(String path);
-    void setVideoURI_impl(Uri uri);
-    void setVideoURI_impl(Uri uri, Map<String, String> headers);
+    void setVideoUri_impl(Uri uri);
+    void setVideoUri_impl(Uri uri, Map<String, String> headers);
     void setViewType_impl(int viewType);
     int getViewType_impl();
-    void stopPlayback_impl();
+    void setCustomActions_impl(List<PlaybackState.CustomAction> actionList,
+            VideoView2.OnCustomActionListener listener);
     void setOnPreparedListener_impl(VideoView2.OnPreparedListener l);
     void setOnCompletionListener_impl(VideoView2.OnCompletionListener l);
     void setOnErrorListener_impl(VideoView2.OnErrorListener l);
diff --git a/media/java/android/media/update/ViewProvider.java b/media/java/android/media/update/ViewProvider.java
index 78c5b36..0dd8f38 100644
--- a/media/java/android/media/update/ViewProvider.java
+++ b/media/java/android/media/update/ViewProvider.java
@@ -17,8 +17,6 @@
 package android.media.update;
 
 import android.annotation.SystemApi;
-import android.graphics.Canvas;
-import android.view.KeyEvent;
 import android.view.MotionEvent;
 
 /**
@@ -42,8 +40,6 @@
     CharSequence getAccessibilityClassName_impl();
     boolean onTouchEvent_impl(MotionEvent ev);
     boolean onTrackballEvent_impl(MotionEvent ev);
-    boolean onKeyDown_impl(int keyCode, KeyEvent event);
     void onFinishInflate_impl();
-    boolean dispatchKeyEvent_impl(KeyEvent event);
     void setEnabled_impl(boolean enabled);
 }
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index 74f3aca..051c802 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -108,6 +108,9 @@
         "libhidlbase",  // VNDK???
         "libmediandk",  // NDK
         "libpowermanager",  // for JWakeLock. to be removed
+
+        "libutils",  // Have to use shared lib to make libandroid_runtime behave correctly.
+                     // Otherwise, AndroidRuntime::getJNIEnv() will return NULL.
     ],
 
     header_libs: ["libhardware_headers"],
@@ -141,7 +144,6 @@
         "libstagefright_rtsp",
         "libstagefright_timedtext",
         "libunwindstack",
-        "libutils",
         "libutilscallstack",
         "libvndksupport",
         "libz",
diff --git a/media/jni/android_media_MediaExtractor.cpp b/media/jni/android_media_MediaExtractor.cpp
index 5c90d00..a855526 100644
--- a/media/jni/android_media_MediaExtractor.cpp
+++ b/media/jni/android_media_MediaExtractor.cpp
@@ -244,6 +244,10 @@
     return mImpl->getSampleTime(sampleTimeUs);
 }
 
+status_t JMediaExtractor::getSampleSize(size_t *sampleSize) {
+    return mImpl->getSampleSize(sampleSize);
+}
+
 status_t JMediaExtractor::getSampleFlags(uint32_t *sampleFlags) {
     *sampleFlags = 0;
 
@@ -505,6 +509,28 @@
     return (jlong) sampleTimeUs;
 }
 
+static jlong android_media_MediaExtractor_getSampleSize(
+        JNIEnv *env, jobject thiz) {
+    sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
+
+    if (extractor == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        return -1ll;
+    }
+
+    size_t sampleSize;
+    status_t err = extractor->getSampleSize(&sampleSize);
+
+    if (err == ERROR_END_OF_STREAM) {
+        return -1ll;
+    } else if (err != OK) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+        return -1ll;
+    }
+
+    return (jlong) sampleSize;
+}
+
 static jint android_media_MediaExtractor_getSampleFlags(
         JNIEnv *env, jobject thiz) {
     sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
@@ -884,6 +910,9 @@
     { "getSampleTime", "()J",
         (void *)android_media_MediaExtractor_getSampleTime },
 
+    { "getSampleSize", "()J",
+        (void *)android_media_MediaExtractor_getSampleSize },
+
     { "getSampleFlags", "()I",
         (void *)android_media_MediaExtractor_getSampleFlags },
 
diff --git a/media/jni/android_media_MediaExtractor.h b/media/jni/android_media_MediaExtractor.h
index a4638ac..aaa8421 100644
--- a/media/jni/android_media_MediaExtractor.h
+++ b/media/jni/android_media_MediaExtractor.h
@@ -60,6 +60,7 @@
     status_t readSampleData(jobject byteBuf, size_t offset, size_t *sampleSize);
     status_t getSampleTrackIndex(size_t *trackIndex);
     status_t getSampleTime(int64_t *sampleTimeUs);
+    status_t getSampleSize(size_t *sampleSize);
     status_t getSampleFlags(uint32_t *sampleFlags);
     status_t getSampleMeta(sp<MetaData> *sampleMeta);
     status_t getMetrics(Parcel *reply) const;
diff --git a/media/jni/android_media_MediaPlayer2.cpp b/media/jni/android_media_MediaPlayer2.cpp
index 3bf0b37..90ee8a6 100644
--- a/media/jni/android_media_MediaPlayer2.cpp
+++ b/media/jni/android_media_MediaPlayer2.cpp
@@ -1165,51 +1165,6 @@
     ;
 }
 
-// Pass through the arguments to the MediaServer player implementation.
-static jint android_media_MediaPlayer2_applyVolumeShaper(JNIEnv *env, jobject thiz,
-        jobject jconfig, jobject joperation) {
-    // NOTE: hard code here to prevent platform issues. Must match VolumeShaper.java
-    const int VOLUME_SHAPER_INVALID_OPERATION = -38;
-
-    sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
-    if (mp == nullptr) {
-        return (jint)VOLUME_SHAPER_INVALID_OPERATION;
-    }
-
-    sp<VolumeShaper::Configuration> configuration;
-    sp<VolumeShaper::Operation> operation;
-    if (jconfig != nullptr) {
-        configuration = VolumeShaperHelper::convertJobjectToConfiguration(
-                env, gVolumeShaperFields, jconfig);
-        ALOGV("applyVolumeShaper configuration: %s", configuration->toString().c_str());
-    }
-    if (joperation != nullptr) {
-        operation = VolumeShaperHelper::convertJobjectToOperation(
-                env, gVolumeShaperFields, joperation);
-        ALOGV("applyVolumeShaper operation: %s", operation->toString().c_str());
-    }
-    VolumeShaper::Status status = mp->applyVolumeShaper(configuration, operation);
-    if (status == INVALID_OPERATION) {
-        status = VOLUME_SHAPER_INVALID_OPERATION;
-    }
-    return (jint)status; // if status < 0 an error, else a VolumeShaper id
-}
-
-// Pass through the arguments to the MediaServer player implementation.
-static jobject android_media_MediaPlayer2_getVolumeShaperState(JNIEnv *env, jobject thiz,
-        jint id) {
-    sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
-    if (mp == nullptr) {
-        return (jobject)nullptr;
-    }
-
-    sp<VolumeShaper::State> state = mp->getVolumeShaperState((int)id);
-    if (state.get() == nullptr) {
-        return (jobject)nullptr;
-    }
-    return VolumeShaperHelper::convertStateToJobject(env, gVolumeShaperFields, state);
-}
-
 /////////////////////////////////////////////////////////////////////////////////////
 // Modular DRM begin
 
@@ -1465,12 +1420,6 @@
     {"attachAuxEffect",     "(I)V",                             (void *)android_media_MediaPlayer2_attachAuxEffect},
     {"native_setRetransmitEndpoint", "(Ljava/lang/String;I)I",  (void *)android_media_MediaPlayer2_setRetransmitEndpoint},
     {"setNextMediaPlayer",  "(Landroid/media/MediaPlayer2;)V",  (void *)android_media_MediaPlayer2_setNextMediaPlayer},
-    {"native_applyVolumeShaper",
-                            "(Landroid/media/VolumeShaper$Configuration;Landroid/media/VolumeShaper$Operation;)I",
-                                                                (void *)android_media_MediaPlayer2_applyVolumeShaper},
-    {"native_getVolumeShaperState",
-                            "(I)Landroid/media/VolumeShaper$State;",
-                                                                (void *)android_media_MediaPlayer2_getVolumeShaperState},
     // Modular DRM
     { "_prepareDrm", "([B[B)V",                                 (void *)android_media_MediaPlayer2_prepareDrm },
     { "_releaseDrm", "()V",                                     (void *)android_media_MediaPlayer2_releaseDrm },
diff --git a/native/android/asset_manager.cpp b/native/android/asset_manager.cpp
index e70d5ea..98e9a42 100644
--- a/native/android/asset_manager.cpp
+++ b/native/android/asset_manager.cpp
@@ -18,11 +18,9 @@
 #include <utils/Log.h>
 
 #include <android/asset_manager_jni.h>
-#include <android_runtime/android_util_AssetManager.h>
 #include <androidfw/Asset.h>
 #include <androidfw/AssetDir.h>
 #include <androidfw/AssetManager.h>
-#include <androidfw/AssetManager2.h>
 #include <utils/threads.h>
 
 #include "jni.h"
@@ -37,20 +35,21 @@
 
 // -----
 struct AAssetDir {
-    std::unique_ptr<AssetDir> mAssetDir;
+    AssetDir* mAssetDir;
     size_t mCurFileIndex;
     String8 mCachedFileName;
 
-    explicit AAssetDir(std::unique_ptr<AssetDir> dir) :
-        mAssetDir(std::move(dir)), mCurFileIndex(0) { }
+    explicit AAssetDir(AssetDir* dir) : mAssetDir(dir), mCurFileIndex(0) { }
+    ~AAssetDir() { delete mAssetDir; }
 };
 
 
 // -----
 struct AAsset {
-    std::unique_ptr<Asset> mAsset;
+    Asset* mAsset;
 
-    explicit AAsset(std::unique_ptr<Asset> asset) : mAsset(std::move(asset)) { }
+    explicit AAsset(Asset* asset) : mAsset(asset) { }
+    ~AAsset() { delete mAsset; }
 };
 
 // -------------------- Public native C API --------------------
@@ -105,18 +104,19 @@
         return NULL;
     }
 
-    ScopedLock<AssetManager2> locked_mgr(*AssetManagerForNdkAssetManager(amgr));
-    std::unique_ptr<Asset> asset = locked_mgr->Open(filename, amMode);
-    if (asset == nullptr) {
-        return nullptr;
+    AssetManager* mgr = static_cast<AssetManager*>(amgr);
+    Asset* asset = mgr->open(filename, amMode);
+    if (asset == NULL) {
+        return NULL;
     }
-    return new AAsset(std::move(asset));
+
+    return new AAsset(asset);
 }
 
 AAssetDir* AAssetManager_openDir(AAssetManager* amgr, const char* dirName)
 {
-    ScopedLock<AssetManager2> locked_mgr(*AssetManagerForNdkAssetManager(amgr));
-    return new AAssetDir(locked_mgr->OpenDir(dirName));
+    AssetManager* mgr = static_cast<AssetManager*>(amgr);
+    return new AAssetDir(mgr->openDir(dirName));
 }
 
 /**
diff --git a/packages/MtpDocumentsProvider/AndroidManifest.xml b/packages/MtpDocumentsProvider/AndroidManifest.xml
index c0a59b3..8d79f62 100644
--- a/packages/MtpDocumentsProvider/AndroidManifest.xml
+++ b/packages/MtpDocumentsProvider/AndroidManifest.xml
@@ -3,7 +3,6 @@
           package="com.android.mtp"
           android:sharedUserId="android.media">
     <uses-feature android:name="android.hardware.usb.host" />
-    <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
     <uses-permission android:name="android.permission.MANAGE_USB" />
     <application android:label="@string/app_label">
         <provider
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 6970c86..b286f89 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -103,21 +103,6 @@
                 Settings.Global.THEATER_MODE_ON,
                 GlobalSettingsProto.THEATER_MODE_ON);
         dumpSetting(s, p,
-                Settings.Global.RADIO_BLUETOOTH,
-                GlobalSettingsProto.RADIO_BLUETOOTH);
-        dumpSetting(s, p,
-                Settings.Global.RADIO_WIFI,
-                GlobalSettingsProto.RADIO_WIFI);
-        dumpSetting(s, p,
-                Settings.Global.RADIO_WIMAX,
-                GlobalSettingsProto.RADIO_WIMAX);
-        dumpSetting(s, p,
-                Settings.Global.RADIO_CELL,
-                GlobalSettingsProto.RADIO_CELL);
-        dumpSetting(s, p,
-                Settings.Global.RADIO_NFC,
-                GlobalSettingsProto.RADIO_NFC);
-        dumpSetting(s, p,
                 Settings.Global.AIRPLANE_MODE_RADIOS,
                 GlobalSettingsProto.AIRPLANE_MODE_RADIOS);
         dumpSetting(s, p,
@@ -592,6 +577,9 @@
                 Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED,
                 GlobalSettingsProto.WIFI_VERBOSE_LOGGING_ENABLED);
         dumpSetting(s, p,
+                Settings.Global.WIFI_CONNECTED_MAC_RANDOMIZATION_ENABLED,
+                GlobalSettingsProto.WIFI_CONNECTED_MAC_RANDOMIZATION_ENABLED);
+        dumpSetting(s, p,
                 Settings.Global.WIFI_MAX_DHCP_RETRY_COUNT,
                 GlobalSettingsProto.WIFI_MAX_DHCP_RETRY_COUNT);
         dumpSetting(s, p,
@@ -1067,6 +1055,9 @@
                 Settings.Global.STORAGE_SETTINGS_CLOBBER_THRESHOLD,
                 GlobalSettingsProto.STORAGE_SETTINGS_CLOBBER_THRESHOLD);
         dumpSetting(s, p,
+                Global.CHAINED_BATTERY_ATTRIBUTION_ENABLED,
+                GlobalSettingsProto.CHAINED_BATTERY_ATTRIBUTION_ENABLED);
+        dumpSetting(s, p,
                 Settings.Global.MULTI_SIM_VOICE_CALL_SUBSCRIPTION,
                 GlobalSettingsProto.MULTI_SIM_VOICE_CALL_SUBSCRIPTION);
         dumpSetting(s, p,
@@ -1130,20 +1121,13 @@
                 Settings.Global.SHOW_FIRST_CRASH_DIALOG,
                 GlobalSettingsProto.SHOW_FIRST_CRASH_DIALOG);
         dumpSetting(s, p,
-                Settings.Global.WIFI_CONNECTED_MAC_RANDOMIZATION_ENABLED,
-                GlobalSettingsProto.WIFI_CONNECTED_MAC_RANDOMIZATION_ENABLED);
-        dumpSetting(s, p,
                 Settings.Global.SHOW_RESTART_IN_CRASH_DIALOG,
                 GlobalSettingsProto.SHOW_RESTART_IN_CRASH_DIALOG);
         dumpSetting(s, p,
                 Settings.Global.SHOW_MUTE_IN_CRASH_DIALOG,
                 GlobalSettingsProto.SHOW_MUTE_IN_CRASH_DIALOG);
-        dumpSetting(s, p,
-                Settings.Global.WIFI_CONNECTED_MAC_RANDOMIZATION_ENABLED,
-                GlobalSettingsProto.WIFI_CONNECTED_MAC_RANDOMIZATION_ENABLED);
-        dumpSetting(s, p,
-                Global.CHAINED_BATTERY_ATTRIBUTION_ENABLED,
-                GlobalSettingsProto.CHAINED_BATTERY_ATTRIBUTION_ENABLED);
+
+        // Please insert new settings using the same order as in Settings.Global.
     }
 
     /** Dump a single {@link SettingsState.Setting} to a proto buf */
@@ -1771,6 +1755,8 @@
         dumpSetting(s, p,
                 Settings.Secure.BLUETOOTH_ON_WHILE_DRIVING,
                 SecureSettingsProto.BLUETOOTH_ON_WHILE_DRIVING);
+
+        // Please insert new settings using the same order as in Settings.Secure.
     }
 
     private static void dumpProtoSystemSettingsLocked(
@@ -2029,5 +2015,7 @@
                 SystemSettingsProto.WHEN_TO_MAKE_WIFI_CALLS);
         // The rest of the settings were moved to Settings.Secure, and are thus excluded here since
         // they're deprecated from Settings.System.
+
+        // Please insert new settings using the same order as in Settings.System.
     }
 }
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 79299aa..64b2ae6 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -44,7 +44,6 @@
     <uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
     <uses-permission android:name="android.permission.MANAGE_USB" />
     <uses-permission android:name="android.permission.USE_RESERVED_DISK" />
-    <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
     <!-- System tool permissions granted to the shell. -->
     <uses-permission android:name="android.permission.REAL_GET_TASKS" />
     <uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
index cc4bc58..da50776 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
@@ -29,4 +29,9 @@
      */
     GraphicBufferCompat screenshot(in Rect sourceCrop, int width, int height, int minLayer,
             int maxLayer, boolean useIdentityTransform, int rotation);
+
+    /**
+     * Called when the overview service has started the recents animation.
+     */
+    void onRecentsAnimationStarted();
 }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
index c9a6ea9..f9e1069 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -32,6 +32,7 @@
 import android.app.IAssistDataReceiver;
 import android.app.WindowConfiguration.ActivityType;
 import android.content.Context;
+import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
@@ -48,7 +49,10 @@
 import android.os.UserHandle;
 import android.util.IconDrawableFactory;
 import android.util.Log;
+import android.view.IRecentsAnimationController;
+import android.view.IRecentsAnimationRunner;
 
+import android.view.RemoteAnimationTarget;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.recents.model.Task.TaskKey;
 import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -243,10 +247,9 @@
     /**
      * Starts the recents activity. The caller should manage the thread on which this is called.
      */
-    public void startRecentsActivity(AssistDataReceiverCompat assistDataReceiver, Bundle options,
-            ActivityOptions opts, int userId, Consumer<Boolean> resultCallback,
+    public void startRecentsActivity(Intent intent, AssistDataReceiver assistDataReceiver,
+            RecentsAnimationListener animationHandler, Consumer<Boolean> resultCallback,
             Handler resultCallbackHandler) {
-        Bundle activityOptions = opts != null ? opts.toBundle() : null;
         try {
             IAssistDataReceiver receiver = null;
             if (assistDataReceiver != null) {
@@ -259,8 +262,24 @@
                     }
                 };
             }
-            ActivityManager.getService().startRecentsActivity(receiver, options, activityOptions,
-                    userId);
+            IRecentsAnimationRunner runner = null;
+            if (animationHandler != null) {
+                runner = new IRecentsAnimationRunner.Stub() {
+                    public void onAnimationStart(IRecentsAnimationController controller,
+                            RemoteAnimationTarget[] apps) {
+                        final RecentsAnimationControllerCompat controllerCompat =
+                                new RecentsAnimationControllerCompat(controller);
+                        final RemoteAnimationTargetCompat[] appsCompat =
+                                RemoteAnimationTargetCompat.wrap(apps);
+                        animationHandler.onAnimationStart(controllerCompat, appsCompat);
+                    }
+
+                    public void onAnimationCanceled() {
+                        animationHandler.onAnimationCanceled();
+                    }
+                };
+            }
+            ActivityManager.getService().startRecentsActivity(intent, receiver, runner);
             if (resultCallback != null) {
                 resultCallbackHandler.post(new Runnable() {
                     @Override
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/AssistDataReceiverCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/AssistDataReceiver.java
similarity index 80%
rename from packages/SystemUI/shared/src/com/android/systemui/shared/system/AssistDataReceiverCompat.java
rename to packages/SystemUI/shared/src/com/android/systemui/shared/system/AssistDataReceiver.java
index cd943f6..7cd6c51 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/AssistDataReceiverCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/AssistDataReceiver.java
@@ -22,7 +22,7 @@
 /**
  * Abstract class for assist data receivers.
  */
-public abstract class AssistDataReceiverCompat {
-    public abstract void onHandleAssistData(Bundle resultData);
-    public abstract void onHandleAssistScreenshot(Bitmap screenshot);
+public abstract class AssistDataReceiver {
+    public void onHandleAssistData(Bundle resultData) {}
+    public void onHandleAssistScreenshot(Bitmap screenshot) {}
 }
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/InputConsumerController.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputConsumerController.java
similarity index 70%
rename from packages/SystemUI/src/com/android/systemui/pip/phone/InputConsumerController.java
rename to packages/SystemUI/shared/src/com/android/systemui/shared/system/InputConsumerController.java
index db4f988..38b8ae8 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/InputConsumerController.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputConsumerController.java
@@ -14,9 +14,10 @@
  * limitations under the License.
  */
 
-package com.android.systemui.pip.phone;
+package com.android.systemui.shared.system;
 
 import static android.view.WindowManager.INPUT_CONSUMER_PIP;
+import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION;
 
 import android.os.Binder;
 import android.os.IBinder;
@@ -29,11 +30,12 @@
 import android.view.InputEvent;
 import android.view.IWindowManager;
 import android.view.MotionEvent;
+import android.view.WindowManagerGlobal;
 
 import java.io.PrintWriter;
 
 /**
- * Manages the input consumer that allows the SystemUI to control the PiP.
+ * Manages the input consumer that allows the SystemUI to directly receive touch input.
  */
 public class InputConsumerController {
 
@@ -55,12 +57,12 @@
     }
 
     /**
-     * Input handler used for the PiP input consumer. Input events are batched and consumed with the
+     * Input handler used for the input consumer. Input events are batched and consumed with the
      * SurfaceFlinger vsync.
      */
-    private final class PipInputEventReceiver extends BatchedInputEventReceiver {
+    private final class InputEventReceiver extends BatchedInputEventReceiver {
 
-        public PipInputEventReceiver(InputChannel inputChannel, Looper looper) {
+        public InputEventReceiver(InputChannel inputChannel, Looper looper) {
             super(inputChannel, looper, Choreographer.getSfInstance());
         }
 
@@ -68,7 +70,6 @@
         public void onInputEvent(InputEvent event, int displayId) {
             boolean handled = true;
             try {
-                // To be implemented for input handling over Pip windows
                 if (mListener != null && event instanceof MotionEvent) {
                     MotionEvent ev = (MotionEvent) event;
                     handled = mListener.onTouchEvent(ev);
@@ -81,15 +82,35 @@
 
     private final IWindowManager mWindowManager;
     private final IBinder mToken;
+    private final String mName;
 
-    private PipInputEventReceiver mInputEventReceiver;
+    private InputEventReceiver mInputEventReceiver;
     private TouchListener mListener;
     private RegistrationListener mRegistrationListener;
 
-    public InputConsumerController(IWindowManager windowManager) {
+    /**
+     * @param name the name corresponding to the input consumer that is defined in the system.
+     */
+    public InputConsumerController(IWindowManager windowManager, String name) {
         mWindowManager = windowManager;
         mToken = new Binder();
-        registerInputConsumer();
+        mName = name;
+    }
+
+    /**
+     * @return A controller for the pip input consumer.
+     */
+    public static InputConsumerController getPipInputConsumer() {
+        return new InputConsumerController(WindowManagerGlobal.getWindowManagerService(),
+                INPUT_CONSUMER_PIP);
+    }
+
+    /**
+     * @return A controller for the recents animation input consumer.
+     */
+    public static InputConsumerController getRecentsAnimationInputConsumer() {
+        return new InputConsumerController(WindowManagerGlobal.getWindowManagerService(),
+                INPUT_CONSUMER_RECENTS_ANIMATION);
     }
 
     /**
@@ -125,12 +146,12 @@
         if (mInputEventReceiver == null) {
             final InputChannel inputChannel = new InputChannel();
             try {
-                mWindowManager.destroyInputConsumer(INPUT_CONSUMER_PIP);
-                mWindowManager.createInputConsumer(mToken, INPUT_CONSUMER_PIP, inputChannel);
+                mWindowManager.destroyInputConsumer(mName);
+                mWindowManager.createInputConsumer(mToken, mName, inputChannel);
             } catch (RemoteException e) {
-                Log.e(TAG, "Failed to create PIP input consumer", e);
+                Log.e(TAG, "Failed to create input consumer", e);
             }
-            mInputEventReceiver = new PipInputEventReceiver(inputChannel, Looper.myLooper());
+            mInputEventReceiver = new InputEventReceiver(inputChannel, Looper.myLooper());
             if (mRegistrationListener != null) {
                 mRegistrationListener.onRegistrationChanged(true /* isRegistered */);
             }
@@ -143,9 +164,9 @@
     public void unregisterInputConsumer() {
         if (mInputEventReceiver != null) {
             try {
-                mWindowManager.destroyInputConsumer(INPUT_CONSUMER_PIP);
+                mWindowManager.destroyInputConsumer(mName);
             } catch (RemoteException e) {
-                Log.e(TAG, "Failed to destroy PIP input consumer", e);
+                Log.e(TAG, "Failed to destroy input consumer", e);
             }
             mInputEventReceiver.dispose();
             mInputEventReceiver = null;
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
new file mode 100644
index 0000000..9a7abf8
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.shared.system;
+
+import android.app.ActivityManager.TaskSnapshot;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.IRecentsAnimationController;
+
+import com.android.systemui.shared.recents.model.ThumbnailData;
+
+public class RecentsAnimationControllerCompat {
+
+    private static final String TAG = RecentsAnimationControllerCompat.class.getSimpleName();
+
+    private IRecentsAnimationController mAnimationController;
+
+    public RecentsAnimationControllerCompat(IRecentsAnimationController animationController) {
+        mAnimationController = animationController;
+    }
+
+    public ThumbnailData screenshotTask(int taskId) {
+        try {
+            TaskSnapshot snapshot = mAnimationController.screenshotTask(taskId);
+            return snapshot != null ? new ThumbnailData(snapshot) : new ThumbnailData();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to screenshot task", e);
+            return new ThumbnailData();
+        }
+    }
+
+    public void setInputConsumerEnabled(boolean enabled) {
+        try {
+            mAnimationController.setInputConsumerEnabled(enabled);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to set input consumer enabled state", e);
+        }
+    }
+
+    public void finish(boolean toHome) {
+        try {
+            mAnimationController.finish(toHome);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to finish recents animation", e);
+        }
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/AssistDataReceiverCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java
similarity index 60%
copy from packages/SystemUI/shared/src/com/android/systemui/shared/system/AssistDataReceiverCompat.java
copy to packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java
index cd943f6..bf6179d 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/AssistDataReceiverCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java
@@ -16,13 +16,16 @@
 
 package com.android.systemui.shared.system;
 
-import android.graphics.Bitmap;
-import android.os.Bundle;
+public interface RecentsAnimationListener {
 
-/**
- * Abstract class for assist data receivers.
- */
-public abstract class AssistDataReceiverCompat {
-    public abstract void onHandleAssistData(Bundle resultData);
-    public abstract void onHandleAssistScreenshot(Bitmap screenshot);
-}
+    /**
+     * Called when the animation into Recents can start. This call is made on the binder thread.
+     */
+    void onAnimationStart(RecentsAnimationControllerCompat controller,
+            RemoteAnimationTargetCompat[] apps);
+
+    /**
+     * Called when the animation into Recents was canceled. This call is made on the binder thread.
+     */
+    void onAnimationCanceled();
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
index 9ff6815..cb732c4 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
@@ -51,6 +51,8 @@
 import androidx.app.slice.Slice;
 import androidx.app.slice.SliceItem;
 import androidx.app.slice.core.SliceQuery;
+import androidx.app.slice.widget.ListContent;
+import androidx.app.slice.widget.RowContent;
 import androidx.app.slice.widget.SliceLiveData;
 
 /**
@@ -115,25 +117,17 @@
 
     private void showSlice(Slice slice) {
 
-        // Main area
-        SliceItem mainItem = SliceQuery.find(slice, android.app.slice.SliceItem.FORMAT_SLICE,
-                null /* hints */, new String[]{android.app.slice.Slice.HINT_LIST_ITEM});
-        mHasHeader = mainItem != null;
-
-        List<SliceItem> subItems = SliceQuery.findAll(slice,
-                android.app.slice.SliceItem.FORMAT_SLICE,
-                new String[]{android.app.slice.Slice.HINT_LIST_ITEM},
-                null /* nonHints */);
-
+        ListContent lc = new ListContent(slice);
+        mHasHeader = lc.hasHeader();
+        List<SliceItem> subItems = lc.getRowItems();
         if (!mHasHeader) {
             mTitle.setVisibility(GONE);
         } else {
             mTitle.setVisibility(VISIBLE);
-            SliceItem mainTitle = SliceQuery.find(mainItem.getSlice(),
-                    android.app.slice.SliceItem.FORMAT_TEXT,
-                    new String[]{android.app.slice.Slice.HINT_TITLE},
-                    null /* nonHints */);
-            CharSequence title = mainTitle.getText();
+            // If there's a header it'll be the first subitem
+            RowContent header = new RowContent(subItems.get(0), true /* showStartItem */);
+            SliceItem mainTitle = header.getTitleItem();
+            CharSequence title = mainTitle != null ? mainTitle.getText() : null;
             mTitle.setText(title);
 
             // Check if we're already ellipsizing the text.
@@ -152,9 +146,10 @@
         mClickActions.clear();
         final int subItemsCount = subItems.size();
         final int blendedColor = getTextColor();
-
-        for (int i = 0; i < subItemsCount; i++) {
+        final int startIndex = mHasHeader ? 1 : 0; // First item is header; skip it
+        for (int i = startIndex; i < subItemsCount; i++) {
             SliceItem item = subItems.get(i);
+            RowContent rc = new RowContent(item, true /* showStartItem */);
             final Uri itemTag = item.getSlice().getUri();
             // Try to reuse the view if already exists in the layout
             KeyguardSliceButton button = mRow.findViewWithTag(itemTag);
@@ -168,20 +163,13 @@
             button.setHasDivider(i < subItemsCount - 1);
             mRow.addView(button, i);
 
-            PendingIntent pendingIntent;
-            try {
-                pendingIntent = item.getAction();
-            } catch (RuntimeException e) {
-                Log.w(TAG, "Cannot retrieve action from keyguard slice", e);
-                pendingIntent = null;
+            PendingIntent pendingIntent = null;
+            if (rc.getContentIntent() != null) {
+                pendingIntent = rc.getContentIntent().getAction();
             }
             mClickActions.put(button, pendingIntent);
 
-            SliceItem title = SliceQuery.find(item.getSlice(),
-                    android.app.slice.SliceItem.FORMAT_TEXT,
-                    new String[]{android.app.slice.Slice.HINT_TITLE},
-                    null /* nonHints */);
-            button.setText(title.getText());
+            button.setText(rc.getTitleItem().getText());
 
             Drawable iconDrawable = null;
             SliceItem icon = SliceQuery.find(item.getSlice(),
diff --git a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
index 244c1b9..b6e49ae 100644
--- a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
@@ -77,6 +77,15 @@
                 Binder.restoreCallingIdentity(token);
             }
         }
+
+        public void onRecentsAnimationStarted() {
+            long token = Binder.clearCallingIdentity();
+            try {
+                notifyRecentsAnimationStarted();
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
     };
 
     private final BroadcastReceiver mLauncherAddedReceiver = new BroadcastReceiver() {
@@ -214,6 +223,12 @@
         }
     }
 
+    private void notifyRecentsAnimationStarted() {
+        for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
+            mConnectionCallbacks.get(i).onRecentsAnimationStarted();
+        }
+    }
+
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println(TAG_OPS + " state:");
@@ -224,6 +239,7 @@
     }
 
     public interface OverviewProxyListener {
-        void onConnectionChanged(boolean isConnected);
+        default void onConnectionChanged(boolean isConnected) {}
+        default void onRecentsAnimationStarted() {}
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
index 36531bb..24d0126 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
@@ -16,12 +16,10 @@
 
 package com.android.systemui.pip.phone;
 
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
-import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.WindowManager.INPUT_CONSUMER_PIP;
 
 import android.app.ActivityManager;
-import android.app.ActivityManager.StackInfo;
 import android.app.IActivityManager;
 import android.content.ComponentName;
 import android.content.Context;
@@ -43,6 +41,7 @@
 import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.InputConsumerController;
 
 import java.io.PrintWriter;
 
@@ -174,7 +173,8 @@
         }
         ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
 
-        mInputConsumerController = new InputConsumerController(mWindowManager);
+        mInputConsumerController = InputConsumerController.getPipInputConsumer();
+        mInputConsumerController.registerInputConsumer();
         mMediaController = new PipMediaController(context, mActivityManager);
         mMenuController = new PipMenuActivityController(context, mActivityManager, mMediaController,
                 mInputConsumerController);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
index 9fb201b..26fced3 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
@@ -23,7 +23,6 @@
 import android.app.ActivityOptions;
 import android.app.IActivityManager;
 import android.app.RemoteAction;
-import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ParceledListSlice;
@@ -43,6 +42,7 @@
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.recents.events.component.HidePipMenuEvent;
 import com.android.systemui.recents.misc.ReferenceCountedTrigger;
+import com.android.systemui.shared.system.InputConsumerController;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index c0fed34..b253517 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -46,6 +46,7 @@
 import com.android.internal.os.logging.MetricsLoggerWrapper;
 import com.android.internal.policy.PipSnapAlgorithm;
 import com.android.systemui.R;
+import com.android.systemui.shared.system.InputConsumerController;
 import com.android.systemui.statusbar.FlingAnimationUtils;
 
 import java.io.PrintWriter;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 29a8f16..669439d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -285,17 +285,22 @@
         int heightDiff = mQSPanel.getBottom() - mHeader.getBottom() + mHeader.getPaddingBottom()
                 + mFooter.getHeight();
         mQSPanel.setTranslationY(translationScaleY * heightDiff);
-        mQSDetail.setFullyExpanded(expansion == 1);
+        boolean fullyExpanded = expansion == 1;
+        mQSDetail.setFullyExpanded(fullyExpanded);
+        if (fullyExpanded) {
+            // Always draw within the bounds of the view when fully expanded.
+            mQSPanel.setClipBounds(null);
+        } else {
+            // Set bounds on the QS panel so it doesn't run over the header when animating.
+            mQsBounds.top = (int) -mQSPanel.getTranslationY();
+            mQsBounds.right = mQSPanel.getWidth();
+            mQsBounds.bottom = mQSPanel.getHeight();
+            mQSPanel.setClipBounds(mQsBounds);
+        }
 
         if (mQSAnimator != null) {
             mQSAnimator.setPosition(expansion);
         }
-
-        // Set bounds on the QS panel so it doesn't run over the header.
-        mQsBounds.top = (int) -mQSPanel.getTranslationY();
-        mQsBounds.right = mQSPanel.getWidth();
-        mQsBounds.bottom = mQSPanel.getHeight();
-        mQSPanel.setClipBounds(mQsBounds);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index eb2e519..aaf6ef5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -76,9 +76,6 @@
     private static final String ACTION_SET_VISIBLE = "com.android.systemui.dndtile.SET_VISIBLE";
     private static final String EXTRA_VISIBLE = "visible";
 
-    private static final QSTile.Icon TOTAL_SILENCE =
-            ResourceIcon.get(R.drawable.ic_qs_dnd_on_total_silence);
-
     private final ZenModeController mController;
     private final DndDetailAdapter mDetailAdapter;
 
@@ -201,25 +198,22 @@
         state.slash.isSlashed = !state.value;
         state.label = getTileLabel();
         state.secondaryLabel = getSecondaryLabel(zen != Global.ZEN_MODE_OFF);
+        state.icon = ResourceIcon.get(R.drawable.ic_qs_dnd_on);
         checkIfRestrictionEnforcedByAdminOnly(state, UserManager.DISALLOW_ADJUST_VOLUME);
         switch (zen) {
             case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
-                state.icon = ResourceIcon.get(R.drawable.ic_qs_dnd_on);
                 state.contentDescription = mContext.getString(
                         R.string.accessibility_quick_settings_dnd_priority_on);
                 break;
             case Global.ZEN_MODE_NO_INTERRUPTIONS:
-                state.icon = TOTAL_SILENCE;
                 state.contentDescription = mContext.getString(
                         R.string.accessibility_quick_settings_dnd_none_on);
                 break;
             case ZEN_MODE_ALARMS:
-                state.icon = ResourceIcon.get(R.drawable.ic_qs_dnd_on);
                 state.contentDescription = mContext.getString(
                         R.string.accessibility_quick_settings_dnd_alarms_on);
                 break;
             default:
-                state.icon = ResourceIcon.get(R.drawable.ic_qs_dnd_on);
                 state.contentDescription = mContext.getString(
                         R.string.accessibility_quick_settings_dnd);
                 break;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 1056ecc..b3f68d3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -1472,7 +1472,6 @@
         return mPrivateLayout.getActiveRemoteInputText();
     }
 
-
     public void animateTranslateNotification(final float leftTarget) {
         if (mTranslateAnim != null) {
             mTranslateAnim.cancel();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
index 8336d29..907af69 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
@@ -19,6 +19,7 @@
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ValueAnimator;
+import android.app.ActivityManager;
 import android.app.ActivityOptions;
 import android.graphics.Matrix;
 import android.graphics.Rect;
@@ -35,10 +36,11 @@
 import com.android.systemui.Interpolators;
 import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.NotificationListContainer;
+import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.phone.CollapsedStatusBarFragment;
 import com.android.systemui.statusbar.phone.NotificationPanelView;
+import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.phone.StatusBarWindowView;
-import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
 
 import java.util.function.Consumer;
 
@@ -57,16 +59,17 @@
     private final NotificationPanelView mNotificationPanel;
     private final NotificationListContainer mNotificationContainer;
     private final StatusBarWindowView mStatusBarWindow;
-    private final Consumer<Boolean> mPanelCollapser;
+    private final StatusBar mStatusBar;
+    private boolean mAnimationPending;
 
     public ActivityLaunchAnimator(StatusBarWindowView statusBarWindow,
-            Consumer<Boolean> panelCollapser,
+            StatusBar statusBar,
             NotificationPanelView notificationPanel,
             NotificationListContainer container) {
         mNotificationPanel = notificationPanel;
         mNotificationContainer = container;
         mStatusBarWindow = statusBarWindow;
-        mPanelCollapser = panelCollapser;
+        mStatusBar = statusBar;
     }
 
     public ActivityOptions getLaunchAnimation(
@@ -76,6 +79,21 @@
                 new RemoteAnimationAdapter(animationRunner, 1000 /* Duration */, 0 /* delay */));
     }
 
+    public boolean isAnimationPending() {
+        return mAnimationPending;
+    }
+
+    public void setLaunchResult(int launchResult) {
+        setAnimationPending((launchResult == ActivityManager.START_TASK_TO_FRONT
+                || launchResult == ActivityManager.START_SUCCESS)
+                        && mStatusBar.getBarState() == StatusBarState.SHADE);
+    }
+
+    private void setAnimationPending(boolean pending) {
+        mAnimationPending = pending;
+        mStatusBarWindow.setExpandAnimationPending(pending);
+    }
+
     class AnimationRunner extends IRemoteAnimationRunner.Stub {
 
         private final ExpandableNotificationRow mSourceNotification;
@@ -94,7 +112,6 @@
                 IRemoteAnimationFinishedCallback iRemoteAnimationFinishedCallback)
                     throws RemoteException {
             mSourceNotification.post(() -> {
-                boolean first = true;
                 for (RemoteAnimationTarget app : remoteAnimationTargets) {
                     if (app.mode == RemoteAnimationTarget.MODE_OPENING) {
                         setExpandAnimationRunning(true);
@@ -139,7 +156,7 @@
                             public void onAnimationEnd(Animator animation) {
                                 setExpandAnimationRunning(false);
                                 if (mInstantCollapsePanel) {
-                                    mPanelCollapser.accept(false /* animate */);
+                                    mStatusBar.collapsePanel(false /* animate */);
                                 }
                                 try {
                                     iRemoteAnimationFinishedCallback.onAnimationFinished();
@@ -152,6 +169,7 @@
                         break;
                     }
                 }
+                setAnimationPending(false);
             });
         }
 
@@ -198,6 +216,10 @@
 
         @Override
         public void onAnimationCancelled() throws RemoteException {
+            mSourceNotification.post(() -> {
+                setAnimationPending(false);
+                mStatusBar.onLaunchAnimationCancelled();
+            });
         }
     };
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
index dec5303..918b6ed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
@@ -137,8 +137,12 @@
         final View transformedView = mTransformedView;
         boolean transformX = (transformationFlags & TRANSFORM_X) != 0;
         boolean transformY = (transformationFlags & TRANSFORM_Y) != 0;
-        boolean differentHeight = otherState.getViewHeight() != getViewHeight();
-        boolean differentWidth = otherState.getViewWidth() != getViewWidth();
+        int viewHeight = getViewHeight();
+        int otherHeight = otherState.getViewHeight();
+        boolean differentHeight = otherHeight != viewHeight && otherHeight != 0 && viewHeight != 0;
+        int viewWidth = getViewWidth();
+        int otherWidth = otherState.getViewWidth();
+        boolean differentWidth = otherWidth != viewWidth && otherWidth != 0 && viewWidth != 0;
         boolean transformScale = transformScale(otherState) && (differentHeight || differentWidth);
         // lets animate the positions correctly
         if (transformationAmount == 0.0f
@@ -165,15 +169,15 @@
                 // we also want to animate the scale if we're the same
                 View otherView = otherState.getTransformedView();
                 if (transformScale && differentWidth) {
-                    setTransformationStartScaleX(otherState.getViewWidth() * otherView.getScaleX()
-                            / (float) getViewWidth());
+                    setTransformationStartScaleX(otherWidth * otherView.getScaleX()
+                            / (float) viewWidth);
                     transformedView.setPivotX(0);
                 } else {
                     setTransformationStartScaleX(UNDEFINED);
                 }
                 if (transformScale && differentHeight) {
-                    setTransformationStartScaleY(otherState.getViewHeight() * otherView.getScaleY()
-                            / (float) getViewHeight());
+                    setTransformationStartScaleY(otherHeight * otherView.getScaleY()
+                            / (float) viewHeight);
                     transformedView.setPivotY(0);
                 } else {
                     setTransformationStartScaleY(UNDEFINED);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 60631518..5401e74 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -225,7 +225,7 @@
         mNavigationBarView = (NavigationBarView) view;
 
         mNavigationBarView.setDisabledFlags(mDisabledFlags1);
-        mNavigationBarView.setComponents(mRecents, mDivider);
+        mNavigationBarView.setComponents(mRecents, mDivider, mStatusBar.getPanel());
         mNavigationBarView.setOnVerticalChangedListener(this::onVerticalChanged);
         mNavigationBarView.setOnTouchListener(this::onNavigationTouch);
         if (savedInstanceState != null) {
@@ -300,7 +300,7 @@
             boolean showImeSwitcher) {
         boolean imeShown = (vis & InputMethodService.IME_VISIBLE) != 0;
         int hints = mNavigationIconHints;
-        if ((backDisposition == InputMethodService.BACK_DISPOSITION_WILL_DISMISS) || imeShown) {
+        if (imeShown && backDisposition != InputMethodService.BACK_DISPOSITION_WILL_NOT_DISMISS) {
             hints |= NAVIGATION_HINT_BACK_ALT;
         } else {
             hints &= ~NAVIGATION_HINT_BACK_ALT;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
index ff923e5..0954fd0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
@@ -34,6 +34,7 @@
 import com.android.systemui.OverviewProxyService;
 import com.android.systemui.R;
 import com.android.systemui.RecentsComponent;
+import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.plugins.statusbar.phone.NavGesture.GestureHelper;
 import com.android.systemui.shared.recents.IOverviewProxy;
 import com.android.systemui.shared.recents.utilities.Utilities;
@@ -78,6 +79,7 @@
     private final int mScrollTouchSlop;
     private final Matrix mTransformGlobalMatrix = new Matrix();
     private final Matrix mTransformLocalMatrix = new Matrix();
+    private final StatusBar mStatusBar;
     private int mTouchDownX;
     private int mTouchDownY;
     private boolean mDownOnRecents;
@@ -90,6 +92,7 @@
 
     public NavigationBarGestureHelper(Context context) {
         mContext = context;
+        mStatusBar = SysUiServiceProvider.getComponent(context, StatusBar.class);
         Resources r = context.getResources();
         mScrollTouchSlop = r.getDimensionPixelSize(R.dimen.navigation_bar_min_swipe_distance);
         mQuickScrubController = new QuickScrubController(context);
@@ -146,7 +149,8 @@
                 break;
             }
         }
-        if (!mQuickScrubController.onInterceptTouchEvent(event)) {
+        if (mStatusBar.isPresenterFullyCollapsed()
+                && !mQuickScrubController.onInterceptTouchEvent(event)) {
             proxyMotionEvents(event);
             return false;
         }
@@ -304,7 +308,8 @@
     }
 
     public boolean onTouchEvent(MotionEvent event) {
-        boolean result = mQuickScrubController.onTouchEvent(event) || proxyMotionEvents(event);
+        boolean result = mStatusBar.isPresenterFullyCollapsed()
+                && (mQuickScrubController.onTouchEvent(event) || proxyMotionEvents(event));
         if (mDockWindowEnabled) {
             result |= handleDockWindowEvent(event);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 9bef0ee..b5fa523 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -104,6 +104,7 @@
     private DeadZone mDeadZone;
     private final NavigationBarTransitions mBarTransitions;
     private final OverviewProxyService mOverviewProxyService;
+    private boolean mRecentsAnimationStarted;
 
     // workaround for LayoutTransitions leaving the nav buttons in a weird state (bug 5549288)
     final static boolean WORKAROUND_INVALID_LAYOUT = true;
@@ -126,6 +127,7 @@
     private RecentsComponent mRecentsComponent;
     private Divider mDivider;
     private SwipeUpOnboarding mSwipeUpOnboarding;
+    private NotificationPanelView mPanelView;
 
     private class NavTransitionListener implements TransitionListener {
         private boolean mBackTransitioning;
@@ -205,10 +207,18 @@
         }
     }
 
-    private final OverviewProxyListener mOverviewProxyListener = isConnected -> {
-        setSlippery(!isConnected);
-        setDisabledFlags(mDisabledFlags, true);
-        setUpSwipeUpOnboarding(isConnected);
+    private final OverviewProxyListener mOverviewProxyListener = new OverviewProxyListener() {
+        @Override
+        public void onConnectionChanged(boolean isConnected) {
+            updateSlippery();
+            setDisabledFlags(mDisabledFlags, true);
+            setUpSwipeUpOnboarding(isConnected);
+        }
+
+        @Override
+        public void onRecentsAnimationStarted() {
+            mRecentsAnimationStarted = true;
+        }
     };
 
     public NavigationBarView(Context context, AttributeSet attrs) {
@@ -251,9 +261,11 @@
         return mBarTransitions.getLightTransitionsController();
     }
 
-    public void setComponents(RecentsComponent recentsComponent, Divider divider) {
+    public void setComponents(RecentsComponent recentsComponent, Divider divider,
+            NotificationPanelView panel) {
         mRecentsComponent = recentsComponent;
         mDivider = divider;
+        mPanelView = panel;
         if (mGestureHelper instanceof NavigationBarGestureHelper) {
             ((NavigationBarGestureHelper) mGestureHelper).setComponents(
                     recentsComponent, divider, this);
@@ -270,12 +282,26 @@
         if (mGestureHelper.onTouchEvent(event)) {
             return true;
         }
-        return super.onTouchEvent(event);
+        return mRecentsAnimationStarted || super.onTouchEvent(event);
     }
 
     @Override
     public boolean onInterceptTouchEvent(MotionEvent event) {
-        return mGestureHelper.onInterceptTouchEvent(event);
+        int action = event.getActionMasked();
+        if (action == MotionEvent.ACTION_DOWN) {
+            mRecentsAnimationStarted = false;
+        } else if (action == MotionEvent.ACTION_UP) {
+            // If the overview proxy service has not started the recents animation then clean up
+            // after it to ensure that the nav bar buttons still work
+            if (mOverviewProxyService.getProxy() != null && !mRecentsAnimationStarted) {
+                try {
+                    ActivityManager.getService().cancelRecentsAnimation();
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Could not cancel recents animation");
+                }
+            }
+        }
+        return mRecentsAnimationStarted || mGestureHelper.onInterceptTouchEvent(event);
     }
 
     public void abortCurrentGesture() {
@@ -571,6 +597,14 @@
         }
     }
 
+    public void onPanelExpandedChange(boolean expanded) {
+        updateSlippery();
+    }
+
+    private void updateSlippery() {
+        setSlippery(mOverviewProxyService.getProxy() != null && mPanelView.isFullyExpanded());
+    }
+
     private void setSlippery(boolean slippery) {
         boolean changed = false;
         final ViewGroup navbarView = ((ViewGroup) getParent());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index a62a424..2b7e474 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -950,7 +950,7 @@
     }
 
     public boolean isCollapsing() {
-        return mClosing;
+        return mClosing || mLaunchingNotification;
     }
 
     public boolean isTracking() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index b181212..cc5a93c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -250,6 +250,9 @@
         super.panelExpansionChanged(frac, expanded);
         mPanelFraction = frac;
         updateScrimFraction();
+        if ((frac == 0 || frac == 1) && mBar.getNavigationBarView() != null) {
+            mBar.getNavigationBarView().onPanelExpandedChange(expanded);
+        }
     }
 
     private void updateScrimFraction() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java
index ee1d088..001a1a2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java
@@ -19,6 +19,7 @@
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
+import android.animation.ArgbEvaluator;
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
 import android.animation.ValueAnimator.AnimatorUpdateListener;
@@ -82,7 +83,10 @@
     private boolean mDragPositive;
     private boolean mIsVertical;
     private boolean mIsRTL;
-    private float mMaxTrackPaintAlpha;
+    private float mTrackAlpha;
+    private int mLightTrackColor;
+    private int mDarkTrackColor;
+    private float mDarkIntensity;
 
     private final Handler mHandler = new Handler();
     private final Interpolator mQuickScrubEndInterpolator = new DecelerateInterpolator();
@@ -98,9 +102,10 @@
     private final ValueAnimator mButtonAnimator;
     private final AnimatorSet mQuickScrubEndAnimator;
     private final Context mContext;
+    private final ArgbEvaluator mTrackColorEvaluator = new ArgbEvaluator();
 
     private final AnimatorUpdateListener mTrackAnimatorListener = valueAnimator -> {
-        mTrackPaint.setAlpha(Math.round((float) valueAnimator.getAnimatedValue() * 255));
+        mTrackAlpha = (float) valueAnimator.getAnimatedValue();
         mNavigationBarView.invalidate();
     };
 
@@ -167,6 +172,7 @@
         mGestureDetector = new GestureDetector(mContext, mGestureListener);
         mTrackThickness = getDimensionPixelSize(mContext, R.dimen.nav_quick_scrub_track_thickness);
         mTrackPadding = getDimensionPixelSize(mContext, R.dimen.nav_quick_scrub_track_edge_padding);
+        mTrackPaint.setAlpha(0);
 
         mTrackAnimator = ObjectAnimator.ofFloat();
         mTrackAnimator.addUpdateListener(mTrackAnimatorListener);
@@ -291,6 +297,10 @@
 
     @Override
     public void onDraw(Canvas canvas) {
+        int color = (int) mTrackColorEvaluator.evaluate(mDarkIntensity, mLightTrackColor,
+                mDarkTrackColor);
+        mTrackPaint.setColor(color);
+        mTrackPaint.setAlpha((int) (mTrackPaint.getAlpha() * mTrackAlpha));
         canvas.drawRect(mTrackRect, mTrackPaint);
     }
 
@@ -326,13 +336,8 @@
 
     @Override
     public void onDarkIntensityChange(float intensity) {
-        if (intensity == 0) {
-            mTrackPaint.setColor(mContext.getColor(R.color.quick_step_track_background_light));
-        } else if (intensity == 1) {
-            mTrackPaint.setColor(mContext.getColor(R.color.quick_step_track_background_dark));
-        }
-        mMaxTrackPaintAlpha = mTrackPaint.getAlpha() * 1f / 255;
-        mTrackPaint.setAlpha(0);
+        mDarkIntensity = intensity;
+        mNavigationBarView.invalidate();
     }
 
     @Override
@@ -365,7 +370,9 @@
     private void startQuickScrub() {
         if (!mQuickScrubActive) {
             mQuickScrubActive = true;
-            mTrackAnimator.setFloatValues(0, mMaxTrackPaintAlpha);
+            mLightTrackColor = mContext.getColor(R.color.quick_step_track_background_light);
+            mDarkTrackColor = mContext.getColor(R.color.quick_step_track_background_dark);
+            mTrackAnimator.setFloatValues(0, 1);
             mTrackAnimator.start();
             try {
                 mOverviewEventSender.getProxy().onQuickScrubStart();
@@ -382,7 +389,7 @@
         mHandler.removeCallbacks(mLongPressRunnable);
         if (mDraggingActive || mQuickScrubActive) {
             mButtonAnimator.setIntValues((int) mTranslation, 0);
-            mTrackAnimator.setFloatValues(mTrackPaint.getAlpha() * 1f / 255, 0);
+            mTrackAnimator.setFloatValues(mTrackAlpha, 0);
             mQuickScrubEndAnimator.start();
             try {
                 mOverviewEventSender.getProxy().onQuickScrubEnd();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 7d84550..b519824 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -100,7 +100,6 @@
 import android.service.notification.StatusBarNotification;
 import android.service.vr.IVrManager;
 import android.service.vr.IVrStateCallbacks;
-import android.text.SpannedString;
 import android.text.TextUtils;
 import android.util.DisplayMetrics;
 import android.util.EventLog;
@@ -589,7 +588,7 @@
 
     private NavigationBarFragment mNavigationBar;
     private View mNavigationBarView;
-    private ActivityLaunchAnimator mActivityLaunchAnimator;
+    protected ActivityLaunchAnimator mActivityLaunchAnimator;
 
     @Override
     public void start() {
@@ -760,7 +759,7 @@
         mNotificationPanel = mStatusBarWindow.findViewById(R.id.notification_panel);
         mStackScroller = mStatusBarWindow.findViewById(R.id.notification_stack_scroller);
         mActivityLaunchAnimator = new ActivityLaunchAnimator(mStatusBarWindow,
-                this::collapsePanel,
+                this,
                 mNotificationPanel,
                 mStackScroller);
         mGutsManager.setUpWithPresenter(this, mEntryManager, mStackScroller, mCheckSaveListener,
@@ -2054,6 +2053,12 @@
         }
     }
 
+    public void onLaunchAnimationCancelled() {
+        if (!isCollapsing()) {
+            onClosingFinished();
+        }
+    }
+
     /**
      * All changes to the status bar and notifications funnel through here and are batched.
      */
@@ -3418,7 +3423,7 @@
     }
 
     public boolean isCollapsing() {
-        return mNotificationPanel.isCollapsing();
+        return mNotificationPanel.isCollapsing() || mActivityLaunchAnimator.isAnimationPending();
     }
 
     public void addPostCollapseAction(Runnable r) {
@@ -4959,6 +4964,7 @@
                     try {
                         launchResult = intent.sendAndReturnResult(mContext, 0, fillInIntent, null,
                                 null, null, getActivityOptions(row));
+                        mActivityLaunchAnimator.setLaunchResult(launchResult);
                     } catch (PendingIntent.CanceledException e) {
                         // the stack trace isn't very helpful here.
                         // Just log the exception message.
@@ -4970,7 +4976,7 @@
                         mAssistManager.hideAssist();
                     }
                 }
-                if (shouldCollapse(launchResult)) {
+                if (shouldCollapse()) {
                     if (Looper.getMainLooper().isCurrentThread()) {
                         collapsePanel();
                     } else {
@@ -5003,17 +5009,8 @@
         }, afterKeyguardGone);
     }
 
-    private boolean shouldCollapse(int launchResult) {
-        return mState != StatusBarState.SHADE
-                || (launchResult != ActivityManager.START_TASK_TO_FRONT
-                        && launchResult != ActivityManager.START_SUCCESS);
-    }
-
-    public void onExpandAnimationFinished() {
-        if (!isPresenterFullyCollapsed()) {
-            instantCollapseNotificationPanel();
-            visibilityChanged(false);
-        }
+    private boolean shouldCollapse() {
+        return mState != StatusBarState.SHADE || !mActivityLaunchAnimator.isAnimationPending();
     }
 
     public void collapsePanel(boolean animate) {
@@ -5128,7 +5125,8 @@
                         .addNextIntentWithParentStack(intent)
                         .startActivities(getActivityOptions(row),
                                 new UserHandle(UserHandle.getUserId(appUid)));
-                if (shouldCollapse(launchResult)) {
+                mActivityLaunchAnimator.setLaunchResult(launchResult);
+                if (shouldCollapse()) {
                     // Putting it back on the main thread, since we're touching views
                     mStatusBarWindow.post(() -> animateCollapsePanels(
                             CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index f7d0967..e32914f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -89,6 +89,7 @@
     private boolean mTouchCancelled;
     private boolean mTouchActive;
     private boolean mExpandAnimationRunning;
+    private boolean mExpandAnimationPending;
 
     public StatusBarWindowView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -268,7 +269,7 @@
                 || ev.getActionMasked() == MotionEvent.ACTION_CANCEL) {
             setTouchActive(false);
         }
-        if (mTouchCancelled || mExpandAnimationRunning) {
+        if (mTouchCancelled || mExpandAnimationRunning || mExpandAnimationPending) {
             return false;
         }
         mFalsingManager.onTouchEvent(ev, getWidth(), getHeight());
@@ -393,6 +394,10 @@
         mExpandAnimationRunning = expandAnimationRunning;
     }
 
+    public void setExpandAnimationPending(boolean pending) {
+        mExpandAnimationPending = pending;
+    }
+
     public class LayoutParams extends FrameLayout.LayoutParams {
 
         public boolean ignoreRightInset;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
index 1e894ff..3febdfd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
@@ -119,7 +119,8 @@
         // for the current foreground user.
         LocationManager locationManager =
                 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
-        return locationManager.isLocationEnabledForUser(Process.myUserHandle());
+        return locationManager.isLocationEnabledForUser(
+                UserHandle.of(ActivityManager.getCurrentUser()));
     }
 
     @Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 99202f4..bdf9b1f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -84,6 +84,7 @@
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.NotificationViewHierarchyManager;
 import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -188,7 +189,8 @@
                 mKeyguardIndicationController, mStackScroller, mHeadsUpManager,
                 mPowerManager, mNotificationPanelView, mBarService, mNotificationListener,
                 mNotificationLogger, mVisualStabilityManager, mViewHierarchyManager,
-                mEntryManager, mScrimController, mFingerprintUnlockController);
+                mEntryManager, mScrimController, mFingerprintUnlockController,
+                mock(ActivityLaunchAnimator.class));
         mStatusBar.mContext = mContext;
         mStatusBar.mComponents = mContext.getComponents();
         mEntryManager.setUpForTest(mStatusBar, mStackScroller, mStatusBar, mHeadsUpManager,
@@ -593,7 +595,8 @@
                 VisualStabilityManager visualStabilityManager,
                 NotificationViewHierarchyManager viewHierarchyManager,
                 TestableNotificationEntryManager entryManager, ScrimController scrimController,
-                FingerprintUnlockController fingerprintUnlockController) {
+                FingerprintUnlockController fingerprintUnlockController,
+                ActivityLaunchAnimator launchAnimator) {
             mStatusBarKeyguardViewManager = man;
             mUnlockMethodCache = unlock;
             mKeyguardIndicationController = key;
@@ -610,6 +613,7 @@
             mEntryManager = entryManager;
             mScrimController = scrimController;
             mFingerprintUnlockController = fingerprintUnlockController;
+            mActivityLaunchAnimator = launchAnimator;
         }
 
         private WakefulnessLifecycle createAwakeWakefulnessLifecycle() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/OutputChooserDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/OutputChooserDialogTest.java
index de99d71..c18ed73 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/OutputChooserDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/OutputChooserDialogTest.java
@@ -28,11 +28,12 @@
 
 import android.bluetooth.BluetoothProfile;
 import android.net.wifi.WifiManager;
-import android.support.test.annotation.UiThreadTest;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.support.v7.media.MediaRouter;
 import android.telecom.TelecomManager;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
 import android.widget.TextView;
 
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
@@ -49,7 +50,8 @@
 import org.mockito.MockitoAnnotations;
 
 @SmallTest
-@RunWith(AndroidJUnit4.class)
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
 public class OutputChooserDialogTest extends SysuiTestCase {
 
     OutputChooserDialog mDialog;
@@ -68,7 +70,6 @@
 
 
     @Before
-    @UiThreadTest
     public void setup() throws Exception {
         MockitoAnnotations.initMocks(this);
 
@@ -82,8 +83,12 @@
         mDialog = new OutputChooserDialog(getContext(), mRouter);
     }
 
+    @After
+    public void tearDown() throws Exception {
+        TestableLooper.get(this).processAllMessages();
+    }
+
     @Test
-    @UiThreadTest
     public void testClickMediaRouterItemConnectsMedia() {
         mDialog.show();
 
@@ -100,7 +105,6 @@
     }
 
     @Test
-    @UiThreadTest
     public void testClickBtItemConnectsBt() {
         mDialog.show();
 
@@ -116,7 +120,6 @@
     }
 
     @Test
-    @UiThreadTest
     public void testTitleNotInCall() {
         mDialog.show();
 
@@ -126,7 +129,6 @@
     }
 
     @Test
-    @UiThreadTest
     public void testTitleInCall() {
         mDialog.setIsInCall(true);
         mDialog.show();
@@ -137,7 +139,6 @@
     }
 
     @Test
-    @UiThreadTest
     public void testNoMediaScanIfInCall() {
         mDialog.setIsInCall(true);
         mDialog.onAttachedToWindow();
@@ -146,7 +147,6 @@
     }
 
     @Test
-    @UiThreadTest
     public void testMediaScanIfNotInCall() {
         mDialog.setIsInCall(false);
         mDialog.onAttachedToWindow();
@@ -155,7 +155,6 @@
     }
 
     @Test
-    @UiThreadTest
     public void testRegisterCallbacks() {
         mDialog.setIsInCall(false);
         mDialog.onAttachedToWindow();
@@ -166,7 +165,6 @@
     }
 
     @Test
-    @UiThreadTest
     public void testUnregisterCallbacks() {
         mDialog.setIsInCall(false);
         mDialog.onDetachedFromWindow();
diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp
index 52d0e08e..b32be73 100644
--- a/rs/jni/android_renderscript_RenderScript.cpp
+++ b/rs/jni/android_renderscript_RenderScript.cpp
@@ -24,9 +24,8 @@
 #include <utils/misc.h>
 #include <inttypes.h>
 
-#include <android-base/macros.h>
 #include <androidfw/Asset.h>
-#include <androidfw/AssetManager2.h>
+#include <androidfw/AssetManager.h>
 #include <androidfw/ResourceTypes.h>
 #include <android-base/macros.h>
 
@@ -1665,22 +1664,18 @@
 static jlong
 nFileA3DCreateFromAsset(JNIEnv *_env, jobject _this, jlong con, jobject _assetMgr, jstring _path)
 {
-    Guarded<AssetManager2>* mgr = AssetManagerForJavaObject(_env, _assetMgr);
+    AssetManager* mgr = assetManagerForJavaObject(_env, _assetMgr);
     if (mgr == nullptr) {
         return 0;
     }
 
     AutoJavaStringToUTF8 str(_env, _path);
-    std::unique_ptr<Asset> asset;
-    {
-        ScopedLock<AssetManager2> locked_mgr(*mgr);
-        asset = locked_mgr->Open(str.c_str(), Asset::ACCESS_BUFFER);
-        if (asset == nullptr) {
-            return 0;
-        }
+    Asset* asset = mgr->open(str.c_str(), Asset::ACCESS_BUFFER);
+    if (asset == nullptr) {
+        return 0;
     }
 
-    jlong id = (jlong)(uintptr_t)rsaFileA3DCreateFromAsset((RsContext)con, asset.release());
+    jlong id = (jlong)(uintptr_t)rsaFileA3DCreateFromAsset((RsContext)con, asset);
     return id;
 }
 
@@ -1757,25 +1752,22 @@
 nFontCreateFromAsset(JNIEnv *_env, jobject _this, jlong con, jobject _assetMgr, jstring _path,
                      jfloat fontSize, jint dpi)
 {
-    Guarded<AssetManager2>* mgr = AssetManagerForJavaObject(_env, _assetMgr);
+    AssetManager* mgr = assetManagerForJavaObject(_env, _assetMgr);
     if (mgr == nullptr) {
         return 0;
     }
 
     AutoJavaStringToUTF8 str(_env, _path);
-    std::unique_ptr<Asset> asset;
-    {
-        ScopedLock<AssetManager2> locked_mgr(*mgr);
-        asset = locked_mgr->Open(str.c_str(), Asset::ACCESS_BUFFER);
-        if (asset == nullptr) {
-            return 0;
-        }
+    Asset* asset = mgr->open(str.c_str(), Asset::ACCESS_BUFFER);
+    if (asset == nullptr) {
+        return 0;
     }
 
     jlong id = (jlong)(uintptr_t)rsFontCreateFromMemory((RsContext)con,
                                            str.c_str(), str.length(),
                                            fontSize, dpi,
                                            asset->getBuffer(false), asset->getLength());
+    delete asset;
     return id;
 }
 
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index dc5f5a2..ba9883b 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -43,17 +43,17 @@
 import android.hardware.health.V2_0.IHealth;
 import android.hardware.health.V2_0.Result;
 import android.os.BatteryManager;
-import android.os.BatteryManagerProto;
 import android.os.BatteryManagerInternal;
 import android.os.BatteryProperty;
 import android.os.Binder;
+import android.os.DropBoxManager;
 import android.os.FileUtils;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBatteryPropertiesListener;
 import android.os.IBatteryPropertiesRegistrar;
 import android.os.IBinder;
-import android.os.DropBoxManager;
+import android.os.OsProtoEnums;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
@@ -127,7 +127,7 @@
     private static final String DUMPSYS_DATA_PATH = "/data/system/";
 
     // This should probably be exposed in the API, though it's not critical
-    private static final int BATTERY_PLUGGED_NONE = 0;
+    private static final int BATTERY_PLUGGED_NONE = OsProtoEnums.BATTERY_PLUGGED_NONE; // = 0
 
     private final Context mContext;
     private final IBatteryStats mBatteryStats;
@@ -921,13 +921,13 @@
 
         synchronized (mLock) {
             proto.write(BatteryServiceDumpProto.ARE_UPDATES_STOPPED, mUpdatesStopped);
-            int batteryPluggedValue = BatteryManagerProto.PLUG_TYPE_NONE;
+            int batteryPluggedValue = OsProtoEnums.BATTERY_PLUGGED_NONE;
             if (mHealthInfo.chargerAcOnline) {
-                batteryPluggedValue = BatteryManagerProto.PLUG_TYPE_AC;
+                batteryPluggedValue = OsProtoEnums.BATTERY_PLUGGED_AC;
             } else if (mHealthInfo.chargerUsbOnline) {
-                batteryPluggedValue = BatteryManagerProto.PLUG_TYPE_USB;
+                batteryPluggedValue = OsProtoEnums.BATTERY_PLUGGED_USB;
             } else if (mHealthInfo.chargerWirelessOnline) {
-                batteryPluggedValue = BatteryManagerProto.PLUG_TYPE_WIRELESS;
+                batteryPluggedValue = OsProtoEnums.BATTERY_PLUGGED_WIRELESS;
             }
             proto.write(BatteryServiceDumpProto.PLUGGED, batteryPluggedValue);
             proto.write(BatteryServiceDumpProto.MAX_CHARGING_CURRENT, mHealthInfo.maxChargingCurrent);
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index bd93b179..1dd92f3 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -1577,13 +1577,22 @@
     }
 
     /**
-     * Returns all providers by name, including passive, but excluding
-     * fused, also including ones that are not permitted to
-     * be accessed by the calling activity or are currently disabled.
+     * Returns all providers by name, including passive and the ones that are not permitted to
+     * be accessed by the calling activity or are currently disabled, but excluding fused.
      */
     @Override
     public List<String> getAllProviders() {
-        List<String> out = getProviders(null /*criteria*/, false /*enabledOnly*/);
+        ArrayList<String> out;
+        synchronized (mLock) {
+            out = new ArrayList<>(mProviders.size());
+            for (LocationProviderInterface provider : mProviders) {
+                String name = provider.getName();
+                if (LocationManager.FUSED_PROVIDER.equals(name)) {
+                    continue;
+                }
+                out.add(name);
+            }
+        }
         if (D) Log.d(TAG, "getAllProviders()=" + out);
         return out;
     }
@@ -2586,9 +2595,10 @@
         // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
         checkInteractAcrossUsersPermission(userId);
 
-        // Enable or disable all location providers
+        // Enable or disable all location providers. Fused provider and passive provider are
+        // excluded.
         synchronized (mLock) {
-            for(String provider : getAllProviders()) {
+            for(String provider : getAllProvidersForLocationSettings()) {
                 setProviderEnabledForUser(provider, enabled, userId);
             }
         }
@@ -2605,9 +2615,10 @@
         // Check INTERACT_ACROSS_USERS permission if userId is not current user id.
         checkInteractAcrossUsersPermission(userId);
 
-        // If at least one location provider is enabled, return true
+        // If at least one location provider is enabled, return true. Fused provider and passive
+        // provider are excluded.
         synchronized (mLock) {
-            for (String provider : getAllProviders()) {
+            for (String provider : getAllProvidersForLocationSettings()) {
                 if (isProviderEnabledForUser(provider, userId)) {
                     return true;
                 }
@@ -2691,6 +2702,26 @@
     }
 
     /**
+     * Return all location providers except fused provider and passive provider. These two
+     * providers are not generating location by themselves, but only echo locations from other
+     * providers.
+     *
+     * @return All location providers except fused provider and passive provider, including
+     *          providers that are not permitted to be accessed by the calling activity or are
+     *          currently disabled.
+     */
+    private List<String> getAllProvidersForLocationSettings() {
+        List<String> providersForSettings = new ArrayList<>(mProviders.size());
+        for (String provider : getAllProviders()) {
+            if (provider.equals(LocationManager.PASSIVE_PROVIDER)) {
+                continue;
+            }
+            providersForSettings.add(provider);
+        }
+        return providersForSettings;
+    }
+
+    /**
      * Read location provider status from Settings.Secure
      *
      * @param provider the location provider to query
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index c1cda98..48b5a58 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -73,6 +73,17 @@
 
     private static final long[] DOUBLE_CLICK_EFFECT_FALLBACK_TIMINGS = { 0, 30, 100, 30 };
 
+    private static final float GAMMA_SCALE_FACTOR_MINIMUM = 2.0f;
+    private static final float GAMMA_SCALE_FACTOR_LOW = 1.5f;
+    private static final float GAMMA_SCALE_FACTOR_HIGH = 0.5f;
+    private static final float GAMMA_SCALE_FACTOR_NONE = 1.0f;
+
+    private static final int MAX_AMPLITUDE_MINIMUM_INTENSITY = 168; // 2/3 * 255
+    private static final int MAX_AMPLITUDE_LOW_INTENSITY = 192; // 3/4 * 255
+
+    // If a vibration is playing for longer than 5s, it's probably not haptic feedback.
+    private static final long MAX_HAPTIC_FEEDBACK_DURATION = 5000;
+
     private final LinkedList<VibrationInfo> mPreviousVibrations;
     private final int mPreviousVibrationsLimit;
     private final boolean mAllowPriorityVibrationsInLowPowerMode;
@@ -89,6 +100,8 @@
     private final IBatteryStats mBatteryStatsService;
     private PowerManagerInternal mPowerManagerInternal;
     private InputManager mIm;
+    private Vibrator mVibrator;
+    private SettingsObserver mSettingObserver;
 
     private volatile VibrateThread mThread;
 
@@ -101,7 +114,8 @@
     private Vibration mCurrentVibration;
     private int mCurVibUid = -1;
     private boolean mLowPowerMode;
-    private SettingsObserver mSettingObserver;
+    private int mHapticFeedbackIntensity;
+    private int mNotificationIntensity;
 
     native static boolean vibratorExists();
     native static void vibratorInit();
@@ -112,27 +126,33 @@
     native static long vibratorPerformEffect(long effect, long strength);
 
     private class Vibration implements IBinder.DeathRecipient {
-        private final IBinder mToken;
-        private final VibrationEffect mEffect;
+        public final IBinder token;
         // Start time in CLOCK_BOOTTIME base.
-        private final long mStartTime;
+        public final long startTime;
         // Start time in unix epoch time. Only to be used for debugging purposes and to correlate
-        // with other system events, any duration calculations should be done use mStartTime so as
+        // with other system events, any duration calculations should be done use startTime so as
         // not to be affected by discontinuities created by RTC adjustments.
-        private final long mStartTimeDebug;
-        private final int mUsageHint;
-        private final int mUid;
-        private final String mOpPkg;
+        public final long startTimeDebug;
+        public final int usageHint;
+        public final int uid;
+        public final String opPkg;
+
+        // The actual effect to be played.
+        public VibrationEffect effect;
+        // The original effect that was requested. This is non-null only when the original effect
+        // differs from the effect that's being played. Typically these two things differ because
+        // the effect was scaled based on the users vibration intensity settings.
+        public VibrationEffect originalEffect;
 
         private Vibration(IBinder token, VibrationEffect effect,
                 int usageHint, int uid, String opPkg) {
-            mToken = token;
-            mEffect = effect;
-            mStartTime = SystemClock.elapsedRealtime();
-            mStartTimeDebug = System.currentTimeMillis();
-            mUsageHint = usageHint;
-            mUid = uid;
-            mOpPkg = opPkg;
+            this.token = token;
+            this.effect = effect;
+            this.startTime = SystemClock.elapsedRealtime();
+            this.startTimeDebug = System.currentTimeMillis();
+            this.usageHint = usageHint;
+            this.uid = uid;
+            this.opPkg = opPkg;
         }
 
         public void binderDied() {
@@ -143,43 +163,68 @@
             }
         }
 
-        public boolean hasLongerTimeout(long millis) {
-            // If the current effect is a one shot vibration that will end after the given timeout
-            // for the new one shot vibration, then just let the current vibration finish. All
-            // other effect types will get pre-empted.
-            if (mEffect instanceof VibrationEffect.OneShot) {
-                VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) mEffect;
-                return mStartTime + oneShot.getTiming() > SystemClock.uptimeMillis() + millis;
-            }
-            return false;
+        public boolean hasTimeoutLongerThan(long millis) {
+            final long duration = effect.getDuration();
+            return duration >= 0 && duration > millis;
         }
 
-        public boolean isSystemHapticFeedback() {
-            boolean repeating = false;
-            if (mEffect instanceof VibrationEffect.Waveform) {
-                VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) mEffect;
-                repeating = (waveform.getRepeatIndex() < 0);
+        public boolean isHapticFeedback() {
+            if (effect instanceof VibrationEffect.Prebaked) {
+                VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) effect;
+                switch (prebaked.getId()) {
+                    case VibrationEffect.EFFECT_CLICK:
+                    case VibrationEffect.EFFECT_DOUBLE_CLICK:
+                    case VibrationEffect.EFFECT_TICK:
+                        return true;
+                    default:
+                        Slog.w(TAG, "Unknown prebaked vibration effect, "
+                                + "assuming it isn't haptic feedback.");
+                        return false;
+                }
             }
-            return (mUid == Process.SYSTEM_UID || mUid == 0 || SYSTEM_UI_PACKAGE.equals(mOpPkg))
-                    && !repeating;
+            final long duration = effect.getDuration();
+            return duration >= 0 && duration < MAX_HAPTIC_FEEDBACK_DURATION;
+        }
+
+        public boolean isNotification() {
+            switch (usageHint) {
+                case AudioAttributes.USAGE_NOTIFICATION:
+                case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST:
+                case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_INSTANT:
+                case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_DELAYED:
+                    return true;
+                default:
+                    return false;
+            }
+        }
+
+        public boolean isRingtone() {
+            return usageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE;
+        }
+
+        public boolean isFromSystem() {
+            return uid == Process.SYSTEM_UID || uid == 0 || SYSTEM_UI_PACKAGE.equals(opPkg);
         }
 
         public VibrationInfo toInfo() {
-            return new VibrationInfo(mStartTimeDebug, mEffect, mUsageHint, mUid, mOpPkg);
+            return new VibrationInfo(
+                    startTimeDebug, effect, originalEffect, usageHint, uid, opPkg);
         }
     }
 
     private static class VibrationInfo {
         private final long mStartTimeDebug;
         private final VibrationEffect mEffect;
+        private final VibrationEffect mOriginalEffect;
         private final int mUsageHint;
         private final int mUid;
         private final String mOpPkg;
 
         public VibrationInfo(long startTimeDebug, VibrationEffect effect,
-                int usageHint, int uid, String opPkg) {
+                VibrationEffect originalEffect, int usageHint, int uid, String opPkg) {
             mStartTimeDebug = startTimeDebug;
             mEffect = effect;
+            mOriginalEffect = originalEffect;
             mUsageHint = usageHint;
             mUid = uid;
             mOpPkg = opPkg;
@@ -192,6 +237,8 @@
                     .append(DateFormat.getDateTimeInstance().format(new Date(mStartTimeDebug)))
                     .append(", effect: ")
                     .append(mEffect)
+                    .append(", originalEffect: ")
+                    .append(mOriginalEffect)
                     .append(", usageHint: ")
                     .append(mUsageHint)
                     .append(", uid: ")
@@ -245,6 +292,7 @@
         VibrationEffect tickEffect = createEffect(tickEffectTimings);
 
         mFallbackEffects = new VibrationEffect[] { clickEffect, doubleClickEffect, tickEffect };
+
     }
 
     private static VibrationEffect createEffect(long[] timings) {
@@ -259,6 +307,7 @@
 
     public void systemReady() {
         mIm = mContext.getSystemService(InputManager.class);
+        mVibrator = mContext.getSystemService(Vibrator.class);
         mSettingObserver = new SettingsObserver(mH);
 
         mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
@@ -279,6 +328,14 @@
                 Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES),
                 true, mSettingObserver, UserHandle.USER_ALL);
 
+        mContext.getContentResolver().registerContentObserver(
+                Settings.System.getUriFor(Settings.System.HAPTIC_FEEDBACK_INTENSITY),
+                true, mSettingObserver, UserHandle.USER_ALL);
+
+        mContext.getContentResolver().registerContentObserver(
+                Settings.System.getUriFor(Settings.System.NOTIFICATION_VIBRATION_INTENSITY),
+                true, mSettingObserver, UserHandle.USER_ALL);
+
         mContext.registerReceiver(new BroadcastReceiver() {
             @Override
             public void onReceive(Context context, Intent intent) {
@@ -380,11 +437,11 @@
         // then just let the current one finish.
         if (effect instanceof VibrationEffect.OneShot
                 && mCurrentVibration != null
-                && mCurrentVibration.mEffect instanceof VibrationEffect.OneShot) {
+                && mCurrentVibration.effect instanceof VibrationEffect.OneShot) {
             VibrationEffect.OneShot newOneShot = (VibrationEffect.OneShot) effect;
             VibrationEffect.OneShot currentOneShot =
-                    (VibrationEffect.OneShot) mCurrentVibration.mEffect;
-            if (mCurrentVibration.hasLongerTimeout(newOneShot.getTiming())
+                    (VibrationEffect.OneShot) mCurrentVibration.effect;
+            if (mCurrentVibration.hasTimeoutLongerThan(newOneShot.getDuration())
                     && newOneShot.getAmplitude() == currentOneShot.getAmplitude()) {
                 if (DEBUG) {
                     Slog.d(TAG, "Ignoring incoming vibration in favor of current vibration");
@@ -398,7 +455,7 @@
         // to grab the attention of the user, like ringtones and alarms, in favor of one-shot
         // vibrations that are likely quite short.
         if (!isRepeatingVibration(effect)
-                && mCurrentVibration != null && isRepeatingVibration(mCurrentVibration.mEffect)) {
+                && mCurrentVibration != null && isRepeatingVibration(mCurrentVibration.effect)) {
             if (DEBUG) {
                 Slog.d(TAG, "Ignoring incoming vibration in favor of alarm vibration");
             }
@@ -421,13 +478,7 @@
     }
 
     private static boolean isRepeatingVibration(VibrationEffect effect) {
-        if (effect instanceof VibrationEffect.Waveform) {
-            final VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) effect;
-            if (waveform.getRepeatIndex() >= 0) {
-                return true;
-            }
-        }
-        return false;
+        return effect.getDuration() == Long.MAX_VALUE;
     }
 
     private void addToPreviousVibrationsLocked(Vibration vib) {
@@ -444,7 +495,7 @@
                 "cancelVibrate");
 
         synchronized (mLock) {
-            if (mCurrentVibration != null && mCurrentVibration.mToken == token) {
+            if (mCurrentVibration != null && mCurrentVibration.token == token) {
                 if (DEBUG) {
                     Slog.d(TAG, "Canceling vibration.");
                 }
@@ -488,15 +539,16 @@
     }
 
     private void startVibrationLocked(final Vibration vib) {
-        if (!isAllowedToVibrate(vib)) {
-            if (DEBUG) {
-                Slog.e(TAG, "Vibrate ignored, low power mode");
-            }
+        if (!isAllowedToVibrateLocked(vib)) {
             return;
         }
 
-        if (vib.mUsageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE &&
-                !shouldVibrateForRingtone()) {
+        final int intensity = getCurrentIntensityLocked(vib);
+        if (intensity == Vibrator.VIBRATION_INTENSITY_OFF) {
+            return;
+        }
+
+        if (vib.isRingtone() && !shouldVibrateForRingtone()) {
             if (DEBUG) {
                 Slog.e(TAG, "Vibrate ignored, not vibrating for ringtones");
             }
@@ -508,26 +560,27 @@
             if (mode == AppOpsManager.MODE_ERRORED) {
                 // We might be getting calls from within system_server, so we don't actually want
                 // to throw a SecurityException here.
-                Slog.w(TAG, "Would be an error: vibrate from uid " + vib.mUid);
+                Slog.w(TAG, "Would be an error: vibrate from uid " + vib.uid);
             }
             return;
         }
+        applyVibrationIntensityScalingLocked(vib, intensity);
         startVibrationInnerLocked(vib);
     }
 
     private void startVibrationInnerLocked(Vibration vib) {
         mCurrentVibration = vib;
-        if (vib.mEffect instanceof VibrationEffect.OneShot) {
-            VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) vib.mEffect;
-            doVibratorOn(oneShot.getTiming(), oneShot.getAmplitude(), vib.mUid, vib.mUsageHint);
-            mH.postDelayed(mVibrationEndRunnable, oneShot.getTiming());
-        } else if (vib.mEffect instanceof VibrationEffect.Waveform) {
+        if (vib.effect instanceof VibrationEffect.OneShot) {
+            VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) vib.effect;
+            doVibratorOn(oneShot.getDuration(), oneShot.getAmplitude(), vib.uid, vib.usageHint);
+            mH.postDelayed(mVibrationEndRunnable, oneShot.getDuration());
+        } else if (vib.effect instanceof VibrationEffect.Waveform) {
             // mThread better be null here. doCancelVibrate should always be
             // called before startNextVibrationLocked or startVibrationLocked.
-            VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) vib.mEffect;
-            mThread = new VibrateThread(waveform, vib.mUid, vib.mUsageHint);
+            VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) vib.effect;
+            mThread = new VibrateThread(waveform, vib.uid, vib.usageHint);
             mThread.start();
-        } else if (vib.mEffect instanceof VibrationEffect.Prebaked) {
+        } else if (vib.effect instanceof VibrationEffect.Prebaked) {
             long timeout = doVibratorPrebakedEffectLocked(vib);
             if (timeout > 0) {
                 mH.postDelayed(mVibrationEndRunnable, timeout);
@@ -537,28 +590,91 @@
         }
     }
 
-    private boolean isAllowedToVibrate(Vibration vib) {
+    private boolean isAllowedToVibrateLocked(Vibration vib) {
         if (!mLowPowerMode) {
             return true;
         }
-        if (vib.mUsageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE) {
+
+        if (vib.usageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE) {
             return true;
         }
-        if (!mAllowPriorityVibrationsInLowPowerMode) {
-            return false;
-        }
-        if (vib.mUsageHint == AudioAttributes.USAGE_ALARM ||
-            vib.mUsageHint == AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY ||
-            vib.mUsageHint == AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST) {
 
+        if (vib.usageHint == AudioAttributes.USAGE_ALARM ||
+                vib.usageHint == AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY ||
+                vib.usageHint == AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST) {
             return true;
         }
 
         return false;
     }
 
+    private int getCurrentIntensityLocked(Vibration vib) {
+        if (vib.isNotification() || vib.isRingtone()){
+            return mNotificationIntensity;
+        } else if (vib.isHapticFeedback()) {
+            return mHapticFeedbackIntensity;
+        } else {
+            return Vibrator.VIBRATION_INTENSITY_MEDIUM;
+        }
+    }
+
+    /**
+     * Scale the vibration effect by the intensity as appropriate based its intent.
+     */
+    private void applyVibrationIntensityScalingLocked(Vibration vib, int intensity) {
+        if (vib.effect instanceof VibrationEffect.Prebaked) {
+            // Prebaked effects are always just a direct translation from intensity to
+            // EffectStrength.
+            VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked)vib.effect;
+            prebaked.setEffectStrength(intensityToEffectStrength(intensity));
+            return;
+        }
+
+        final float gamma;
+        final int maxAmplitude;
+        if (vib.isNotification() || vib.isRingtone()) {
+            if (intensity == Vibrator.VIBRATION_INTENSITY_LOW) {
+                gamma = GAMMA_SCALE_FACTOR_MINIMUM;
+                maxAmplitude = MAX_AMPLITUDE_MINIMUM_INTENSITY;
+            } else if (intensity == Vibrator.VIBRATION_INTENSITY_MEDIUM) {
+                gamma = GAMMA_SCALE_FACTOR_LOW;
+                maxAmplitude = MAX_AMPLITUDE_LOW_INTENSITY;
+            } else {
+                gamma = GAMMA_SCALE_FACTOR_NONE;
+                maxAmplitude = VibrationEffect.MAX_AMPLITUDE;
+            }
+        } else {
+            if (intensity == Vibrator.VIBRATION_INTENSITY_LOW) {
+                gamma = GAMMA_SCALE_FACTOR_LOW;
+                maxAmplitude = MAX_AMPLITUDE_LOW_INTENSITY;
+            } else if (intensity == Vibrator.VIBRATION_INTENSITY_HIGH) {
+                gamma = GAMMA_SCALE_FACTOR_HIGH;
+                maxAmplitude = VibrationEffect.MAX_AMPLITUDE;
+            } else {
+                gamma = GAMMA_SCALE_FACTOR_NONE;
+                maxAmplitude = VibrationEffect.MAX_AMPLITUDE;
+            }
+        }
+
+        VibrationEffect scaledEffect = null;
+        if (vib.effect instanceof VibrationEffect.OneShot) {
+            VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) vib.effect;
+            scaledEffect = oneShot.scale(gamma, maxAmplitude);
+        } else if (vib.effect instanceof VibrationEffect.Waveform) {
+            VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) vib.effect;
+            scaledEffect = waveform.scale(gamma, maxAmplitude);
+        } else {
+            Slog.w(TAG, "Unable to apply intensity scaling, unknown VibrationEffect type");
+        }
+
+        if (scaledEffect != null) {
+            vib.originalEffect = vib.effect;
+            vib.effect = scaledEffect;
+        }
+    }
+
     private boolean shouldVibrateForRingtone() {
-        AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+        AudioManager audioManager = mContext.getSystemService(AudioManager.class);
         int ringerMode = audioManager.getRingerModeInternal();
         // "Also vibrate for calls" Setting in Sound
         if (Settings.System.getInt(
@@ -573,10 +689,10 @@
         int mode;
         try {
             mode = mAppOpsService.checkAudioOperation(AppOpsManager.OP_VIBRATE,
-                    vib.mUsageHint, vib.mUid, vib.mOpPkg);
+                    vib.usageHint, vib.uid, vib.opPkg);
             if (mode == AppOpsManager.MODE_ALLOWED) {
                 mode = mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService),
-                    AppOpsManager.OP_VIBRATE, vib.mUid, vib.mOpPkg);
+                    AppOpsManager.OP_VIBRATE, vib.uid, vib.opPkg);
             }
         } catch (RemoteException e) {
             Slog.e(TAG, "Failed to get appop mode for vibration!", e);
@@ -589,8 +705,8 @@
         if (mCurrentVibration != null) {
             try {
                 mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService),
-                        AppOpsManager.OP_VIBRATE, mCurrentVibration.mUid,
-                        mCurrentVibration.mOpPkg);
+                        AppOpsManager.OP_VIBRATE, mCurrentVibration.uid,
+                        mCurrentVibration.opPkg);
             } catch (RemoteException e) { }
             unlinkVibration(mCurrentVibration);
             mCurrentVibration = null;
@@ -600,9 +716,9 @@
     private void linkVibration(Vibration vib) {
         // Only link against waveforms since they potentially don't have a finish if
         // they're repeating. Let other effects just play out until they're done.
-        if (vib.mEffect instanceof VibrationEffect.Waveform) {
+        if (vib.effect instanceof VibrationEffect.Waveform) {
             try {
-                vib.mToken.linkToDeath(vib, 0);
+                vib.token.linkToDeath(vib, 0);
             } catch (RemoteException e) {
                 return;
             }
@@ -610,8 +726,8 @@
     }
 
     private void unlinkVibration(Vibration vib) {
-        if (vib.mEffect instanceof VibrationEffect.Waveform) {
-            vib.mToken.unlinkToDeath(vib, 0);
+        if (vib.effect instanceof VibrationEffect.Waveform) {
+            vib.token.unlinkToDeath(vib, 0);
         }
     }
 
@@ -619,6 +735,7 @@
         synchronized (mLock) {
             boolean devicesUpdated = updateInputDeviceVibratorsLocked();
             boolean lowPowerModeUpdated = updateLowPowerModeLocked();
+            updateVibrationIntensityLocked();
 
             if (devicesUpdated || lowPowerModeUpdated) {
                 // If the state changes out from under us then just reset.
@@ -678,6 +795,15 @@
         return false;
     }
 
+    private void updateVibrationIntensityLocked() {
+        mHapticFeedbackIntensity = Settings.System.getIntForUser(mContext.getContentResolver(),
+                Settings.System.HAPTIC_FEEDBACK_INTENSITY,
+                mVibrator.getDefaultHapticFeedbackIntensity(), UserHandle.USER_CURRENT);
+        mNotificationIntensity = Settings.System.getIntForUser(mContext.getContentResolver(),
+                Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
+                mVibrator.getDefaultNotificationVibrationIntensity(), UserHandle.USER_CURRENT);
+    }
+
     @Override
     public void onInputDeviceAdded(int deviceId) {
         updateVibrators();
@@ -755,28 +881,32 @@
     }
 
     private long doVibratorPrebakedEffectLocked(Vibration vib) {
+        final VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) vib.effect;
+        final boolean usingInputDeviceVibrators;
         synchronized (mInputDeviceVibrators) {
-            VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) vib.mEffect;
-            // Input devices don't support prebaked effect, so skip trying it with them.
-            if (mInputDeviceVibrators.isEmpty()) {
-                long timeout = vibratorPerformEffect(prebaked.getId(), EffectStrength.MEDIUM);
-                if (timeout > 0) {
-                    noteVibratorOnLocked(vib.mUid, timeout);
-                    return timeout;
-                }
-            }
-            if (!prebaked.shouldFallback()) {
-                return 0;
-            }
-            VibrationEffect effect = getFallbackEffect(prebaked.getId());
-            if (effect == null) {
-                Slog.w(TAG, "Failed to play prebaked effect, no fallback");
-                return 0;
-            }
-            Vibration fallbackVib =
-                    new Vibration(vib.mToken, effect, vib.mUsageHint, vib.mUid, vib.mOpPkg);
-            startVibrationInnerLocked(fallbackVib);
+            usingInputDeviceVibrators = !mInputDeviceVibrators.isEmpty();
         }
+        // Input devices don't support prebaked effect, so skip trying it with them.
+        if (!usingInputDeviceVibrators) {
+            long timeout = vibratorPerformEffect(prebaked.getId(), prebaked.getEffectStrength());
+            if (timeout > 0) {
+                noteVibratorOnLocked(vib.uid, timeout);
+                return timeout;
+            }
+        }
+        if (!prebaked.shouldFallback()) {
+            return 0;
+        }
+        VibrationEffect effect = getFallbackEffect(prebaked.getId());
+        if (effect == null) {
+            Slog.w(TAG, "Failed to play prebaked effect, no fallback");
+            return 0;
+        }
+        Vibration fallbackVib =
+                new Vibration(vib.token, effect, vib.usageHint, vib.uid, vib.opPkg);
+        final int intensity = getCurrentIntensityLocked(fallbackVib);
+        applyVibrationIntensityScalingLocked(fallbackVib, intensity);
+        startVibrationInnerLocked(fallbackVib);
         return 0;
     }
 
@@ -787,6 +917,25 @@
         return mFallbackEffects[effectId];
     }
 
+    /**
+     * Return the current desired effect strength.
+     *
+     * If the returned value is &lt; 0 then the vibration shouldn't be played at all.
+     */
+    private static int intensityToEffectStrength(int intensity) {
+        switch (intensity) {
+            case Vibrator.VIBRATION_INTENSITY_LOW:
+                return EffectStrength.LIGHT;
+            case Vibrator.VIBRATION_INTENSITY_MEDIUM:
+                return EffectStrength.MEDIUM;
+            case Vibrator.VIBRATION_INTENSITY_HIGH:
+                return EffectStrength.STRONG;
+            default:
+                Slog.w(TAG, "Got unexpected vibration intensity: " + intensity);
+                return EffectStrength.STRONG;
+        }
+    }
+
     private void noteVibratorOnLocked(int uid, long millis) {
         try {
             mBatteryStatsService.noteVibratorOn(uid, millis);
@@ -945,7 +1094,8 @@
                     // haptic feedback as part of the transition.  So we don't cancel
                     // system vibrations.
                     if (mCurrentVibration != null
-                            && !mCurrentVibration.isSystemHapticFeedback()) {
+                            && !(mCurrentVibration.isHapticFeedback()
+                                && mCurrentVibration.isFromSystem())) {
                         doCancelVibrateLocked();
                     }
                 }
@@ -957,10 +1107,21 @@
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
 
-        pw.println("Previous vibrations:");
+        pw.println("Vibrator Service:");
         synchronized (mLock) {
+            pw.print("  mCurrentVibration=");
+            if (mCurrentVibration != null) {
+                pw.println(mCurrentVibration.toInfo().toString());
+            } else {
+                pw.println("null");
+            }
+            pw.println("  mLowPowerMode=" + mLowPowerMode);
+            pw.println("  mHapticFeedbackIntensity=" + mHapticFeedbackIntensity);
+            pw.println("  mNotificationIntensity=" + mNotificationIntensity);
+            pw.println("");
+            pw.println("  Previous vibrations:");
             for (VibrationInfo info : mPreviousVibrations) {
-                pw.print("  ");
+                pw.print("    ");
                 pw.println(info.toString());
             }
         }
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 30432df4..5215b6f 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -87,6 +87,7 @@
         "media.metrics", // system/bin/mediametrics
         "media.codec", // vendor/bin/hw/android.hardware.media.omx@1.0-service
         "com.android.bluetooth",  // Bluetooth service
+        "statsd",  // Stats daemon
     };
 
     public static final List<String> HAL_INTERFACES_OF_INTEREST = Arrays.asList(
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 266abf8..2f7d4c1 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -1042,14 +1042,20 @@
                         throw new SecurityException("Instant app " + r.appInfo.packageName
                                 + " does not have permission to create foreground services");
                     default:
-                        mAm.enforcePermission(
-                                android.Manifest.permission.INSTANT_APP_FOREGROUND_SERVICE,
-                                r.app.pid, r.appInfo.uid, "startForeground");
+                        try {
+                            if (AppGlobals.getPackageManager().checkPermission(
+                                    android.Manifest.permission.INSTANT_APP_FOREGROUND_SERVICE,
+                                    r.appInfo.packageName, UserHandle.getUserId(r.appInfo.uid))
+                                            != PackageManager.PERMISSION_GRANTED) {
+                                throw new SecurityException("Instant app " + r.appInfo.packageName
+                                        + " does not have permission to create foreground"
+                                        + "services");
+                            }
+                        } catch (RemoteException e) {
+                            throw new SecurityException("Failed to check instant app permission." ,
+                                    e);
+                        }
                 }
-            } else if (r.appInfo.targetSdkVersion >= Build.VERSION_CODES.P) {
-                mAm.enforcePermission(
-                        android.Manifest.permission.FOREGROUND_SERVICE,
-                        r.app.pid, r.appInfo.uid, "startForeground");
             }
             if (r.fgRequired) {
                 if (DEBUG_SERVICE || DEBUG_BACKGROUND_CHECK) {
diff --git a/services/core/java/com/android/server/am/ActivityDisplay.java b/services/core/java/com/android/server/am/ActivityDisplay.java
index db21ef1..220014f 100644
--- a/services/core/java/com/android/server/am/ActivityDisplay.java
+++ b/services/core/java/com/android/server/am/ActivityDisplay.java
@@ -16,6 +16,7 @@
 
 package com.android.server.am;
 
+import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
@@ -50,7 +51,9 @@
 import android.view.Display;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.wm.ConfigurationContainer;
+import com.android.server.wm.DisplayWindowController;
 
+import com.android.server.wm.WindowContainerListener;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 
@@ -58,7 +61,8 @@
  * Exactly one of these classes per Display in the system. Capable of holding zero or more
  * attached {@link ActivityStack}s.
  */
-class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
+class ActivityDisplay extends ConfigurationContainer<ActivityStack>
+        implements WindowContainerListener {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityDisplay" : TAG_AM;
     private static final String TAG_STACK = TAG + POSTFIX_STACK;
 
@@ -100,6 +104,8 @@
     // Used in updating the display size
     private Point mTmpDisplaySize = new Point();
 
+    private DisplayWindowController mWindowContainerController;
+
     ActivityDisplay(ActivityStackSupervisor supervisor, int displayId) {
         mSupervisor = supervisor;
         mDisplayId = displayId;
@@ -108,10 +114,15 @@
             throw new IllegalStateException("Display does not exist displayId=" + displayId);
         }
         mDisplay = display;
+        mWindowContainerController = createWindowContainerController();
 
         updateBounds();
     }
 
+    protected DisplayWindowController createWindowContainerController() {
+        return new DisplayWindowController(mDisplayId, this);
+    }
+
     void updateBounds() {
         mDisplay.getSize(mTmpDisplaySize);
         setBounds(0, 0, mTmpDisplaySize.x, mTmpDisplaySize.y);
@@ -148,7 +159,10 @@
 
     private void positionChildAt(ActivityStack stack, int position) {
         mStacks.remove(stack);
-        mStacks.add(getTopInsertPosition(stack, position), stack);
+        final int insertPosition = getTopInsertPosition(stack, position);
+        mStacks.add(insertPosition, stack);
+        mWindowContainerController.positionChildAt(stack.getWindowContainerController(),
+                insertPosition);
     }
 
     private int getTopInsertPosition(ActivityStack stack, int candidatePosition) {
@@ -410,7 +424,7 @@
             }
         } finally {
             final ActivityStack topFullscreenStack =
-                    getStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+                    getTopStackInWindowingMode(WINDOWING_MODE_FULLSCREEN);
             if (topFullscreenStack != null && mHomeStack != null && !isTopStack(mHomeStack)) {
                 // Whenever split-screen is dismissed we want the home stack directly behind the
                 // current top fullscreen stack so it shows up when the top stack is finished.
@@ -566,6 +580,16 @@
         return false;
     }
 
+    ActivityStack getTopStackInWindowingMode(int windowingMode) {
+        for (int i = mStacks.size() - 1; i >= 0; --i) {
+            final ActivityStack current = mStacks.get(i);
+            if (windowingMode == current.getWindowingMode()) {
+                return current;
+            }
+        }
+        return null;
+    }
+
     int getIndexOf(ActivityStack stack) {
         return mStacks.indexOf(stack);
     }
@@ -651,6 +675,64 @@
                 && (mSupervisor.mService.mRunningVoice == null);
     }
 
+    /**
+     * @return the stack currently above the home stack.  Can be null if there is no home stack, or
+     *         the home stack is already on top.
+     */
+    ActivityStack getStackAboveHome() {
+        if (mHomeStack == null) {
+            // Skip if there is no home stack
+            return null;
+        }
+
+        final int stackIndex = mStacks.indexOf(mHomeStack) + 1;
+        return (stackIndex < mStacks.size()) ? mStacks.get(stackIndex) : null;
+    }
+
+    /**
+     * Adjusts the home stack behind the last visible stack in the display if necessary. Generally
+     * used in conjunction with {@link #moveHomeStackBehindStack}.
+     */
+    void moveHomeStackBehindBottomMostVisibleStack() {
+        if (mHomeStack == null) {
+            // Skip if there is no home stack
+            return;
+        }
+
+        // Move the home stack to the bottom to not affect the following visibility checks
+        positionChildAtBottom(mHomeStack);
+
+        // Find the next position where the homes stack should be placed
+        final int numStacks = mStacks.size();
+        for (int stackNdx = 0; stackNdx < numStacks; stackNdx++) {
+            final ActivityStack stack = mStacks.get(stackNdx);
+            if (stack == mHomeStack) {
+                continue;
+            }
+            final int winMode = stack.getWindowingMode();
+            final boolean isValidWindowingMode = winMode == WINDOWING_MODE_FULLSCREEN ||
+                    winMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+            if (stack.shouldBeVisible(null) && isValidWindowingMode) {
+                // Move the home stack to behind this stack
+                positionChildAt(mHomeStack, Math.max(0, stackNdx - 1));
+                break;
+            }
+        }
+    }
+
+    /**
+     * Moves the home stack behind the given {@param stack} if possible. If {@param stack} is not
+     * currently in the display, then then the home stack is moved to the back. Generally used in
+     * conjunction with {@link #moveHomeStackBehindBottomMostVisibleStack}.
+     */
+    void moveHomeStackBehindStack(ActivityStack behindStack) {
+        if (behindStack == null) {
+            return;
+        }
+
+        positionChildAt(mHomeStack, Math.max(0, mStacks.indexOf(behindStack) - 1));
+    }
+
     boolean isSleeping() {
         return mSleeping;
     }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 364d5d5..f658b27 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -39,6 +39,7 @@
 import static android.app.ActivityThread.PROC_START_SEQ_IDENT;
 import static android.app.AppOpsManager.OP_ASSIST_STRUCTURE;
 import static android.app.AppOpsManager.OP_NONE;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
@@ -46,6 +47,7 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
@@ -228,6 +230,7 @@
 import android.app.BroadcastOptions;
 import android.app.ContentProviderHolder;
 import android.app.Dialog;
+import android.app.GrantedUriPermission;
 import android.app.IActivityController;
 import android.app.IActivityManager;
 import android.app.IApplicationThread;
@@ -376,6 +379,7 @@
 import android.util.proto.ProtoOutputStream;
 import android.util.proto.ProtoUtils;
 import android.view.Gravity;
+import android.view.IRecentsAnimationRunner;
 import android.view.LayoutInflater;
 import android.view.RemoteAnimationDefinition;
 import android.view.View;
@@ -449,6 +453,7 @@
 import com.android.server.utils.PriorityDump;
 import com.android.server.vr.VrManagerInternal;
 import com.android.server.wm.PinnedStackWindowController;
+import com.android.server.wm.RecentsAnimationController;
 import com.android.server.wm.WindowManagerService;
 
 import dalvik.system.VMRuntime;
@@ -1633,6 +1638,14 @@
     String mProfileApp = null;
     ProcessRecord mProfileProc = null;
     ProfilerInfo mProfilerInfo = null;
+
+    /**
+     * Stores a map of process name -> agent string. When a process is started and mAgentAppMap
+     * is not null, this map is checked and the mapped agent installed during bind-time. Note:
+     * A non-null agent in mProfileInfo overrides this.
+     */
+    private @Nullable Map<String, String> mAppAgentMap = null;
+
     int mProfileType = 0;
     final ProcessMap<Pair<Long, String>> mMemWatchProcesses = new ProcessMap<>();
     String mMemWatchDumpProcName;
@@ -5095,23 +5108,16 @@
     }
 
     @Override
-    public int startRecentsActivity(IAssistDataReceiver assistDataReceiver, Bundle options,
-            Bundle activityOptions, int userId) {
-        if (!mRecentTasks.isCallerRecents(Binder.getCallingUid())) {
-            String msg = "Permission Denial: startRecentsActivity() from pid="
-                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
-                    + " not recent tasks package";
-            Slog.w(TAG, msg);
-            throw new SecurityException(msg);
-        }
-
-        final SafeActivityOptions safeOptions = SafeActivityOptions.fromBundle(options);
-        final int recentsUid = mRecentTasks.getRecentsComponentUid();
-        final ComponentName recentsComponent = mRecentTasks.getRecentsComponent();
-        final String recentsPackage = recentsComponent.getPackageName();
+    public void startRecentsActivity(Intent intent, IAssistDataReceiver assistDataReceiver,
+                IRecentsAnimationRunner recentsAnimationRunner) {
+        enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "startRecentsActivity()");
         final long origId = Binder.clearCallingIdentity();
         try {
             synchronized (this) {
+                final int recentsUid = mRecentTasks.getRecentsComponentUid();
+                final ComponentName recentsComponent = mRecentTasks.getRecentsComponent();
+                final String recentsPackage = recentsComponent.getPackageName();
+
                 // If provided, kick off the request for the assist data in the background before
                 // starting the activity
                 if (assistDataReceiver != null) {
@@ -5128,17 +5134,24 @@
                             recentsUid, recentsPackage);
                 }
 
-                final Intent intent = new Intent();
-                intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
-                intent.setComponent(recentsComponent);
-                intent.putExtras(options);
+                // Start a new recents animation
+                final RecentsAnimation anim = new RecentsAnimation(this, mStackSupervisor,
+                        mActivityStartController, mWindowManager, mUserController);
+                anim.startRecentsActivity(intent, recentsAnimationRunner, recentsComponent,
+                        recentsUid);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
 
-                return mActivityStartController.obtainStarter(intent, "startRecentsActivity")
-                        .setCallingUid(recentsUid)
-                        .setCallingPackage(recentsPackage)
-                        .setActivityOptions(safeOptions)
-                        .setMayWait(userId)
-                        .execute();
+    @Override
+    public void cancelRecentsAnimation() {
+        enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "cancelRecentsAnimation()");
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized (this) {
+                mWindowManager.cancelRecentsAnimation();
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
@@ -7452,25 +7465,6 @@
                 }
             }
 
-            ProfilerInfo profilerInfo = null;
-            String preBindAgent = null;
-            if (mProfileApp != null && mProfileApp.equals(processName)) {
-                mProfileProc = app;
-                if (mProfilerInfo != null) {
-                    // Send a profiler info object to the app if either a file is given, or
-                    // an agent should be loaded at bind-time.
-                    boolean needsInfo = mProfilerInfo.profileFile != null
-                            || mProfilerInfo.attachAgentDuringBind;
-                    profilerInfo = needsInfo ? new ProfilerInfo(mProfilerInfo) : null;
-                    if (!mProfilerInfo.attachAgentDuringBind) {
-                        preBindAgent = mProfilerInfo.agent;
-                    }
-                }
-            } else if (app.instr != null && app.instr.mProfileFile != null) {
-                profilerInfo = new ProfilerInfo(app.instr.mProfileFile, null, 0, false, false,
-                        null, false);
-            }
-
             boolean enableTrackAllocation = false;
             if (mTrackAllocationApp != null && mTrackAllocationApp.equals(processName)) {
                 enableTrackAllocation = true;
@@ -7495,6 +7489,39 @@
             ApplicationInfo appInfo = app.instr != null ? app.instr.mTargetInfo : app.info;
             app.compat = compatibilityInfoForPackageLocked(appInfo);
 
+            ProfilerInfo profilerInfo = null;
+            String preBindAgent = null;
+            if (mProfileApp != null && mProfileApp.equals(processName)) {
+                mProfileProc = app;
+                if (mProfilerInfo != null) {
+                    // Send a profiler info object to the app if either a file is given, or
+                    // an agent should be loaded at bind-time.
+                    boolean needsInfo = mProfilerInfo.profileFile != null
+                            || mProfilerInfo.attachAgentDuringBind;
+                    profilerInfo = needsInfo ? new ProfilerInfo(mProfilerInfo) : null;
+                    if (mProfilerInfo.agent != null) {
+                        preBindAgent = mProfilerInfo.agent;
+                    }
+                }
+            } else if (app.instr != null && app.instr.mProfileFile != null) {
+                profilerInfo = new ProfilerInfo(app.instr.mProfileFile, null, 0, false, false,
+                        null, false);
+            }
+            if (mAppAgentMap != null && mAppAgentMap.containsKey(processName)) {
+                // We need to do a debuggable check here. See setAgentApp for why the check is
+                // postponed to here.
+                if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
+                    String agent = mAppAgentMap.get(processName);
+                    // Do not overwrite already requested agent.
+                    if (profilerInfo == null) {
+                        profilerInfo = new ProfilerInfo(null, null, 0, false, false,
+                                mAppAgentMap.get(processName), true);
+                    } else if (profilerInfo.agent == null) {
+                        profilerInfo = profilerInfo.setAgent(mAppAgentMap.get(processName), true);
+                    }
+                }
+            }
+
             if (profilerInfo != null && profilerInfo.profileFd != null) {
                 profilerInfo.profileFd = profilerInfo.profileFd.dup();
             }
@@ -8890,20 +8917,6 @@
     /**
      * This can be called with or without the global lock held.
      */
-    void enforcePermission(String permission, int pid, int uid, String func) {
-        if (checkPermission(permission, pid, uid) == PackageManager.PERMISSION_GRANTED) {
-            return;
-        }
-
-        String msg = "Permission Denial: " + func + " from pid=" + pid + ", uid=" + uid
-                + " requires " + permission;
-        Slog.w(TAG, msg);
-        throw new SecurityException(msg);
-    }
-
-    /**
-     * This can be called with or without the global lock held.
-     */
     void enforceCallerIsRecentsOrHasPermission(String permission, String func) {
         if (!mRecentTasks.isCallerRecents(Binder.getCallingUid())) {
             enforceCallingPermission(permission, func);
@@ -10204,7 +10217,8 @@
                 if (perms == null) {
                     Slog.w(TAG, "No permission grants found for " + packageName);
                 } else {
-                    for (UriPermission perm : perms.values()) {
+                    for (int j = 0; j < perms.size(); j++) {
+                        final UriPermission perm = perms.valueAt(j);
                         if (packageName.equals(perm.targetPkg) && perm.persistedModeFlags != 0) {
                             result.add(perm.buildPersistedPublicApiObject());
                         }
@@ -10215,7 +10229,8 @@
                 for (int i = 0; i < size; i++) {
                     final ArrayMap<GrantUri, UriPermission> perms =
                             mGrantedUriPermissions.valueAt(i);
-                    for (UriPermission perm : perms.values()) {
+                    for (int j = 0; j < perms.size(); j++) {
+                        final UriPermission perm = perms.valueAt(j);
                         if (packageName.equals(perm.sourcePkg) && perm.persistedModeFlags != 0) {
                             result.add(perm.buildPersistedPublicApiObject());
                         }
@@ -10227,25 +10242,27 @@
     }
 
     @Override
-    public ParceledListSlice<android.content.UriPermission> getGrantedUriPermissions(
-            String packageName, int userId) {
+    public ParceledListSlice<GrantedUriPermission> getGrantedUriPermissions(
+            @Nullable String packageName, int userId) {
         enforceCallingPermission(android.Manifest.permission.GET_APP_GRANTED_URI_PERMISSIONS,
                 "getGrantedUriPermissions");
 
-        final ArrayList<android.content.UriPermission> result = Lists.newArrayList();
+        final List<GrantedUriPermission> result = new ArrayList<>();
         synchronized (this) {
             final int size = mGrantedUriPermissions.size();
             for (int i = 0; i < size; i++) {
                 final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.valueAt(i);
-                for (UriPermission perm : perms.values()) {
-                    if (packageName.equals(perm.targetPkg) && perm.targetUserId == userId
+                for (int j = 0; j < perms.size(); j++) {
+                    final UriPermission perm = perms.valueAt(j);
+                    if ((packageName == null || packageName.equals(perm.targetPkg))
+                            && perm.targetUserId == userId
                             && perm.persistedModeFlags != 0) {
-                        result.add(perm.buildPersistedPublicApiObject());
+                        result.add(perm.buildGrantedUriPermission());
                     }
                 }
             }
         }
-        return new ParceledListSlice<android.content.UriPermission>(result);
+        return new ParceledListSlice<>(result);
     }
 
     @Override
@@ -11037,8 +11054,20 @@
                 }
 
                 if (toTop) {
+                    // Caller wants the current split-screen primary stack to be the top stack after
+                    // it goes fullscreen, so move it to the front.
                     stack.moveToFront("dismissSplitScreenMode");
+                } else if (mStackSupervisor.isFocusedStack(stack)) {
+                    // In this case the current split-screen primary stack shouldn't be the top
+                    // stack after it goes fullscreen, but it current has focus, so we move the
+                    // focus to the top-most split-screen secondary stack next to it.
+                    final ActivityStack otherStack = stack.getDisplay().getTopStackInWindowingMode(
+                            WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+                    if (otherStack != null) {
+                        otherStack.moveToFront("dismissSplitScreenMode_other");
+                    }
                 }
+
                 stack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
             }
         } finally {
@@ -13147,6 +13176,52 @@
         }
     }
 
+    /**
+     * Set or remove an agent to be run whenever an app with the given process name starts.
+     *
+     * This method will not check whether the given process name matches a debuggable app. That
+     * would require scanning all current packages, and a rescan when new packages are installed
+     * or updated.
+     *
+     * Instead, do the check when an application is started and matched to a stored agent.
+     *
+     * @param packageName the process name of the app.
+     * @param agent the agent string to be used, or null to remove any previously set agent.
+     */
+    @Override
+    public void setAgentApp(@NonNull String packageName, @Nullable String agent) {
+        synchronized (this) {
+            // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
+            // its own permission.
+            if (checkCallingPermission(
+                    android.Manifest.permission.SET_ACTIVITY_WATCHER) !=
+                        PackageManager.PERMISSION_GRANTED) {
+                throw new SecurityException(
+                        "Requires permission " + android.Manifest.permission.SET_ACTIVITY_WATCHER);
+            }
+
+            if (agent == null) {
+                if (mAppAgentMap != null) {
+                    mAppAgentMap.remove(packageName);
+                    if (mAppAgentMap.isEmpty()) {
+                        mAppAgentMap = null;
+                    }
+                }
+            } else {
+                if (mAppAgentMap == null) {
+                    mAppAgentMap = new HashMap<>();
+                }
+                if (mAppAgentMap.size() >= 100) {
+                    // Limit the size of the map, to avoid OOMEs.
+                    Slog.e(TAG, "App agent map has too many entries, cannot add " + packageName
+                            + "/" + agent);
+                    return;
+                }
+                mAppAgentMap.put(packageName, agent);
+            }
+        }
+    }
+
     void setTrackAllocationApp(ApplicationInfo app, String processName) {
         synchronized (this) {
             boolean isDebuggable = "1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"));
@@ -25537,11 +25612,14 @@
             // "= 0" is needed because otherwise catch(RemoteException) would make it look like
             // packageUid may not be initialized.
             int packageUid = 0;
+            final long ident = Binder.clearCallingIdentity();
             try {
                 packageUid = AppGlobals.getPackageManager().getPackageUid(
                         packageName, PackageManager.MATCH_DEBUG_TRIAGED_MISSING, userId);
             } catch (RemoteException e) {
                 // Shouldn't happen.
+            } finally {
+                Binder.restoreCallingIdentity(ident);
             }
 
             synchronized (ActivityManagerService.this) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 1240f5e..f0c90e0 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -160,6 +160,8 @@
                     return runDumpHeap(pw);
                 case "set-debug-app":
                     return runSetDebugApp(pw);
+                case "set-agent-app":
+                    return runSetAgentApp(pw);
                 case "clear-debug-app":
                     return runClearDebugApp(pw);
                 case "set-watch-heap":
@@ -873,6 +875,13 @@
         return 0;
     }
 
+    int runSetAgentApp(PrintWriter pw) throws RemoteException {
+        String pkg = getNextArgRequired();
+        String agent = getNextArg();
+        mInterface.setAgentApp(pkg, agent);
+        return 0;
+    }
+
     int runClearDebugApp(PrintWriter pw) throws RemoteException {
         mInterface.setDebugApp(null, false, true);
         return 0;
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 9d06b0d..ec8cf91 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -481,7 +481,7 @@
 
     @Override
     public void setWindowingMode(int windowingMode) {
-        setWindowingMode(windowingMode, false /* animate */, true /* showRecents */,
+        setWindowingMode(windowingMode, false /* animate */, false /* showRecents */,
                 false /* enteringSplitScreenMode */);
     }
 
@@ -642,7 +642,10 @@
         // TODO: We should probably resolve the windowing mode for the stack on the new display here
         // so that it end up in a compatible mode in the new display. e.g. split-screen secondary.
         removeFromDisplay();
+        // Reparent the window container before we try to update the position when adding it to
+        // the new display below
         mTmpRect2.setEmpty();
+        mWindowContainerController.reparent(activityDisplay.mDisplayId, mTmpRect2, onTop);
         postAddToDisplay(activityDisplay, mTmpRect2.isEmpty() ? null : mTmpRect2, onTop);
         adjustFocusToNextFocusableStack("reparent", true /* allowFocusSelf */);
         mStackSupervisor.resumeFocusedStackTopActivityLocked();
@@ -650,7 +653,6 @@
         // windows that are no longer visible.
         mStackSupervisor.ensureActivitiesVisibleLocked(null /* starting */, 0 /* configChanges */,
                 !PRESERVE_WINDOWS);
-        mWindowContainerController.reparent(activityDisplay.mDisplayId, mTmpRect2, onTop);
     }
 
     /**
@@ -994,12 +996,6 @@
             insertTaskAtTop(task, null);
             return;
         }
-
-        task = topTask();
-        if (task != null) {
-            mWindowContainerController.positionChildAtTop(task.getWindowContainerController(),
-                    true /* includingParents */);
-        }
     }
 
     /**
@@ -1024,12 +1020,6 @@
         if (task != null) {
             insertTaskAtBottom(task);
             return;
-        } else {
-            task = bottomTask();
-            if (task != null) {
-                mWindowContainerController.positionChildAtBottom(
-                        task.getWindowContainerController(), true /* includingParents */);
-            }
         }
     }
 
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index bfb563f..510a3fa 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -297,6 +297,7 @@
     private RunningTasks mRunningTasks;
 
     final ActivityStackSupervisorHandler mHandler;
+    final Looper mLooper;
 
     /** Short cut */
     WindowManagerService mWindowManager;
@@ -581,6 +582,7 @@
 
     public ActivityStackSupervisor(ActivityManagerService service, Looper looper) {
         mService = service;
+        mLooper = looper;
         mHandler = new ActivityStackSupervisorHandler(looper);
     }
 
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 4dc30dd..8fd754a 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -302,6 +302,7 @@
         SafeActivityOptions activityOptions;
         boolean ignoreTargetSecurity;
         boolean componentSpecified;
+        boolean avoidMoveToFront;
         ActivityRecord[] outActivity;
         TaskRecord inTask;
         String reason;
@@ -356,6 +357,7 @@
             userId = 0;
             waitResult = null;
             mayWait = false;
+            avoidMoveToFront = false;
         }
 
         /**
@@ -390,6 +392,7 @@
             userId = request.userId;
             waitResult = request.waitResult;
             mayWait = request.mayWait;
+            avoidMoveToFront = request.avoidMoveToFront;
         }
     }
 
@@ -1485,19 +1488,23 @@
             mDoResume = false;
         }
 
-        if (mOptions != null && mOptions.getLaunchTaskId() != -1
-                && mOptions.getTaskOverlay()) {
-            r.mTaskOverlay = true;
-            if (!mOptions.canTaskOverlayResume()) {
-                final TaskRecord task = mSupervisor.anyTaskForIdLocked(mOptions.getLaunchTaskId());
-                final ActivityRecord top = task != null ? task.getTopActivity() : null;
-                if (top != null && top.state != RESUMED) {
+        if (mOptions != null) {
+            if (mOptions.getLaunchTaskId() != -1 && mOptions.getTaskOverlay()) {
+                r.mTaskOverlay = true;
+                if (!mOptions.canTaskOverlayResume()) {
+                    final TaskRecord task = mSupervisor.anyTaskForIdLocked(
+                            mOptions.getLaunchTaskId());
+                    final ActivityRecord top = task != null ? task.getTopActivity() : null;
+                    if (top != null && top.state != RESUMED) {
 
-                    // The caller specifies that we'd like to be avoided to be moved to the front,
-                    // so be it!
-                    mDoResume = false;
-                    mAvoidMoveToFront = true;
+                        // The caller specifies that we'd like to be avoided to be moved to the
+                        // front, so be it!
+                        mDoResume = false;
+                        mAvoidMoveToFront = true;
+                    }
                 }
+            } else if (mOptions.getAvoidMoveToFront()) {
+                mAvoidMoveToFront = true;
             }
         }
 
@@ -1838,7 +1845,7 @@
         // Need to update mTargetStack because if task was moved out of it, the original stack may
         // be destroyed.
         mTargetStack = intentActivity.getStack();
-        if (!mMovedToFront && mDoResume) {
+        if (!mAvoidMoveToFront && !mMovedToFront && mDoResume) {
             if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Bring to front target: " + mTargetStack
                     + " from " + intentActivity);
             mTargetStack.moveToFront("intentActivityFound");
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 6b380f1..0d96468 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -16,6 +16,7 @@
 
 package com.android.server.am;
 
+import android.app.ActivityManager;
 import android.bluetooth.BluetoothActivityEnergyInfo;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
@@ -353,10 +354,12 @@
         }
     }
 
+    /** @param state Process state from ActivityManager.java. */
     void noteUidProcessState(int uid, int state) {
         synchronized (mStats) {
             // TODO: remove this once we figure out properly where and how
-            StatsLog.write(StatsLog.UID_PROCESS_STATE_CHANGED, uid, state);
+            StatsLog.write(StatsLog.UID_PROCESS_STATE_CHANGED, uid,
+                    ActivityManager.processStateAmToProto(state));
 
             mStats.noteUidProcessStateLocked(uid, state);
         }
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 29bfebe..a50d069 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -24,7 +24,7 @@
 import java.nio.ByteBuffer;
 
 import android.app.ActivityManager;
-import android.app.ActivityManagerProto;
+import android.app.AppProtoEnums;
 import android.os.Build;
 import android.os.SystemClock;
 import com.android.internal.util.MemInfoReader;
@@ -420,47 +420,49 @@
     public static int makeProcStateProtoEnum(int curProcState) {
         switch (curProcState) {
             case ActivityManager.PROCESS_STATE_PERSISTENT:
-                return ActivityManagerProto.PROCESS_STATE_PERSISTENT;
+                return AppProtoEnums.PROCESS_STATE_PERSISTENT;
             case ActivityManager.PROCESS_STATE_PERSISTENT_UI:
-                return ActivityManagerProto.PROCESS_STATE_PERSISTENT_UI;
+                return AppProtoEnums.PROCESS_STATE_PERSISTENT_UI;
             case ActivityManager.PROCESS_STATE_TOP:
-                return ActivityManagerProto.PROCESS_STATE_TOP;
+                return AppProtoEnums.PROCESS_STATE_TOP;
             case ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE:
-                return ActivityManagerProto.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
+                return AppProtoEnums.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
             case ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE:
-                return ActivityManagerProto.PROCESS_STATE_FOREGROUND_SERVICE;
+                return AppProtoEnums.PROCESS_STATE_FOREGROUND_SERVICE;
             case ActivityManager.PROCESS_STATE_TOP_SLEEPING:
-                return ActivityManagerProto.PROCESS_STATE_TOP_SLEEPING;
+                return AppProtoEnums.PROCESS_STATE_TOP_SLEEPING;
             case ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND:
-                return ActivityManagerProto.PROCESS_STATE_IMPORTANT_FOREGROUND;
+                return AppProtoEnums.PROCESS_STATE_IMPORTANT_FOREGROUND;
             case ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND:
-                return ActivityManagerProto.PROCESS_STATE_IMPORTANT_BACKGROUND;
+                return AppProtoEnums.PROCESS_STATE_IMPORTANT_BACKGROUND;
             case ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND:
-                return ActivityManagerProto.PROCESS_STATE_TRANSIENT_BACKGROUND;
+                return AppProtoEnums.PROCESS_STATE_TRANSIENT_BACKGROUND;
             case ActivityManager.PROCESS_STATE_BACKUP:
-                return ActivityManagerProto.PROCESS_STATE_BACKUP;
+                return AppProtoEnums.PROCESS_STATE_BACKUP;
             case ActivityManager.PROCESS_STATE_HEAVY_WEIGHT:
-                return ActivityManagerProto.PROCESS_STATE_HEAVY_WEIGHT;
+                return AppProtoEnums.PROCESS_STATE_HEAVY_WEIGHT;
             case ActivityManager.PROCESS_STATE_SERVICE:
-                return ActivityManagerProto.PROCESS_STATE_SERVICE;
+                return AppProtoEnums.PROCESS_STATE_SERVICE;
             case ActivityManager.PROCESS_STATE_RECEIVER:
-                return ActivityManagerProto.PROCESS_STATE_RECEIVER;
+                return AppProtoEnums.PROCESS_STATE_RECEIVER;
             case ActivityManager.PROCESS_STATE_HOME:
-                return ActivityManagerProto.PROCESS_STATE_HOME;
+                return AppProtoEnums.PROCESS_STATE_HOME;
             case ActivityManager.PROCESS_STATE_LAST_ACTIVITY:
-                return ActivityManagerProto.PROCESS_STATE_LAST_ACTIVITY;
+                return AppProtoEnums.PROCESS_STATE_LAST_ACTIVITY;
             case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY:
-                return ActivityManagerProto.PROCESS_STATE_CACHED_ACTIVITY;
+                return AppProtoEnums.PROCESS_STATE_CACHED_ACTIVITY;
             case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
-                return ActivityManagerProto.PROCESS_STATE_CACHED_ACTIVITY_CLIENT;
+                return AppProtoEnums.PROCESS_STATE_CACHED_ACTIVITY_CLIENT;
             case ActivityManager.PROCESS_STATE_CACHED_RECENT:
-                return ActivityManagerProto.PROCESS_STATE_CACHED_RECENT;
+                return AppProtoEnums.PROCESS_STATE_CACHED_RECENT;
             case ActivityManager.PROCESS_STATE_CACHED_EMPTY:
-                return ActivityManagerProto.PROCESS_STATE_CACHED_EMPTY;
+                return AppProtoEnums.PROCESS_STATE_CACHED_EMPTY;
             case ActivityManager.PROCESS_STATE_NONEXISTENT:
-                return ActivityManagerProto.PROCESS_STATE_NONEXISTENT;
+                return AppProtoEnums.PROCESS_STATE_NONEXISTENT;
+            case ActivityManager.PROCESS_STATE_UNKNOWN:
+                return AppProtoEnums.PROCESS_STATE_UNKNOWN;
             default:
-                return -1;
+                return AppProtoEnums.PROCESS_STATE_UNKNOWN_TO_PROTO;
         }
     }
 
diff --git a/services/core/java/com/android/server/am/RecentsAnimation.java b/services/core/java/com/android/server/am/RecentsAnimation.java
new file mode 100644
index 0000000..fe576fda
--- /dev/null
+++ b/services/core/java/com/android/server/am/RecentsAnimation.java
@@ -0,0 +1,159 @@
+/*
+ * 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.am;
+
+import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.content.Intent.FLAG_ACTIVITY_NO_ANIMATION;
+import static android.view.WindowManager.TRANSIT_NONE;
+import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
+
+import android.app.ActivityOptions;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.os.Handler;
+import android.view.IRecentsAnimationRunner;
+import com.android.server.wm.RecentsAnimationController.RecentsAnimationCallbacks;
+import com.android.server.wm.WindowManagerService;
+
+/**
+ * Manages the recents animation, including the reordering of the stacks for the transition and
+ * cleanup. See {@link com.android.server.wm.RecentsAnimationController}.
+ */
+class RecentsAnimation implements RecentsAnimationCallbacks {
+    private static final String TAG = RecentsAnimation.class.getSimpleName();
+
+    private static final int RECENTS_ANIMATION_TIMEOUT = 10 * 1000;
+
+    private final ActivityManagerService mService;
+    private final ActivityStackSupervisor mStackSupervisor;
+    private final ActivityStartController mActivityStartController;
+    private final WindowManagerService mWindowManager;
+    private final UserController mUserController;
+    private final Handler mHandler;
+
+    private final Runnable mCancelAnimationRunnable;
+
+    // The stack to restore the home stack behind when the animation is finished
+    private ActivityStack mRestoreHomeBehindStack;
+
+    RecentsAnimation(ActivityManagerService am, ActivityStackSupervisor stackSupervisor,
+            ActivityStartController activityStartController, WindowManagerService wm,
+            UserController userController) {
+        mService = am;
+        mStackSupervisor = stackSupervisor;
+        mActivityStartController = activityStartController;
+        mHandler = new Handler(mStackSupervisor.mLooper);
+        mWindowManager = wm;
+        mUserController = userController;
+        mCancelAnimationRunnable = () -> {
+            // The caller has not finished the animation in a predefined amount of time, so
+            // force-cancel the animation
+            mWindowManager.cancelRecentsAnimation();
+        };
+    }
+
+    void startRecentsActivity(Intent intent, IRecentsAnimationRunner recentsAnimationRunner,
+            ComponentName recentsComponent, int recentsUid) {
+
+        // Cancel the previous recents animation if necessary
+        mWindowManager.cancelRecentsAnimation();
+
+        final boolean hasExistingHomeActivity = mStackSupervisor.getHomeActivity() != null;
+        if (!hasExistingHomeActivity) {
+            // No home activity
+            final ActivityOptions opts = ActivityOptions.makeBasic();
+            opts.setLaunchActivityType(ACTIVITY_TYPE_HOME);
+            opts.setAvoidMoveToFront();
+            intent.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_NO_ANIMATION);
+
+            mActivityStartController.obtainStarter(intent, "startRecentsActivity_noHomeActivity")
+                    .setCallingUid(recentsUid)
+                    .setCallingPackage(recentsComponent.getPackageName())
+                    .setActivityOptions(SafeActivityOptions.fromBundle(opts.toBundle()))
+                    .setMayWait(mUserController.getCurrentUserId())
+                    .execute();
+            mWindowManager.prepareAppTransition(TRANSIT_NONE, false);
+
+            // TODO: Maybe wait for app to draw in this particular case?
+        }
+
+        final ActivityRecord homeActivity = mStackSupervisor.getHomeActivity();
+        final ActivityDisplay display = homeActivity.getDisplay();
+
+        // Save the initial position of the home activity stack to be restored to after the
+        // animation completes
+        mRestoreHomeBehindStack = hasExistingHomeActivity
+                ? display.getStackAboveHome()
+                : null;
+
+        // Move the home activity into place for the animation
+        display.moveHomeStackBehindBottomMostVisibleStack();
+
+        // Mark the home activity as launch-behind to bump its visibility for the
+        // duration of the gesture that is driven by the recents component
+        homeActivity.mLaunchTaskBehind = true;
+
+        // Fetch all the surface controls and pass them to the client to get the animation
+        // started
+        mWindowManager.initializeRecentsAnimation(recentsAnimationRunner, this, display.mDisplayId);
+
+        // If we updated the launch-behind state, update the visibility of the activities after we
+        // fetch the visible tasks to be controlled by the animation
+        mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, PRESERVE_WINDOWS);
+
+        // Post a timeout for the animation
+        mHandler.postDelayed(mCancelAnimationRunnable, RECENTS_ANIMATION_TIMEOUT);
+    }
+
+    @Override
+    public void onAnimationFinished(boolean moveHomeToTop) {
+        mHandler.removeCallbacks(mCancelAnimationRunnable);
+        synchronized (mService) {
+            if (mWindowManager.getRecentsAnimationController() == null) return;
+
+            mWindowManager.inSurfaceTransaction(() -> {
+                mWindowManager.cleanupRecentsAnimation();
+
+                // Move the home stack to the front
+                final ActivityRecord homeActivity = mStackSupervisor.getHomeActivity();
+                if (homeActivity == null) {
+                    return;
+                }
+
+                // Restore the launched-behind state
+                homeActivity.mLaunchTaskBehind = false;
+
+                if (moveHomeToTop) {
+                    // Bring the home stack to the front
+                    final ActivityStack homeStack = homeActivity.getStack();
+                    homeStack.mNoAnimActivities.add(homeActivity);
+                    homeStack.moveToFront("RecentsAnimation.onAnimationFinished()");
+                } else {
+                    // Restore the home stack to its previous position
+                    final ActivityDisplay display = homeActivity.getDisplay();
+                    display.moveHomeStackBehindStack(mRestoreHomeBehindStack);
+                }
+
+                mWindowManager.prepareAppTransition(TRANSIT_NONE, false);
+                mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, false);
+                mStackSupervisor.resumeFocusedStackTopActivityLocked();
+            });
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/am/UriPermission.java b/services/core/java/com/android/server/am/UriPermission.java
index 90577e3..1e071aa 100644
--- a/services/core/java/com/android/server/am/UriPermission.java
+++ b/services/core/java/com/android/server/am/UriPermission.java
@@ -16,6 +16,7 @@
 
 package com.android.server.am;
 
+import android.app.GrantedUriPermission;
 import android.content.Intent;
 import android.os.Binder;
 import android.os.UserHandle;
@@ -387,4 +388,8 @@
     public android.content.UriPermission buildPersistedPublicApiObject() {
         return new android.content.UriPermission(uri.uri, persistedModeFlags, persistedCreateTime);
     }
+
+    public GrantedUriPermission buildGrantedUriPermission() {
+        return new GrantedUriPermission(uri.uri, targetPkg);
+    }
 }
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index bedf0431..edeee3e 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -133,6 +133,7 @@
 
 import org.xmlpull.v1.XmlPullParserException;
 
+import java.io.File;
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.PrintWriter;
@@ -4767,6 +4768,16 @@
             Settings.Global.putInt(mContentResolver, Settings.Global.MODE_RINGER, ringerMode);
         }
 
+        private String getSoundEffectFilePath(int effectType) {
+            String filePath = Environment.getProductDirectory() + SOUND_EFFECTS_PATH
+                    + SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effectType][0]);
+            if (!new File(filePath).isFile()) {
+                filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH
+                        + SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effectType][0]);
+            }
+            return filePath;
+        }
+
         private boolean onLoadSoundEffects() {
             int status;
 
@@ -4836,9 +4847,7 @@
                         continue;
                     }
                     if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) {
-                        String filePath = Environment.getRootDirectory()
-                                + SOUND_EFFECTS_PATH
-                                + SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effect][0]);
+                        String filePath = getSoundEffectFilePath(effect);
                         int sampleId = mSoundPool.load(filePath, 0);
                         if (sampleId <= 0) {
                             Log.w(TAG, "Soundpool could not load file: "+filePath);
@@ -4944,8 +4953,7 @@
                 } else {
                     MediaPlayer mediaPlayer = new MediaPlayer();
                     try {
-                        String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH +
-                                    SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effectType][0]);
+                        String filePath = getSoundEffectFilePath(effectType);
                         mediaPlayer.setDataSource(filePath);
                         mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM);
                         mediaPlayer.prepare();
diff --git a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
index 979beed..57258a8 100644
--- a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
+++ b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
@@ -257,6 +257,29 @@
                 uid, iface, ethertype, dstMac, srcIp, dstIp, ipNextHeader, srcPort, dstPort);
     }
 
+    @Override
+    public synchronized void onTcpSocketStatsEvent(int[] networkIds,
+            int[] sentPackets, int[] lostPackets, int[] rttsUs, int[] sentAckDiffsMs) {
+        if (networkIds.length != sentPackets.length
+                || networkIds.length != lostPackets.length
+                || networkIds.length != rttsUs.length
+                || networkIds.length != sentAckDiffsMs.length) {
+            Log.e(TAG, "Mismatched lengths of TCP socket stats data arrays");
+            return;
+        }
+
+        long timestamp = System.currentTimeMillis();
+        for (int i = 0; i < networkIds.length; i++) {
+            int netId = networkIds[i];
+            int sent = sentPackets[i];
+            int lost = lostPackets[i];
+            int rttUs = rttsUs[i];
+            int sentAckDiffMs = sentAckDiffsMs[i];
+            getMetricsForNetwork(timestamp, netId)
+                    .addTcpStatsResult(sent, lost, rttUs, sentAckDiffMs);
+        }
+    }
+
     private void addWakeupEvent(WakeupEvent event) {
         String iface = event.iface;
         mWakeupEvents.append(event);
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index ad2cf6c..422d0cb 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -20,6 +20,8 @@
 import android.accounts.AccountAndUser;
 import android.accounts.AccountManager;
 import android.accounts.AccountManagerInternal;
+import android.annotation.NonNull;
+import android.annotation.UserIdInt;
 import android.app.ActivityManager;
 import android.app.AppGlobals;
 import android.app.Notification;
@@ -32,6 +34,7 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.ISyncAdapter;
+import android.content.ISyncAdapterUnsyncableAccountCallback;
 import android.content.ISyncContext;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -212,6 +215,10 @@
     private static final int SYNC_OP_STATE_INVALID = 1;
     private static final int SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS = 2;
 
+    /** Flags used when connecting to a sync adapter service */
+    private static final int SYNC_ADAPTER_CONNECTION_FLAGS = Context.BIND_AUTO_CREATE
+            | Context.BIND_NOT_FOREGROUND | Context.BIND_ALLOW_OOM_MANAGEMENT;
+
     private Context mContext;
 
     private static final AccountAndUser[] INITIAL_ACCOUNTS_ARRAY = new AccountAndUser[0];
@@ -876,7 +883,7 @@
     public void scheduleSync(Account requestedAccount, int userId, int reason,
                              String requestedAuthority, Bundle extras, int targetSyncState) {
         scheduleSync(requestedAccount, userId, reason, requestedAuthority, extras, targetSyncState,
-                0 /* min delay */);
+                0 /* min delay */, true /* checkIfAccountReady */);
     }
 
     /**
@@ -884,7 +891,7 @@
      */
     private void scheduleSync(Account requestedAccount, int userId, int reason,
                              String requestedAuthority, Bundle extras, int targetSyncState,
-                             final long minDelayMillis) {
+                             final long minDelayMillis, boolean checkIfAccountReady) {
         final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
         if (extras == null) {
             extras = new Bundle();
@@ -963,7 +970,8 @@
             }
 
             for (String authority : syncableAuthorities) {
-                int isSyncable = computeSyncable(account.account, account.userId, authority);
+                int isSyncable = computeSyncable(account.account, account.userId, authority,
+                        !checkIfAccountReady);
 
                 if (isSyncable == AuthorityInfo.NOT_SYNCABLE) {
                     continue;
@@ -1000,7 +1008,8 @@
                                 if (result != null
                                         && result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT)) {
                                     scheduleSync(account.account, userId, reason, authority,
-                                            finalExtras, targetSyncState, minDelayMillis);
+                                            finalExtras, targetSyncState, minDelayMillis,
+                                            true /* checkIfAccountReady */);
                                 }
                             }
                         ));
@@ -1009,7 +1018,7 @@
 
                 final boolean allowParallelSyncs = syncAdapterInfo.type.allowParallelSyncs();
                 final boolean isAlwaysSyncable = syncAdapterInfo.type.isAlwaysSyncable();
-                if (isSyncable < 0 && isAlwaysSyncable) {
+                if (!checkIfAccountReady && isSyncable < 0 && isAlwaysSyncable) {
                     mSyncStorageEngine.setIsSyncable(
                             account.account, account.userId, authority, AuthorityInfo.SYNCABLE);
                     isSyncable = AuthorityInfo.SYNCABLE;
@@ -1045,25 +1054,34 @@
                 final String owningPackage = syncAdapterInfo.componentName.getPackageName();
 
                 if (isSyncable == AuthorityInfo.NOT_INITIALIZED) {
-                    // Initialisation sync.
-                    Bundle newExtras = new Bundle();
-                    newExtras.putBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, true);
-                    if (isLoggable) {
-                        Slog.v(TAG, "schedule initialisation Sync:"
-                                + ", delay until " + delayUntil
-                                + ", run by " + 0
-                                + ", flexMillis " + 0
-                                + ", source " + source
-                                + ", account " + account
-                                + ", authority " + authority
-                                + ", extras " + newExtras);
+                    if (checkIfAccountReady) {
+                        Bundle finalExtras = new Bundle(extras);
+
+                        sendOnUnsyncableAccount(mContext, syncAdapterInfo, account.userId,
+                                () -> scheduleSync(account.account, account.userId, reason,
+                                        authority, finalExtras, targetSyncState, minDelayMillis,
+                                        false));
+                    } else {
+                        // Initialisation sync.
+                        Bundle newExtras = new Bundle();
+                        newExtras.putBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, true);
+                        if (isLoggable) {
+                            Slog.v(TAG, "schedule initialisation Sync:"
+                                    + ", delay until " + delayUntil
+                                    + ", run by " + 0
+                                    + ", flexMillis " + 0
+                                    + ", source " + source
+                                    + ", account " + account
+                                    + ", authority " + authority
+                                    + ", extras " + newExtras);
+                        }
+                        postScheduleSyncMessage(
+                                new SyncOperation(account.account, account.userId,
+                                        owningUid, owningPackage, reason, source,
+                                        authority, newExtras, allowParallelSyncs),
+                                minDelayMillis
+                        );
                     }
-                    postScheduleSyncMessage(
-                            new SyncOperation(account.account, account.userId,
-                                    owningUid, owningPackage, reason, source,
-                                    authority, newExtras, allowParallelSyncs),
-                            minDelayMillis
-                    );
                 } else if (targetSyncState == AuthorityInfo.UNDEFINED
                         || targetSyncState == isSyncable) {
                     if (isLoggable) {
@@ -1085,10 +1103,6 @@
         }
     }
 
-    private int computeSyncable(Account account, int userId, String authority) {
-        return computeSyncable(account, userId, authority, true);
-    }
-
     public int computeSyncable(Account account, int userId, String authority,
             boolean checkAccountAccess) {
         final int status = getIsSyncable(account, userId, authority);
@@ -1198,7 +1212,7 @@
         final Bundle extras = new Bundle();
         extras.putBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, true);
         scheduleSync(account, userId, reason, authority, extras,
-                AuthorityInfo.UNDEFINED, LOCAL_SYNC_DELAY);
+                AuthorityInfo.UNDEFINED, LOCAL_SYNC_DELAY, true /* checkIfAccountReady */);
     }
 
     public SyncAdapterType[] getSyncAdapterTypes(int userId) {
@@ -1706,6 +1720,28 @@
     }
 
     /**
+     * Construct intent used to bind to an adapter.
+     *
+     * @param context Context to create intent for
+     * @param syncAdapterComponent The adapter description
+     * @param userId The user the adapter belongs to
+     *
+     * @return The intent required to bind to the adapter
+     */
+    static @NonNull Intent getAdapterBindIntent(@NonNull Context context,
+            @NonNull ComponentName syncAdapterComponent, @UserIdInt int userId) {
+        final Intent intent = new Intent();
+        intent.setAction("android.content.SyncAdapter");
+        intent.setComponent(syncAdapterComponent);
+        intent.putExtra(Intent.EXTRA_CLIENT_LABEL,
+                com.android.internal.R.string.sync_binding_label);
+        intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivityAsUser(context, 0,
+                new Intent(Settings.ACTION_SYNC_SETTINGS), 0, null, UserHandle.of(userId)));
+
+        return intent;
+    }
+
+    /**
      * @hide
      */
     class ActiveSyncContext extends ISyncContext.Stub
@@ -1793,19 +1829,11 @@
             if (Log.isLoggable(TAG, Log.VERBOSE)) {
                 Log.d(TAG, "bindToSyncAdapter: " + serviceComponent + ", connection " + this);
             }
-            Intent intent = new Intent();
-            intent.setAction("android.content.SyncAdapter");
-            intent.setComponent(serviceComponent);
-            intent.putExtra(Intent.EXTRA_CLIENT_LABEL,
-                    com.android.internal.R.string.sync_binding_label);
-            intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivityAsUser(
-                    mContext, 0, new Intent(Settings.ACTION_SYNC_SETTINGS), 0,
-                    null, new UserHandle(userId)));
+            Intent intent = getAdapterBindIntent(mContext, serviceComponent, userId);
+
             mBound = true;
             final boolean bindResult = mContext.bindServiceAsUser(intent, this,
-                    Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND
-                            | Context.BIND_ALLOW_OOM_MANAGEMENT,
-                    new UserHandle(mSyncOperation.target.userId));
+                    SYNC_ADAPTER_CONNECTION_FLAGS, new UserHandle(mSyncOperation.target.userId));
             mLogger.log("bindService() returned=", mBound, " for ", this);
             if (!bindResult) {
                 mBound = false;
@@ -2528,6 +2556,92 @@
         }
     }
 
+    interface OnReadyCallback {
+        void onReady();
+    }
+
+    static void sendOnUnsyncableAccount(@NonNull Context context,
+            @NonNull RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo,
+            @UserIdInt int userId, @NonNull OnReadyCallback onReadyCallback) {
+        OnUnsyncableAccountCheck connection = new OnUnsyncableAccountCheck(syncAdapterInfo,
+                onReadyCallback);
+
+        boolean isBound = context.bindServiceAsUser(
+                getAdapterBindIntent(context, syncAdapterInfo.componentName, userId),
+                connection, SYNC_ADAPTER_CONNECTION_FLAGS, UserHandle.of(userId));
+
+        if (isBound) {
+            // Unbind after SERVICE_BOUND_TIME_MILLIS to not leak the connection.
+            (new Handler(Looper.getMainLooper())).postDelayed(
+                    () -> context.unbindService(connection),
+                    OnUnsyncableAccountCheck.SERVICE_BOUND_TIME_MILLIS);
+        } else {
+                /*
+                 * The default implementation of adapter.onUnsyncableAccount returns true. Hence if
+                 * there the service cannot be bound, assume the default behavior.
+                 */
+            connection.onReady();
+        }
+    }
+
+
+    /**
+     * Helper class for calling ISyncAdapter.onUnsyncableAccountDone.
+     *
+     * If this returns {@code true} the onReadyCallback is called. Otherwise nothing happens.
+     */
+    private static class OnUnsyncableAccountCheck implements ServiceConnection {
+        static final long SERVICE_BOUND_TIME_MILLIS = 5000;
+
+        private final @NonNull OnReadyCallback mOnReadyCallback;
+        private final @NonNull RegisteredServicesCache.ServiceInfo<SyncAdapterType>
+                mSyncAdapterInfo;
+
+        OnUnsyncableAccountCheck(
+                @NonNull RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo,
+                @NonNull OnReadyCallback onReadyCallback) {
+            mSyncAdapterInfo = syncAdapterInfo;
+            mOnReadyCallback = onReadyCallback;
+        }
+
+        private void onReady() {
+            long identity = Binder.clearCallingIdentity();
+            try {
+                mOnReadyCallback.onReady();
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            final ISyncAdapter adapter = ISyncAdapter.Stub.asInterface(service);
+
+            try {
+                adapter.onUnsyncableAccount(new ISyncAdapterUnsyncableAccountCallback.Stub() {
+                    @Override
+                    public void onUnsyncableAccountDone(boolean isReady) {
+                        if (isReady) {
+                            onReady();
+                        }
+                    }
+                });
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Could not call onUnsyncableAccountDone " + mSyncAdapterInfo, e);
+                /*
+                 * The default implementation of adapter.onUnsyncableAccount returns true. Hence if
+                 * there is a crash in the implementation, assume the default behavior.
+                 */
+                onReady();
+            }
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            // Wait until the service connects again
+        }
+    }
+
     /**
      * A helper object to keep track of the time we have spent syncing since the last boot
      */
@@ -3199,7 +3313,7 @@
                 return SYNC_OP_STATE_INVALID;
             }
             // Drop this sync request if it isn't syncable.
-            state = computeSyncable(target.account, target.userId, target.provider);
+            state = computeSyncable(target.account, target.userId, target.provider, true);
             if (state == AuthorityInfo.SYNCABLE_NO_ACCOUNT_ACCESS) {
                 if (isLoggable) {
                     Slog.v(TAG, "    Dropping sync operation: "
diff --git a/services/core/java/com/android/server/job/JobSchedulerInternal.java b/services/core/java/com/android/server/job/JobSchedulerInternal.java
index 4e74908..569e9ec 100644
--- a/services/core/java/com/android/server/job/JobSchedulerInternal.java
+++ b/services/core/java/com/android/server/job/JobSchedulerInternal.java
@@ -16,6 +16,7 @@
 
 package com.android.server.job;
 
+import android.annotation.UserIdInt;
 import android.app.job.JobInfo;
 
 import java.util.List;
@@ -39,6 +40,14 @@
     long nextHeartbeatForBucket(int bucket);
 
     /**
+     * Heartbeat ordinal for the given app.  This is typically the heartbeat at which
+     * the app last ran jobs, so that a newly-scheduled job in an app that hasn't run
+     * jobs in a long time is immediately runnable even if the app is bucketed into
+     * an infrequent time allocation.
+     */
+    public long baseHeartbeatForApp(String packageName, @UserIdInt int userId, int appBucket);
+
+    /**
      * Returns a list of pending jobs scheduled by the system service.
      */
     List<JobInfo> getSystemScheduledPendingJobs();
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 5da470e..2066f2a 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -19,6 +19,7 @@
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
 
+import android.annotation.UserIdInt;
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
@@ -39,6 +40,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.Intent.UriFlags;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
@@ -2065,6 +2067,33 @@
         }
 
         /**
+         * Heartbeat ordinal for the given app.  This is typically the heartbeat at which
+         * the app last ran jobs, so that a newly-scheduled job in an app that hasn't run
+         * jobs in a long time is immediately runnable even if the app is bucketed into
+         * an infrequent time allocation.
+         */
+        public long baseHeartbeatForApp(String packageName, @UserIdInt int userId,
+                final int appStandbyBucket) {
+            if (appStandbyBucket == 0 ||
+                    appStandbyBucket >= mConstants.STANDBY_BEATS.length) {
+                // ACTIVE => everything can be run right away
+                // NEVER => we won't run them anyway, so let them go in the future
+                // as soon as the app enters normal use
+                return 0;
+            }
+
+            final long timeSinceLastJob = mStandbyTracker.getTimeSinceLastJobRun(
+                    packageName, userId);
+            final long bucketLength = mConstants.STANDBY_BEATS[appStandbyBucket];
+            final long bucketsAgo = timeSinceLastJob / bucketLength;
+
+            // If we haven't run any jobs for more than the app's current bucket period, just
+            // consider anything new to be immediately runnable.  Otherwise, base it on the
+            // bucket at which we last ran jobs.
+            return (bucketsAgo > bucketLength) ? 0 : (getCurrentHeartbeat() - bucketsAgo);
+        }
+
+        /**
          * Returns a list of all pending jobs. A running job is not considered pending. Periodic
          * jobs are always considered pending.
          */
@@ -2139,10 +2168,14 @@
             mUsageStats = usageStats;
         }
 
+        public long getTimeSinceLastJobRun(String packageName, final @UserIdInt int userId) {
+            return mUsageStats.getTimeSinceLastJobRun(packageName, userId);
+        }
+
         // AppIdleStateChangeListener interface for live updates
 
         @Override
-        public void onAppIdleStateChanged(final String packageName, final int userId,
+        public void onAppIdleStateChanged(final String packageName, final @UserIdInt int userId,
                 boolean idle, int bucket) {
             final int uid = mLocalPM.getPackageUid(packageName,
                     PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
diff --git a/services/core/java/com/android/server/job/JobStore.java b/services/core/java/com/android/server/job/JobStore.java
index 6da783c..a24a4ac 100644
--- a/services/core/java/com/android/server/job/JobStore.java
+++ b/services/core/java/com/android/server/job/JobStore.java
@@ -1052,13 +1052,18 @@
             final ArraySet<JobStatus> jobs = mJobs.get(uid);
             final int sourceUid = job.getSourceUid();
             final ArraySet<JobStatus> jobsForSourceUid = mJobsPerSourceUid.get(sourceUid);
-            boolean didRemove = jobs != null && jobs.remove(job) && jobsForSourceUid.remove(job);
-            if (didRemove) {
-                if (jobs.size() == 0) {
-                    // no more jobs for this uid; let the now-empty set object be GC'd.
+            final boolean didRemove = jobs != null && jobs.remove(job);
+            final boolean sourceRemove = jobsForSourceUid != null && jobsForSourceUid.remove(job);
+            if (didRemove != sourceRemove) {
+                Slog.wtf(TAG, "Job presence mismatch; caller=" + didRemove
+                        + " source=" + sourceRemove);
+            }
+            if (didRemove || sourceRemove) {
+                // no more jobs for this uid?  let the now-empty set objects be GC'd.
+                if (jobs != null && jobs.size() == 0) {
                     mJobs.remove(uid);
                 }
-                if (jobsForSourceUid.size() == 0) {
+                if (jobsForSourceUid != null && jobsForSourceUid.size() == 0) {
                     mJobsPerSourceUid.remove(sourceUid);
                 }
                 return true;
diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java
index d9a5ff6..08ff7bd 100644
--- a/services/core/java/com/android/server/job/controllers/JobStatus.java
+++ b/services/core/java/com/android/server/job/controllers/JobStatus.java
@@ -414,8 +414,9 @@
         int standbyBucket = JobSchedulerService.standbyBucketForPackage(jobPackage,
                 sourceUserId, elapsedNow);
         JobSchedulerInternal js = LocalServices.getService(JobSchedulerInternal.class);
-        long currentHeartbeat = js != null ? js.currentHeartbeat() : 0;
-
+        long currentHeartbeat = js != null
+                ? js.baseHeartbeatForApp(jobPackage, sourceUserId, standbyBucket)
+                : 0;
         return new JobStatus(job, callingUid, resolveTargetSdkVersion(job), sourcePkg, sourceUserId,
                 standbyBucket, currentHeartbeat, tag, 0,
                 earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis,
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
index e1e769c..db46c3d 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
@@ -305,7 +305,7 @@
             NoSuchAlgorithmException, NoSuchPaddingException, BadPlatformKeyException,
             InvalidKeyException, InvalidAlgorithmParameterException {
         PlatformKeyManager platformKeyManager = mPlatformKeyManagerFactory.newInstance();
-        PlatformDecryptionKey decryptKey = platformKeyManager.getDecryptKey(mUserId);
+        PlatformDecryptionKey decryptKey = platformKeyManager.getDecryptKey(mUserId);;
         Map<String, WrappedKey> wrappedKeys = mRecoverableKeyStoreDb.getAllKeys(
                 mUserId, recoveryAgentUid, decryptKey.getGenerationId());
         return WrappedKey.unwrapKeys(decryptKey, wrappedKeys);
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java
index 7005de5..ee6a893 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java
@@ -131,6 +131,7 @@
     /**
      * Generates a new key and increments the generation ID. Should be invoked if the platform key
      * is corrupted and needs to be rotated.
+     * Updates status of old keys to {@code RecoveryController.RECOVERY_STATUS_PERMANENT_FAILURE}.
      *
      * @param userId The ID of the user to whose lock screen the platform key must be bound.
      * @throws NoSuchAlgorithmException if AES is unavailable - should never happen.
@@ -158,6 +159,7 @@
 
     /**
      * Returns the platform key used for encryption.
+     * Tries to regenerate key one time if it is permanently invalid.
      *
      * @param userId The ID of the user to whose lock screen the platform key must be bound.
      * @throws KeyStoreException if there was an AndroidKeyStore error.
@@ -170,6 +172,30 @@
     public PlatformEncryptionKey getEncryptKey(int userId) throws KeyStoreException,
            UnrecoverableKeyException, NoSuchAlgorithmException, InsecureUserException {
         init(userId);
+        try {
+            return getEncryptKeyInternal(userId);
+        } catch (UnrecoverableKeyException e) {
+            Log.i(TAG, String.format(Locale.US,
+                    "Regenerating permanently invalid Platform key for user %d.",
+                    userId));
+            regenerate(userId);
+            return getEncryptKeyInternal(userId);
+        }
+    }
+
+    /**
+     * Returns the platform key used for encryption.
+     *
+     * @param userId The ID of the user to whose lock screen the platform key must be bound.
+     * @throws KeyStoreException if there was an AndroidKeyStore error.
+     * @throws UnrecoverableKeyException if the key could not be recovered.
+     * @throws NoSuchAlgorithmException if AES is unavailable - should never occur.
+     * @throws InsecureUserException if the user does not have a lock screen set.
+     *
+     * @hide
+     */
+    private PlatformEncryptionKey getEncryptKeyInternal(int userId) throws KeyStoreException,
+           UnrecoverableKeyException, NoSuchAlgorithmException, InsecureUserException {
         int generationId = getGenerationId(userId);
         AndroidKeyStoreSecretKey key = (AndroidKeyStoreSecretKey) mKeyStore.getKey(
                 getEncryptAlias(userId, generationId), /*password=*/ null);
@@ -178,6 +204,32 @@
 
     /**
      * Returns the platform key used for decryption. Only works after a recent screen unlock.
+     * Tries to regenerate key one time if it is permanently invalid.
+     *
+     * @param userId The ID of the user to whose lock screen the platform key must be bound.
+     * @throws KeyStoreException if there was an AndroidKeyStore error.
+     * @throws UnrecoverableKeyException if the key could not be recovered.
+     * @throws NoSuchAlgorithmException if AES is unavailable - should never occur.
+     * @throws InsecureUserException if the user does not have a lock screen set.
+     *
+     * @hide
+     */
+    public PlatformDecryptionKey getDecryptKey(int userId) throws KeyStoreException,
+           UnrecoverableKeyException, NoSuchAlgorithmException, InsecureUserException {
+        init(userId);
+        try {
+            return getDecryptKeyInternal(userId);
+        } catch (UnrecoverableKeyException e) {
+            Log.i(TAG, String.format(Locale.US,
+                    "Regenerating permanently invalid Platform key for user %d.",
+                    userId));
+            regenerate(userId);
+            return getDecryptKeyInternal(userId);
+        }
+    }
+
+    /**
+     * Returns the platform key used for decryption. Only works after a recent screen unlock.
      *
      * @param userId The ID of the user to whose lock screen the platform key must be bound.
      * @throws KeyStoreException if there was an AndroidKeyStore error.
@@ -187,9 +239,8 @@
      *
      * @hide
      */
-    public PlatformDecryptionKey getDecryptKey(int userId) throws KeyStoreException,
+    private PlatformDecryptionKey getDecryptKeyInternal(int userId) throws KeyStoreException,
            UnrecoverableKeyException, NoSuchAlgorithmException, InsecureUserException {
-        init(userId);
         int generationId = getGenerationId(userId);
         AndroidKeyStoreSecretKey key = (AndroidKeyStoreSecretKey) mKeyStore.getKey(
                 getDecryptAlias(userId, generationId), /*password=*/ null);
@@ -294,13 +345,7 @@
         String decryptAlias = getDecryptAlias(userId, generationId);
         SecretKey secretKey = generateAesKey();
 
-        mKeyStore.setEntry(
-                encryptAlias,
-                new KeyStore.SecretKeyEntry(secretKey),
-                new KeyProtection.Builder(KeyProperties.PURPOSE_ENCRYPT)
-                    .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
-                    .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
-                    .build());
+        // Store Since decryption key first since it is more likely to fail.
         mKeyStore.setEntry(
                 decryptAlias,
                 new KeyStore.SecretKeyEntry(secretKey),
@@ -313,6 +358,14 @@
                     .setBoundToSpecificSecureUserId(userId)
                     .build());
 
+        mKeyStore.setEntry(
+                encryptAlias,
+                new KeyStore.SecretKeyEntry(secretKey),
+                new KeyProtection.Builder(KeyProperties.PURPOSE_ENCRYPT)
+                    .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
+                    .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
+                    .build());
+
         setGenerationId(userId, generationId);
 
         try {
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java
index f2e71b3..b96208d 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDb.java
@@ -22,6 +22,7 @@
 import android.content.Context;
 import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabase;
+import android.security.keystore.recovery.RecoveryController;
 import android.text.TextUtils;
 import android.util.Log;
 
@@ -289,8 +290,27 @@
         ContentValues values = new ContentValues();
         values.put(UserMetadataEntry.COLUMN_NAME_USER_ID, userId);
         values.put(UserMetadataEntry.COLUMN_NAME_PLATFORM_KEY_GENERATION_ID, generationId);
-        return db.replace(
+        long result = db.replace(
                 UserMetadataEntry.TABLE_NAME, /*nullColumnHack=*/ null, values);
+        if (result != -1) {
+            invalidateKeysWithOldGenerationId(userId, generationId);
+        }
+        return result;
+    }
+
+    /**
+     * Updates status of old keys to {@code RecoveryController.RECOVERY_STATUS_PERMANENT_FAILURE}.
+     */
+    public void invalidateKeysWithOldGenerationId(int userId, int newGenerationId) {
+        SQLiteDatabase db = mKeyStoreDbHelper.getWritableDatabase();
+        ContentValues values = new ContentValues();
+        values.put(KeysEntry.COLUMN_NAME_RECOVERY_STATUS,
+                RecoveryController.RECOVERY_STATUS_PERMANENT_FAILURE);
+        String selection =
+                KeysEntry.COLUMN_NAME_USER_ID + " = ? AND "
+                + KeysEntry.COLUMN_NAME_GENERATION_ID + " < ?";
+        db.update(KeysEntry.TABLE_NAME, values, selection,
+            new String[] {String.valueOf(userId), String.valueOf(newGenerationId)});
     }
 
     /**
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index 5bf38dc..10e05cf 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -362,9 +362,10 @@
                 continue;
             }
 
-            // If the path is in /system or /vendor, ignore. It will have been ota-dexopted into
-            // /data/ota and moved into the dalvik-cache already.
-            if (pkg.codePath.startsWith("/system") || pkg.codePath.startsWith("/vendor")) {
+            // If the path is in /system, /vendor or /product, ignore. It will have been
+            // ota-dexopted into /data/ota and moved into the dalvik-cache already.
+            if (pkg.codePath.startsWith("/system") || pkg.codePath.startsWith("/vendor")
+                    || pkg.codePath.startsWith("/product")) {
                 continue;
             }
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 837a118..7767945 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -466,6 +466,7 @@
     static final int SCAN_AS_PRIVILEGED = 1<<18;
     static final int SCAN_AS_OEM = 1<<19;
     static final int SCAN_AS_VENDOR = 1<<20;
+    static final int SCAN_AS_PRODUCT = 1<<21;
 
     @IntDef(flag = true, prefix = { "SCAN_" }, value = {
             SCAN_NO_DEX,
@@ -570,6 +571,8 @@
 
     private static final String VENDOR_OVERLAY_DIR = "/vendor/overlay";
 
+    private static final String PRODUCT_OVERLAY_DIR = "/product/overlay";
+
     private static final String PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB = "pm.dexopt.priv-apps-oob";
 
     /** Canonical intent used to identify what counts as a "web browser" app */
@@ -2552,7 +2555,7 @@
                 scanFlags = scanFlags | SCAN_FIRST_BOOT_OR_UPGRADE;
             }
 
-            // Collect vendor overlay packages. (Do this before scanning any apps.)
+            // Collect vendor/product overlay packages. (Do this before scanning any apps.)
             // For security and version matching reason, only consider
             // overlay packages if they reside in the right directory.
             scanDirTracedLI(new File(VENDOR_OVERLAY_DIR),
@@ -2562,6 +2565,13 @@
                     | SCAN_AS_SYSTEM
                     | SCAN_AS_VENDOR,
                     0);
+            scanDirTracedLI(new File(PRODUCT_OVERLAY_DIR),
+                    mDefParseFlags
+                    | PackageParser.PARSE_IS_SYSTEM_DIR,
+                    scanFlags
+                    | SCAN_AS_SYSTEM
+                    | SCAN_AS_PRODUCT,
+                    0);
 
             mParallelPackageParserCallback.findStaticOverlayPackages();
 
@@ -2595,8 +2605,7 @@
                     0);
 
             // Collected privileged vendor packages.
-                File privilegedVendorAppDir = new File(Environment.getVendorDirectory(),
-                        "priv-app");
+            File privilegedVendorAppDir = new File(Environment.getVendorDirectory(), "priv-app");
             try {
                 privilegedVendorAppDir = privilegedVendorAppDir.getCanonicalFile();
             } catch (IOException e) {
@@ -2636,6 +2645,37 @@
                     | SCAN_AS_OEM,
                     0);
 
+            // Collected privileged product packages.
+            File privilegedProductAppDir = new File(Environment.getProductDirectory(), "priv-app");
+            try {
+                privilegedProductAppDir = privilegedProductAppDir.getCanonicalFile();
+            } catch (IOException e) {
+                // failed to look up canonical path, continue with original one
+            }
+            scanDirTracedLI(privilegedProductAppDir,
+                    mDefParseFlags
+                    | PackageParser.PARSE_IS_SYSTEM_DIR,
+                    scanFlags
+                    | SCAN_AS_SYSTEM
+                    | SCAN_AS_PRODUCT
+                    | SCAN_AS_PRIVILEGED,
+                    0);
+
+            // Collect ordinary product packages.
+            File productAppDir = new File(Environment.getProductDirectory(), "app");
+            try {
+                productAppDir = productAppDir.getCanonicalFile();
+            } catch (IOException e) {
+                // failed to look up canonical path, continue with original one
+            }
+            scanDirTracedLI(productAppDir,
+                    mDefParseFlags
+                    | PackageParser.PARSE_IS_SYSTEM_DIR,
+                    scanFlags
+                    | SCAN_AS_SYSTEM
+                    | SCAN_AS_PRODUCT,
+                    0);
+
             // Prune any system packages that no longer exist.
             final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<>();
             // Stub packages must either be replaced with full versions in the /data
@@ -2842,6 +2882,23 @@
                                     scanFlags
                                     | SCAN_AS_SYSTEM
                                     | SCAN_AS_OEM;
+                        } else if (FileUtils.contains(privilegedProductAppDir, scanFile)) {
+                            reparseFlags =
+                                    mDefParseFlags |
+                                    PackageParser.PARSE_IS_SYSTEM_DIR;
+                            rescanFlags =
+                                    scanFlags
+                                    | SCAN_AS_SYSTEM
+                                    | SCAN_AS_PRODUCT
+                                    | SCAN_AS_PRIVILEGED;
+                        } else if (FileUtils.contains(productAppDir, scanFile)) {
+                            reparseFlags =
+                                    mDefParseFlags |
+                                    PackageParser.PARSE_IS_SYSTEM_DIR;
+                            rescanFlags =
+                                    scanFlags
+                                    | SCAN_AS_SYSTEM
+                                    | SCAN_AS_PRODUCT;
                         } else {
                             Slog.e(TAG, "Ignoring unexpected fallback path " + scanFile);
                             continue;
@@ -9862,6 +9919,7 @@
      * <li>{@link #SCAN_AS_PRIVILEGED}</li>
      * <li>{@link #SCAN_AS_OEM}</li>
      * <li>{@link #SCAN_AS_VENDOR}</li>
+     * <li>{@link #SCAN_AS_PRODUCT}</li>
      * <li>{@link #SCAN_AS_INSTANT_APP}</li>
      * <li>{@link #SCAN_AS_VIRTUAL_PRELOAD}</li>
      * </ul>
@@ -9884,6 +9942,10 @@
                     & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0) {
                 scanFlags |= SCAN_AS_VENDOR;
             }
+            if ((disabledPkgSetting.pkgPrivateFlags
+                    & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0) {
+                scanFlags |= SCAN_AS_PRODUCT;
+            }
         }
         if (pkgSetting != null) {
             final int userId = ((user == null) ? 0 : user.getIdentifier());
@@ -10662,6 +10724,10 @@
             pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_VENDOR;
         }
 
+        if ((scanFlags & SCAN_AS_PRODUCT) != 0) {
+            pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRODUCT;
+        }
+
         if (!isSystemApp(pkg)) {
             // Only system apps can use these features.
             pkg.mOriginalPackages = null;
@@ -11708,6 +11774,8 @@
             codeRoot = Environment.getOemDirectory();
         } else if (FileUtils.contains(Environment.getVendorDirectory(), codePath)) {
             codeRoot = Environment.getVendorDirectory();
+        } else if (FileUtils.contains(Environment.getProductDirectory(), codePath)) {
+            codeRoot = Environment.getProductDirectory();
         } else {
             // Unrecognized code path; take its top real segment as the apk root:
             // e.g. /something/app/blah.apk => /something
@@ -16110,7 +16178,7 @@
 
         boolean sysPkg = (isSystemApp(oldPackage));
         if (sysPkg) {
-            // Set the system/privileged/oem/vendor flags as needed
+            // Set the system/privileged/oem/vendor/product flags as needed
             final boolean privileged =
                     (oldPackage.applicationInfo.privateFlags
                             & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
@@ -16120,12 +16188,16 @@
             final boolean vendor =
                     (oldPackage.applicationInfo.privateFlags
                             & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0;
+            final boolean product =
+                    (oldPackage.applicationInfo.privateFlags
+                            & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0;
             final @ParseFlags int systemParseFlags = parseFlags;
             final @ScanFlags int systemScanFlags = scanFlags
                     | SCAN_AS_SYSTEM
                     | (privileged ? SCAN_AS_PRIVILEGED : 0)
                     | (oem ? SCAN_AS_OEM : 0)
-                    | (vendor ? SCAN_AS_VENDOR : 0);
+                    | (vendor ? SCAN_AS_VENDOR : 0)
+                    | (product ? SCAN_AS_PRODUCT : 0);
 
             replaceSystemPackageLIF(oldPackage, pkg, systemParseFlags, systemScanFlags,
                     user, allUsers, installerPackageName, res, installReason);
@@ -17373,6 +17445,10 @@
         return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0;
     }
 
+    private static boolean isProductApp(PackageParser.Package pkg) {
+        return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0;
+    }
+
     private static boolean hasDomainURLs(PackageParser.Package pkg) {
         return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS) != 0;
     }
@@ -18112,8 +18188,10 @@
         try {
             final File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app");
             final File privilegedVendorAppDir = new File(Environment.getVendorDirectory(), "priv-app");
+            final File privilegedProductAppDir = new File(Environment.getProductDirectory(), "priv-app");
             return path.startsWith(privilegedAppDir.getCanonicalPath())
-                    || path.startsWith(privilegedVendorAppDir.getCanonicalPath());
+                    || path.startsWith(privilegedVendorAppDir.getCanonicalPath())
+                    || path.startsWith(privilegedProductAppDir.getCanonicalPath());
         } catch (IOException e) {
             Slog.e(TAG, "Unable to access code path " + path);
         }
@@ -18138,6 +18216,15 @@
         return false;
     }
 
+    static boolean locationIsProduct(String path) {
+        try {
+            return path.startsWith(Environment.getProductDirectory().getCanonicalPath());
+        } catch (IOException e) {
+            Slog.e(TAG, "Unable to access code path " + path);
+        }
+        return false;
+    }
+
     /*
      * Tries to delete system package.
      */
@@ -18262,6 +18349,9 @@
         if (locationIsVendor(codePathString)) {
             scanFlags |= SCAN_AS_VENDOR;
         }
+        if (locationIsProduct(codePathString)) {
+            scanFlags |= SCAN_AS_PRODUCT;
+        }
 
         final File codePath = new File(codePathString);
         final PackageParser.Package pkg =
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 47cd813..686c4a5 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -1555,6 +1555,15 @@
         }
     }
 
+    private boolean isProductApp(String pkg) {
+        try {
+            final PackageInfo info = mInterface.getPackageInfo(pkg, 0, UserHandle.USER_SYSTEM);
+            return info != null && info.applicationInfo.isProduct();
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+
     private int runGetPrivappPermissions() {
         final String pkg = getNextArg();
         if (pkg == null) {
@@ -1562,9 +1571,14 @@
             return 1;
         }
 
-        ArraySet<String> privAppPermissions = isVendorApp(pkg) ?
-                SystemConfig.getInstance().getVendorPrivAppPermissions(pkg)
-                    : SystemConfig.getInstance().getPrivAppPermissions(pkg);
+        ArraySet<String> privAppPermissions = null;
+        if (isVendorApp(pkg)) {
+            privAppPermissions = SystemConfig.getInstance().getVendorPrivAppPermissions(pkg);
+        } else if (isProductApp(pkg)) {
+            privAppPermissions = SystemConfig.getInstance().getProductPrivAppPermissions(pkg);
+        } else {
+            privAppPermissions = SystemConfig.getInstance().getPrivAppPermissions(pkg);
+        }
 
         getOutPrintWriter().println(privAppPermissions == null
                 ? "{}" : privAppPermissions.toString());
@@ -1578,9 +1592,14 @@
             return 1;
         }
 
-        ArraySet<String> privAppPermissions = isVendorApp(pkg) ?
-                SystemConfig.getInstance().getVendorPrivAppDenyPermissions(pkg)
-                    : SystemConfig.getInstance().getPrivAppDenyPermissions(pkg);
+        ArraySet<String> privAppPermissions = null;
+        if (isVendorApp(pkg)) {
+            privAppPermissions = SystemConfig.getInstance().getVendorPrivAppDenyPermissions(pkg);
+        } else if (isProductApp(pkg)) {
+            privAppPermissions = SystemConfig.getInstance().getProductPrivAppDenyPermissions(pkg);
+        } else {
+            privAppPermissions = SystemConfig.getInstance().getPrivAppDenyPermissions(pkg);
+        }
 
         getOutPrintWriter().println(privAppPermissions == null
                 ? "{}" : privAppPermissions.toString());
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 2a2430c..3e2bd4a 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -173,6 +173,10 @@
         return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0;
     }
 
+    public boolean isProduct() {
+        return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0;
+    }
+
     public boolean isForwardLocked() {
         return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0;
     }
diff --git a/services/core/java/com/android/server/pm/SettingBase.java b/services/core/java/com/android/server/pm/SettingBase.java
index 46ba006..7c92045 100644
--- a/services/core/java/com/android/server/pm/SettingBase.java
+++ b/services/core/java/com/android/server/pm/SettingBase.java
@@ -62,6 +62,7 @@
                 & (ApplicationInfo.PRIVATE_FLAG_PRIVILEGED
                 | ApplicationInfo.PRIVATE_FLAG_OEM
                 | ApplicationInfo.PRIVATE_FLAG_VENDOR
+                | ApplicationInfo.PRIVATE_FLAG_PRODUCT
                 | ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK
                 | ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER);
     }
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 8ce412e..5e9019d 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -851,6 +851,8 @@
                 pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_OEM;
         pkgSetting.pkgPrivateFlags |=
                 pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR;
+        pkgSetting.pkgPrivateFlags |=
+                pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT;
         pkgSetting.primaryCpuAbiString = primaryCpuAbi;
         pkgSetting.secondaryCpuAbiString = secondaryCpuAbi;
         if (childPkgNames != null) {
@@ -4397,6 +4399,7 @@
             ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER, "REQUIRED_FOR_SYSTEM_USER",
             ApplicationInfo.PRIVATE_FLAG_STATIC_SHARED_LIBRARY, "STATIC_SHARED_LIBRARY",
             ApplicationInfo.PRIVATE_FLAG_VENDOR, "VENDOR",
+            ApplicationInfo.PRIVATE_FLAG_PRODUCT, "PRODUCT",
             ApplicationInfo.PRIVATE_FLAG_VIRTUAL_PRELOAD, "VIRTUAL_PRELOAD",
     };
 
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 6e07eaa..e2123c2 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -1215,6 +1215,10 @@
         if (dir.isDirectory() && dir.canRead()) {
             Collections.addAll(ret, dir.listFiles());
         }
+        dir = new File(Environment.getProductDirectory(), "etc/default-permissions");
+        if (dir.isDirectory() && dir.canRead()) {
+            Collections.addAll(ret, dir.listFiles());
+        }
         return ret.isEmpty() ? null : ret.toArray(new File[0]);
     }
 
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 786b998..cb3b107 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -954,9 +954,16 @@
      * <p>This handles parent/child apps.
      */
     private boolean hasPrivappWhitelistEntry(String perm, PackageParser.Package pkg) {
-        ArraySet<String> wlPermissions = pkg.isVendor() ?
-                SystemConfig.getInstance().getVendorPrivAppPermissions(pkg.packageName)
-                    : SystemConfig.getInstance().getPrivAppPermissions(pkg.packageName);
+        ArraySet<String> wlPermissions = null;
+        if (pkg.isVendor()) {
+            wlPermissions =
+                    SystemConfig.getInstance().getVendorPrivAppPermissions(pkg.packageName);
+        } else if (pkg.isProduct()) {
+            wlPermissions =
+                    SystemConfig.getInstance().getProductPrivAppPermissions(pkg.packageName);
+        } else {
+            wlPermissions = SystemConfig.getInstance().getPrivAppPermissions(pkg.packageName);
+        }
         // Let's check if this package is whitelisted...
         boolean whitelisted = wlPermissions != null && wlPermissions.contains(perm);
         // If it's not, we'll also tail-recurse to the parent.
@@ -979,11 +986,17 @@
                 // Only report violations for apps on system image
                 if (!mSystemReady && !pkg.isUpdatedSystemApp()) {
                     // it's only a reportable violation if the permission isn't explicitly denied
-                    final ArraySet<String> deniedPermissions = pkg.isVendor() ?
-                            SystemConfig.getInstance()
-                                    .getVendorPrivAppDenyPermissions(pkg.packageName)
-                            : SystemConfig.getInstance()
-                                    .getPrivAppDenyPermissions(pkg.packageName);
+                    ArraySet<String> deniedPermissions = null;
+                    if (pkg.isVendor()) {
+                        deniedPermissions = SystemConfig.getInstance()
+                                .getVendorPrivAppDenyPermissions(pkg.packageName);
+                    } else if (pkg.isProduct()) {
+                        deniedPermissions = SystemConfig.getInstance()
+                                .getProductPrivAppDenyPermissions(pkg.packageName);
+                    } else {
+                        deniedPermissions = SystemConfig.getInstance()
+                                .getPrivAppDenyPermissions(pkg.packageName);
+                    }
                     final boolean permissionViolation =
                             deniedPermissions == null || !deniedPermissions.contains(perm);
                     if (permissionViolation) {
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index cf36166..db83158 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -3763,12 +3763,8 @@
                 proto.write(PowerManagerServiceDumpProto.UidStateProto.UID_STRING, UserHandle.formatUid(uid));
                 proto.write(PowerManagerServiceDumpProto.UidStateProto.IS_ACTIVE, state.mActive);
                 proto.write(PowerManagerServiceDumpProto.UidStateProto.NUM_WAKE_LOCKS, state.mNumWakeLocks);
-                if (state.mProcState == ActivityManager.PROCESS_STATE_UNKNOWN) {
-                    proto.write(PowerManagerServiceDumpProto.UidStateProto.IS_PROCESS_STATE_UNKNOWN, true);
-                } else {
-                    proto.write(PowerManagerServiceDumpProto.UidStateProto.PROCESS_STATE,
-                            ActivityManager.processStateAmToProto(state.mProcState));
-                }
+                proto.write(PowerManagerServiceDumpProto.UidStateProto.PROCESS_STATE,
+                        ActivityManager.processStateAmToProto(state.mProcState));
                 proto.end(uIDToken);
             }
 
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index faafb39..cfdec4c 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -648,7 +648,7 @@
                     SynchronousResultReceiver modemReceiver = new SynchronousResultReceiver("telephony");
                     mTelephony.requestModemActivityInfo(modemReceiver);
                     final ModemActivityInfo modemInfo = awaitControllerInfo(modemReceiver);
-                    StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 6);
+                    StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 10);
                     e.writeLong(modemInfo.getTimestamp());
                     e.writeLong(modemInfo.getSleepTimeMillis());
                     e.writeLong(modemInfo.getIdleTimeMillis());
@@ -706,7 +706,8 @@
         enforceCallingPermission();
         if (DEBUG) Slog.d(TAG, "learned that statsdReady");
         sayHiToStatsd(); // tell statsd that we're ready too and link to it
-        mContext.sendBroadcast(new Intent(StatsManager.ACTION_STATSD_STARTED),
+        mContext.sendBroadcastAsUser(new Intent(StatsManager.ACTION_STATSD_STARTED),
+                UserHandle.SYSTEM,
                 android.Manifest.permission.DUMP);
     }
 
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdater.java b/services/core/java/com/android/server/webkit/WebViewUpdater.java
index 7e05e46..61a3c09 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdater.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdater.java
@@ -507,22 +507,16 @@
         if (systemInterface.systemIsDebuggable()) {
             return true;
         }
-        Signature[] packageSignatures;
         // If no signature is declared, instead check whether the package is included in the
         // system.
         if (provider.signatures == null || provider.signatures.length == 0) {
             return packageInfo.applicationInfo.isSystemApp();
         }
-        packageSignatures = packageInfo.signatures;
-        if (packageSignatures.length != 1)
-            return false;
+        if (packageInfo.signatures.length != 1) return false;
 
-        final byte[] packageSignature = packageSignatures[0].toByteArray();
         // Return whether the package signature matches any of the valid signatures
-        for (String signature : provider.signatures) {
-            final byte[] validSignature = Base64.decode(signature, Base64.DEFAULT);
-            if (Arrays.equals(packageSignature, validSignature))
-                return true;
+        for (Signature signature : provider.signatures) {
+            if (signature.equals(packageInfo.signatures[0])) return true;
         }
         return false;
     }
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 6dc384a..3f49f0c 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1508,6 +1508,10 @@
         return mTaskStackContainers.getTopStack();
     }
 
+    ArrayList<Task> getVisibleTasks() {
+        return mTaskStackContainers.getVisibleTasks();
+    }
+
     void onStackWindowingModeChanged(TaskStack stack) {
         mTaskStackContainers.onStackWindowingModeChanged(stack);
     }
@@ -1802,6 +1806,11 @@
         getParent().positionChildAt(position, this, includingParents);
     }
 
+    void positionStackAt(int position, TaskStack child) {
+        mTaskStackContainers.positionChildAt(position, child, false /* includingParents */);
+        layoutAndAssignWindowLayersIfNeeded();
+    }
+
     int taskIdFromPoint(int x, int y) {
         for (int stackNdx = mTaskStackContainers.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
             final TaskStack stack = mTaskStackContainers.getChildAt(stackNdx);
@@ -3255,6 +3264,16 @@
             return mSplitScreenPrimaryStack;
         }
 
+        ArrayList<Task> getVisibleTasks() {
+            final ArrayList<Task> visibleTasks = new ArrayList<>();
+            forAllTasks(task -> {
+                if (task.isVisible()) {
+                    visibleTasks.add(task);
+                }
+            });
+            return visibleTasks;
+        }
+
         /**
          * Adds the stack to this container.
          * @see DisplayContent#createStack(int, boolean, StackWindowController)
diff --git a/services/core/java/com/android/server/wm/DisplayWindowController.java b/services/core/java/com/android/server/wm/DisplayWindowController.java
new file mode 100644
index 0000000..ad4957e
--- /dev/null
+++ b/services/core/java/com/android/server/wm/DisplayWindowController.java
@@ -0,0 +1,85 @@
+/*
+ * 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.wm;
+
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+
+import android.content.res.Configuration;
+import android.util.Slog;
+
+/**
+ * Controller for the display container. This is created by activity manager to link activity
+ * displays to the display content they use in window manager.
+ */
+public class DisplayWindowController
+        extends WindowContainerController<DisplayContent, WindowContainerListener> {
+
+    private final int mDisplayId;
+
+    public DisplayWindowController(int displayId, WindowContainerListener listener) {
+        super(listener, WindowManagerService.getInstance());
+        mDisplayId = displayId;
+
+        synchronized (mWindowMap) {
+            // TODO: Convert to setContainer() from DisplayContent once everything is hooked up.
+            // Currently we are not setup to register for config changes.
+            mContainer = mRoot.getDisplayContentOrCreate(displayId);
+            if (mContainer == null) {
+                throw new IllegalArgumentException("Trying to add displayId=" + displayId);
+            }
+        }
+    }
+
+    @Override
+    public void removeContainer() {
+        // TODO: Pipe through from ActivityDisplay to remove the display
+        throw new UnsupportedOperationException("To be implemented");
+    }
+
+    @Override
+    public void onOverrideConfigurationChanged(Configuration overrideConfiguration) {
+        // TODO: Pipe through from ActivityDisplay to update the configuration for the display
+        throw new UnsupportedOperationException("To be implemented");
+    }
+
+    /**
+     * Positions the task stack at the given position in the task stack container.
+     */
+    public void positionChildAt(StackWindowController child, int position) {
+        synchronized (mWindowMap) {
+            if (DEBUG_STACK) Slog.i(TAG_WM, "positionTaskStackAt: positioning stack=" + child
+                    + " at " + position);
+            if (mContainer == null) {
+                if (DEBUG_STACK) Slog.i(TAG_WM,
+                        "positionTaskStackAt: could not find display=" + mContainer);
+                return;
+            }
+            if (child.mContainer == null) {
+                if (DEBUG_STACK) Slog.i(TAG_WM,
+                        "positionTaskStackAt: could not find stack=" + this);
+                return;
+            }
+            mContainer.positionStackAt(position, child.mContainer);
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "{DisplayWindowController displayId=" + mDisplayId + "}";
+    }
+}
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 88b7a11..281e0a844 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -19,6 +19,7 @@
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowManager.INPUT_CONSUMER_NAVIGATION;
 import static android.view.WindowManager.INPUT_CONSUMER_PIP;
+import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION;
 import static android.view.WindowManager.INPUT_CONSUMER_WALLPAPER;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_DISABLE_WALLPAPER_TOUCH_EVENTS;
@@ -86,6 +87,7 @@
     private boolean mAddInputConsumerHandle;
     private boolean mAddPipInputConsumerHandle;
     private boolean mAddWallpaperInputConsumerHandle;
+    private boolean mAddRecentsAnimationInputConsumerHandle;
     private boolean mDisableWallpaperTouchEvents;
     private final Rect mTmpRect = new Rect();
     private final UpdateInputForAllWindowsConsumer mUpdateInputForAllWindowsConsumer =
@@ -612,7 +614,7 @@
         InputConsumerImpl navInputConsumer;
         InputConsumerImpl pipInputConsumer;
         InputConsumerImpl wallpaperInputConsumer;
-        Rect pipTouchableBounds;
+        InputConsumerImpl recentsAnimationInputConsumer;
         boolean inDrag;
         WallpaperController wallpaperController;
 
@@ -622,11 +624,13 @@
             navInputConsumer = getInputConsumer(INPUT_CONSUMER_NAVIGATION, DEFAULT_DISPLAY);
             pipInputConsumer = getInputConsumer(INPUT_CONSUMER_PIP, DEFAULT_DISPLAY);
             wallpaperInputConsumer = getInputConsumer(INPUT_CONSUMER_WALLPAPER, DEFAULT_DISPLAY);
+            recentsAnimationInputConsumer = getInputConsumer(INPUT_CONSUMER_RECENTS_ANIMATION,
+                    DEFAULT_DISPLAY);
             mAddInputConsumerHandle = navInputConsumer != null;
             mAddPipInputConsumerHandle = pipInputConsumer != null;
             mAddWallpaperInputConsumerHandle = wallpaperInputConsumer != null;
+            mAddRecentsAnimationInputConsumerHandle = recentsAnimationInputConsumer != null;
             mTmpRect.setEmpty();
-            pipTouchableBounds = mAddPipInputConsumerHandle ? mTmpRect : null;
             mDisableWallpaperTouchEvents = false;
             this.inDrag = inDrag;
             wallpaperController = mService.mRoot.mWallpaperController;
@@ -659,12 +663,28 @@
             final boolean hasFocus = w == mInputFocus;
             final boolean isVisible = w.isVisibleLw();
 
+            if (mAddRecentsAnimationInputConsumerHandle) {
+                final RecentsAnimationController recentsAnimationController =
+                        mService.getRecentsAnimationController();
+                if (recentsAnimationController != null
+                        && recentsAnimationController.hasInputConsumerForApp(w.mAppToken)) {
+                    if (recentsAnimationController.updateInputConsumerForApp(
+                            recentsAnimationInputConsumer, hasFocus)) {
+                        addInputWindowHandle(recentsAnimationInputConsumer.mWindowHandle);
+                        mAddRecentsAnimationInputConsumerHandle = false;
+                    }
+                    // Skip adding the window below regardless of whether there is an input consumer
+                    // to handle it
+                    return;
+                }
+            }
+
             if (w.inPinnedWindowingMode()) {
                 if (mAddPipInputConsumerHandle
                         && (inputWindowHandle.layer <= pipInputConsumer.mWindowHandle.layer)) {
                     // Update the bounds of the Pip input consumer to match the window bounds.
-                    w.getBounds(pipTouchableBounds);
-                    pipInputConsumer.mWindowHandle.touchableRegion.set(pipTouchableBounds);
+                    w.getBounds(mTmpRect);
+                    pipInputConsumer.mWindowHandle.touchableRegion.set(mTmpRect);
                     addInputWindowHandle(pipInputConsumer.mWindowHandle);
                     mAddPipInputConsumerHandle = false;
                 }
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
new file mode 100644
index 0000000..c7d4b8e
--- /dev/null
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -0,0 +1,385 @@
+/*
+ * 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.server.wm;
+
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.view.RemoteAnimationTarget.MODE_CLOSING;
+import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION;
+import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+
+import android.app.ActivityManager;
+import android.app.ActivityManager.TaskSnapshot;
+import android.app.WindowConfiguration;
+import android.graphics.GraphicBuffer;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.os.Binder;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.util.Log;
+import android.util.Slog;
+import android.view.IRecentsAnimationController;
+import android.view.IRecentsAnimationRunner;
+import android.view.RemoteAnimationTarget;
+import android.view.SurfaceControl;
+import android.view.SurfaceControl.Transaction;
+import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+
+/**
+ * Controls a single instance of the remote driven recents animation. In particular, this allows
+ * the calling SystemUI to animate the visible task windows as a part of the transition. The remote
+ * runner is provided an animation controller which allows it to take screenshots and to notify
+ * window manager when the animation is completed. In addition, window manager may also notify the
+ * app if it requires the animation to be canceled at any time (ie. due to timeout, etc.)
+ */
+public class RecentsAnimationController {
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "RecentsAnimationController" : TAG_WM;
+    private static final boolean DEBUG = false;
+
+    private final WindowManagerService mService;
+    private final IRecentsAnimationRunner mRunner;
+    private final RecentsAnimationCallbacks mCallbacks;
+    private final ArrayList<TaskAnimationAdapter> mPendingAnimations = new ArrayList<>();
+
+    // The recents component app token that is shown behind the visibile tasks
+    private AppWindowToken mHomeAppToken;
+
+    // We start the RecentsAnimationController in a pending-start state since we need to wait for
+    // the wallpaper/activity to draw before we can give control to the handler to start animating
+    // the visible task surfaces
+    private boolean mPendingStart = true;
+
+    // Set when the animation has been canceled
+    private boolean mCanceled = false;
+
+    // Whether or not the input consumer is enabled. The input consumer must be both registered and
+    // enabled for it to start intercepting touch events.
+    private boolean mInputConsumerEnabled;
+
+    private Rect mTmpRect = new Rect();
+
+    public interface RecentsAnimationCallbacks {
+        void onAnimationFinished(boolean moveHomeToTop);
+    }
+
+    private final IRecentsAnimationController mController =
+            new IRecentsAnimationController.Stub() {
+
+        @Override
+        public TaskSnapshot screenshotTask(int taskId) {
+            if (DEBUG) Log.d(TAG, "screenshotTask(" + taskId + "): mCanceled=" + mCanceled);
+            long token = Binder.clearCallingIdentity();
+            try {
+                synchronized (mService.getWindowManagerLock()) {
+                    if (mCanceled) {
+                        return null;
+                    }
+                    for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
+                        final TaskAnimationAdapter adapter = mPendingAnimations.get(i);
+                        final Task task = adapter.mTask;
+                        if (task.mTaskId == taskId) {
+                            // TODO: Save this screenshot as the task snapshot?
+                            final Rect taskFrame = new Rect();
+                            task.getBounds(taskFrame);
+                            final GraphicBuffer buffer = SurfaceControl.captureLayers(
+                                    task.getSurfaceControl().getHandle(), taskFrame, 1f);
+                            final AppWindowToken topChild = task.getTopChild();
+                            final WindowState mainWindow = topChild.findMainWindow();
+                            return new TaskSnapshot(buffer, topChild.getConfiguration().orientation,
+                                    mainWindow.mStableInsets,
+                                    ActivityManager.isLowRamDeviceStatic() /* reduced */,
+                                    1.0f /* scale */);
+                        }
+                    }
+                    return null;
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void finish(boolean moveHomeToTop) {
+            if (DEBUG) Log.d(TAG, "finish(" + moveHomeToTop + "): mCanceled=" + mCanceled);
+            long token = Binder.clearCallingIdentity();
+            try {
+                synchronized (mService.getWindowManagerLock()) {
+                    if (mCanceled) {
+                        return;
+                    }
+                }
+
+                // Note, the callback will handle its own synchronization, do not lock on WM lock
+                // prior to calling the callback
+                mCallbacks.onAnimationFinished(moveHomeToTop);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void setInputConsumerEnabled(boolean enabled) {
+            if (DEBUG) Log.d(TAG, "setInputConsumerEnabled(" + enabled + "): mCanceled="
+                    + mCanceled);
+            long token = Binder.clearCallingIdentity();
+            try {
+                synchronized (mService.getWindowManagerLock()) {
+                    if (mCanceled) {
+                        return;
+                    }
+
+                    mInputConsumerEnabled = enabled;
+                    mService.mInputMonitor.updateInputWindowsLw(true /*force*/);
+                    mService.scheduleAnimationLocked();
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+    };
+
+    /**
+     * Initializes a new RecentsAnimationController.
+     *
+     * @param remoteAnimationRunner The remote runner which should be notified when the animation is
+     *                              ready to start or has been canceled
+     * @param callbacks Callbacks to be made when the animation finishes
+     * @param restoreHomeBehindStackId The stack id to restore the home stack behind once the
+     *                                 animation is complete. Will be passed to the callback.
+     */
+    RecentsAnimationController(WindowManagerService service,
+            IRecentsAnimationRunner remoteAnimationRunner, RecentsAnimationCallbacks callbacks,
+            int displayId) {
+        mService = service;
+        mRunner = remoteAnimationRunner;
+        mCallbacks = callbacks;
+
+        final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);
+        final ArrayList<Task> visibleTasks = dc.getVisibleTasks();
+        if (visibleTasks.isEmpty()) {
+            cancelAnimation();
+            return;
+        }
+
+        // Make leashes for each of the visible tasks and add it to the recents animation to be
+        // started
+        final int taskCount = visibleTasks.size();
+        for (int i = 0; i < taskCount; i++) {
+            final Task task = visibleTasks.get(i);
+            final WindowConfiguration config = task.getWindowConfiguration();
+            if (config.tasksAreFloating()
+                    || config.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
+                    || config.getActivityType() == ACTIVITY_TYPE_HOME) {
+                continue;
+            }
+            addAnimation(task);
+        }
+
+        // Adjust the wallpaper visibility for the showing home activity
+        final AppWindowToken recentsComponentAppToken =
+                dc.getHomeStack().getTopChild().getTopFullscreenAppToken();
+        if (recentsComponentAppToken != null) {
+            if (DEBUG) Log.d(TAG, "setHomeApp(" + recentsComponentAppToken.getName() + ")");
+            mHomeAppToken = recentsComponentAppToken;
+            final WallpaperController wc = dc.mWallpaperController;
+            if (recentsComponentAppToken.windowsCanBeWallpaperTarget()) {
+                dc.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
+                dc.setLayoutNeeded();
+            }
+        }
+
+        mService.mWindowPlacerLocked.performSurfacePlacement();
+    }
+
+    private void addAnimation(Task task) {
+        if (DEBUG) Log.d(TAG, "addAnimation(" + task.getName() + ")");
+        final SurfaceAnimator anim = new SurfaceAnimator(task, null /* animationFinishedCallback */,
+                mService.mAnimator::addAfterPrepareSurfacesRunnable, mService);
+        final TaskAnimationAdapter taskAdapter = new TaskAnimationAdapter(task);
+        anim.startAnimation(task.getPendingTransaction(), taskAdapter, false /* hidden */);
+        task.commitPendingTransaction();
+        mPendingAnimations.add(taskAdapter);
+    }
+
+    void startAnimation() {
+        if (DEBUG) Log.d(TAG, "startAnimation(): mPendingStart=" + mPendingStart);
+        if (!mPendingStart) {
+            return;
+        }
+        try {
+            final RemoteAnimationTarget[] appAnimations =
+                    new RemoteAnimationTarget[mPendingAnimations.size()];
+            for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
+                appAnimations[i] = mPendingAnimations.get(i).createRemoteAnimationApp();
+            }
+            mPendingStart = false;
+            mRunner.onAnimationStart(mController, appAnimations);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Failed to start recents animation", e);
+        }
+    }
+
+    void cancelAnimation() {
+        if (DEBUG) Log.d(TAG, "cancelAnimation()");
+        if (mCanceled) {
+            // We've already canceled the animation
+            return;
+        }
+        mCanceled = true;
+        try {
+            mRunner.onAnimationCanceled();
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Failed to cancel recents animation", e);
+        }
+
+        // Clean up and return to the previous app
+        mCallbacks.onAnimationFinished(false /* moveHomeToTop */);
+    }
+
+    void cleanupAnimation() {
+        if (DEBUG) Log.d(TAG, "cleanupAnimation(): mPendingAnimations="
+                + mPendingAnimations.size());
+        for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
+            final TaskAnimationAdapter adapter = mPendingAnimations.get(i);
+            adapter.mCapturedFinishCallback.onAnimationFinished(adapter);
+        }
+        mPendingAnimations.clear();
+
+        mService.mInputMonitor.updateInputWindowsLw(true /*force*/);
+        mService.scheduleAnimationLocked();
+        mService.destroyInputConsumer(INPUT_CONSUMER_RECENTS_ANIMATION);
+    }
+
+    void checkAnimationReady(WallpaperController wallpaperController) {
+        if (mPendingStart) {
+            final boolean wallpaperReady = !isHomeAppOverWallpaper()
+                    || (wallpaperController.getWallpaperTarget() != null
+                            && wallpaperController.wallpaperTransitionReady());
+            if (wallpaperReady) {
+                mService.getRecentsAnimationController().startAnimation();
+            }
+        }
+    }
+
+    boolean isWallpaperVisible(WindowState w) {
+        return w != null && w.mAppToken != null && mHomeAppToken == w.mAppToken
+                && isHomeAppOverWallpaper();
+    }
+
+    boolean hasInputConsumerForApp(AppWindowToken appToken) {
+        return mInputConsumerEnabled && isAnimatingApp(appToken);
+    }
+
+    boolean updateInputConsumerForApp(InputConsumerImpl recentsAnimationInputConsumer,
+            boolean hasFocus) {
+        // Update the input consumer touchable region to match the home app main window
+        final WindowState homeAppMainWindow = mHomeAppToken != null
+                ? mHomeAppToken.findMainWindow()
+                : null;
+        if (homeAppMainWindow != null) {
+            homeAppMainWindow.getBounds(mTmpRect);
+            recentsAnimationInputConsumer.mWindowHandle.hasFocus = hasFocus;
+            recentsAnimationInputConsumer.mWindowHandle.touchableRegion.set(mTmpRect);
+            return true;
+        }
+        return false;
+    }
+
+    private boolean isHomeAppOverWallpaper() {
+        if (mHomeAppToken == null) {
+            return false;
+        }
+        return mHomeAppToken.windowsCanBeWallpaperTarget();
+    }
+
+    private boolean isAnimatingApp(AppWindowToken appToken) {
+        for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
+            final Task task = mPendingAnimations.get(i).mTask;
+            for (int j = task.getChildCount() - 1; j >= 0; j--) {
+                final AppWindowToken app = task.getChildAt(j);
+                if (app == appToken) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    private class TaskAnimationAdapter implements AnimationAdapter {
+
+        private Task mTask;
+        private SurfaceControl mCapturedLeash;
+        private OnAnimationFinishedCallback mCapturedFinishCallback;
+
+        TaskAnimationAdapter(Task task) {
+            mTask = task;
+        }
+
+        RemoteAnimationTarget createRemoteAnimationApp() {
+            // TODO: Do we need position and stack bounds?
+            return new RemoteAnimationTarget(mTask.mTaskId, MODE_CLOSING, mCapturedLeash,
+                    !mTask.fillsParent(),
+                    mTask.getTopVisibleAppMainWindow().mWinAnimator.mLastClipRect,
+                    mTask.getPrefixOrderIndex(), new Point(), new Rect(),
+                    mTask.getWindowConfiguration());
+        }
+
+        @Override
+        public boolean getDetachWallpaper() {
+            return false;
+        }
+
+        @Override
+        public int getBackgroundColor() {
+            return 0;
+        }
+
+        @Override
+        public void startAnimation(SurfaceControl animationLeash, Transaction t,
+                OnAnimationFinishedCallback finishCallback) {
+            mCapturedLeash = animationLeash;
+            mCapturedFinishCallback = finishCallback;
+        }
+
+        @Override
+        public void onAnimationCancelled(SurfaceControl animationLeash) {
+            cancelAnimation();
+        }
+
+        @Override
+        public long getDurationHint() {
+            return 0;
+        }
+
+        @Override
+        public long getStatusBarTransitionsStartTime() {
+            return SystemClock.uptimeMillis();
+        }
+    }
+
+    public void dump(PrintWriter pw, String prefix) {
+        final String innerPrefix = prefix + "  ";
+        pw.print(prefix); pw.println(RecentsAnimationController.class.getSimpleName() + ":");
+        pw.print(innerPrefix); pw.println("mPendingStart=" + mPendingStart);
+        pw.print(innerPrefix); pw.println("mHomeAppToken=" + mHomeAppToken);
+    }
+}
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
index 8515dcb..7d4eafb 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -160,7 +160,8 @@
             return new RemoteAnimationTarget(task.mTaskId, getMode(),
                     mCapturedLeash, !mAppWindowToken.fillsParent(),
                     mainWindow.mWinAnimator.mLastClipRect,
-                    mAppWindowToken.getPrefixOrderIndex(), mPosition, mStackBounds);
+                    mAppWindowToken.getPrefixOrderIndex(), mPosition, mStackBounds,
+                    task.getWindowConfiguration());
         }
 
         private int getMode() {
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 2cc96c9..deed7f1 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -623,6 +623,13 @@
                         defaultDisplay.pendingLayoutChanges);
         }
 
+        // Defer starting the recents animation until the wallpaper has drawn
+        final RecentsAnimationController recentsAnimationController =
+            mService.getRecentsAnimationController();
+        if (recentsAnimationController != null) {
+            recentsAnimationController.checkAnimationReady(mWallpaperController);
+        }
+
         if (mWallpaperForceHidingChanged && defaultDisplay.pendingLayoutChanges == 0
                 && !mService.mAppTransition.isReady()) {
             // At this point, there was a window with a wallpaper that was force hiding other
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java
index 10f1c3a..0512a08 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimator.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java
@@ -62,7 +62,7 @@
      * @param addAfterPrepareSurfaces Consumer that takes a runnable and executes it after preparing
      *                                surfaces in WM. Can be implemented differently during testing.
      */
-    SurfaceAnimator(Animatable animatable, Runnable animationFinishedCallback,
+    SurfaceAnimator(Animatable animatable, @Nullable Runnable animationFinishedCallback,
             Consumer<Runnable> addAfterPrepareSurfaces, WindowManagerService service) {
         mAnimatable = animatable;
         mService = service;
@@ -71,7 +71,8 @@
                 addAfterPrepareSurfaces);
     }
 
-    private OnAnimationFinishedCallback getFinishedCallback(Runnable animationFinishedCallback,
+    private OnAnimationFinishedCallback getFinishedCallback(
+            @Nullable Runnable animationFinishedCallback,
             Consumer<Runnable> addAfterPrepareSurfaces) {
         return anim -> {
             synchronized (mService.mWindowMap) {
@@ -97,7 +98,9 @@
                     SurfaceControl.openTransaction();
                     try {
                         reset(t, true /* destroyLeash */);
-                        animationFinishedCallback.run();
+                        if (animationFinishedCallback != null) {
+                            animationFinishedCallback.run();
+                        }
                     } finally {
                         SurfaceControl.mergeToGlobalTransaction(t);
                         SurfaceControl.closeTransaction();
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index f79719c..212a0d70 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -223,6 +223,27 @@
             return null;
         }
 
+        if (top.hasCommittedReparentToAnimationLeash()) {
+            if (DEBUG_SCREENSHOT) {
+                Slog.w(TAG_WM, "Failed to take screenshot. App is animating " + top);
+            }
+            return null;
+        }
+
+        final boolean hasVisibleChild = top.forAllWindows(
+                // Ensure at least one window for the top app is visible before attempting to take
+                // a screenshot. Visible here means that the WSA surface is shown and has an alpha
+                // greater than 0.
+                ws -> ws.mWinAnimator != null && ws.mWinAnimator.getShown()
+                        && ws.mWinAnimator.mLastAlpha > 0f, true);
+
+        if (!hasVisibleChild) {
+            if (DEBUG_SCREENSHOT) {
+                Slog.w(TAG_WM, "Failed to take screenshot. No visible windows for " + task);
+            }
+            return null;
+        }
+
         final boolean isLowRamDevice = ActivityManager.isLowRamDeviceStatic();
         final float scaleFraction = isLowRamDevice ? REDUCED_SCALE : 1f;
         task.getBounds(mTmpRect);
@@ -233,7 +254,7 @@
 
         if (buffer == null || buffer.getWidth() <= 1 || buffer.getHeight() <= 1) {
             if (DEBUG_SCREENSHOT) {
-                Slog.w(TAG_WM, "Failed to take screenshot");
+                Slog.w(TAG_WM, "Failed to take screenshot for " + task);
             }
             return null;
         }
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 1218d3b..f2ad6fb 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -149,8 +149,17 @@
             mFindResults.setUseTopWallpaperAsTarget(true);
         }
 
+        final RecentsAnimationController recentsAnimationController =
+                mService.getRecentsAnimationController();
         final boolean hasWallpaper = (w.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0;
-        if (hasWallpaper && w.isOnScreen() && (mWallpaperTarget == w || w.isDrawFinishedLw())) {
+        final boolean isRecentsTransitionTarget = (recentsAnimationController != null
+                && recentsAnimationController.isWallpaperVisible(w));
+        if (isRecentsTransitionTarget) {
+            if (DEBUG_WALLPAPER) Slog.v(TAG, "Found recents animation wallpaper target: " + w);
+            mFindResults.setWallpaperTarget(w);
+            return true;
+        } else if (hasWallpaper && w.isOnScreen()
+                && (mWallpaperTarget == w || w.isDrawFinishedLw())) {
             if (DEBUG_WALLPAPER) Slog.v(TAG, "Found wallpaper target: " + w);
             mFindResults.setWallpaperTarget(w);
             if (w == mWallpaperTarget && w.mWinAnimator.isAnimationSet()) {
@@ -199,15 +208,22 @@
         }
     }
 
-    private boolean isWallpaperVisible(WindowState wallpaperTarget) {
+    private final boolean isWallpaperVisible(WindowState wallpaperTarget) {
+        final RecentsAnimationController recentsAnimationController =
+                mService.getRecentsAnimationController();
+        boolean isAnimatingWithRecentsComponent = recentsAnimationController != null
+                && recentsAnimationController.isWallpaperVisible(wallpaperTarget);
         if (DEBUG_WALLPAPER) Slog.v(TAG, "Wallpaper vis: target " + wallpaperTarget + ", obscured="
                 + (wallpaperTarget != null ? Boolean.toString(wallpaperTarget.mObscured) : "??")
                 + " animating=" + ((wallpaperTarget != null && wallpaperTarget.mAppToken != null)
                 ? wallpaperTarget.mAppToken.isSelfAnimating() : null)
-                + " prev=" + mPrevWallpaperTarget);
+                + " prev=" + mPrevWallpaperTarget
+                + " recentsAnimationWallpaperVisible=" + isAnimatingWithRecentsComponent);
         return (wallpaperTarget != null
-                && (!wallpaperTarget.mObscured || (wallpaperTarget.mAppToken != null
-                && wallpaperTarget.mAppToken.isSelfAnimating())))
+                && (!wallpaperTarget.mObscured
+                        || isAnimatingWithRecentsComponent
+                        || (wallpaperTarget.mAppToken != null
+                                && wallpaperTarget.mAppToken.isSelfAnimating())))
                 || mPrevWallpaperTarget != null;
     }
 
@@ -587,6 +603,11 @@
             mWallpaperDrawState = WALLPAPER_DRAW_TIMEOUT;
             if (DEBUG_APP_TRANSITIONS || DEBUG_WALLPAPER) Slog.v(TAG,
                     "*** WALLPAPER DRAW TIMEOUT");
+
+            // If there was a recents animation in progress, cancel that animation
+            if (mService.getRecentsAnimationController() != null) {
+                mService.getRecentsAnimationController().cancelAnimation();
+            }
             return true;
         }
         return false;
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 42c6ec2..1f9255a 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -100,6 +100,12 @@
     /** Total number of elements in this subtree, including our own hierarchy element. */
     private int mTreeWeight = 1;
 
+    /**
+     * Indicates whether we are animating and have committed the transaction to reparent our 
+     * surface to the animation leash
+     */
+    private boolean mCommittedReparentToAnimationLeash;
+
     WindowContainer(WindowManagerService service) {
         mService = service;
         mPendingTransaction = service.mTransactionFactory.make();
@@ -337,9 +343,9 @@
     }
 
     /** Returns true if this window container has the input child. */
-    boolean hasChild(WindowContainer child) {
+    boolean hasChild(E child) {
         for (int i = mChildren.size() - 1; i >= 0; --i) {
-            final WindowContainer current = mChildren.get(i);
+            final E current = mChildren.get(i);
             if (current == child || current.hasChild(child)) {
                 return true;
             }
@@ -1025,12 +1031,24 @@
      */
     void prepareSurfaces() {
         SurfaceControl.mergeToGlobalTransaction(getPendingTransaction());
+
+        // If a leash has been set when the transaction was committed, then the leash reparent has
+        // been committed.
+        mCommittedReparentToAnimationLeash = mSurfaceAnimator.hasLeash();
         for (int i = 0; i < mChildren.size(); i++) {
             mChildren.get(i).prepareSurfaces();
         }
     }
 
     /**
+     * @return true if the reparent to animation leash transaction has been committed, false
+     * otherwise.
+     */
+    boolean hasCommittedReparentToAnimationLeash() {
+        return mCommittedReparentToAnimationLeash;
+    }
+
+    /**
      * Trigger a call to prepareSurfaces from the animation thread, such that
      * mPendingTransaction will be applied.
      */
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index de1e7ec..4fb2390 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -24,6 +24,8 @@
 import static android.app.ActivityManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
 import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW;
 import static android.app.StatusBarManager.DISABLE_MASK;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
 import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED;
 import static android.content.Intent.ACTION_USER_REMOVED;
 import static android.content.Intent.EXTRA_USER_HANDLE;
@@ -123,6 +125,7 @@
 import android.app.AppOpsManager;
 import android.app.IActivityManager;
 import android.app.IAssistDataReceiver;
+import android.app.WindowConfiguration;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -196,6 +199,7 @@
 import android.view.IInputFilter;
 import android.view.IOnKeyguardExitResult;
 import android.view.IPinnedStackListener;
+import android.view.IRecentsAnimationRunner;
 import android.view.IRotationWatcher;
 import android.view.IWallpaperVisibilityListener;
 import android.view.IWindow;
@@ -528,6 +532,7 @@
     IInputMethodManager mInputMethodManager;
 
     AccessibilityController mAccessibilityController;
+    private RecentsAnimationController mRecentsAnimationController;
 
     Watermark mWatermark;
     StrictModeFlash mStrictModeFlash;
@@ -2670,6 +2675,39 @@
         }
     }
 
+    public void initializeRecentsAnimation(
+            IRecentsAnimationRunner recentsAnimationRunner,
+            RecentsAnimationController.RecentsAnimationCallbacks callbacks, int displayId) {
+        synchronized (mWindowMap) {
+            cancelRecentsAnimation();
+            mRecentsAnimationController = new RecentsAnimationController(this,
+                    recentsAnimationRunner, callbacks, displayId);
+        }
+    }
+
+    public RecentsAnimationController getRecentsAnimationController() {
+        return mRecentsAnimationController;
+    }
+
+    public void cancelRecentsAnimation() {
+        synchronized (mWindowMap) {
+            if (mRecentsAnimationController != null) {
+                // This call will call through to cleanupAnimation() below after the animation is
+                // canceled
+                mRecentsAnimationController.cancelAnimation();
+            }
+        }
+    }
+
+    public void cleanupRecentsAnimation() {
+        synchronized (mWindowMap) {
+            if (mRecentsAnimationController != null) {
+                mRecentsAnimationController.cleanupAnimation();
+                mRecentsAnimationController = null;
+            }
+        }
+    }
+
     public void setAppFullscreen(IBinder token, boolean toOpaque) {
         synchronized (mWindowMap) {
             final AppWindowToken atoken = mRoot.getAppWindowToken(token);
@@ -6327,6 +6365,10 @@
             pw.print("  mSkipAppTransitionAnimation=");pw.println(mSkipAppTransitionAnimation);
             pw.println("  mLayoutToAnim:");
             mAppTransition.dump(pw, "    ");
+            if (mRecentsAnimationController != null) {
+                pw.print("  mRecentsAnimationController="); pw.println(mRecentsAnimationController);
+                mRecentsAnimationController.dump(pw, "    ");
+            }
         }
     }
 
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index 67bad0f..8fd5be2 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -358,6 +358,7 @@
     Return<void> gnssAcquireWakelockCb() override;
     Return<void> gnssReleaseWakelockCb() override;
     Return<void> gnssRequestTimeCb() override;
+    Return<void> gnssRequestLocationCb(const bool independentFromGnss) override;
     Return<void> gnssSetSystemInfoCb(const IGnssCallback::GnssSystemInfo& info) override;
 
     // New in 1.1
@@ -472,6 +473,11 @@
     return Void();
 }
 
+Return<void> GnssCallback::gnssRequestLocationCb(const bool independentFromGnss) {
+    // TODO(b/72405645): call into java implementation
+    return Void();
+}
+
 Return<void> GnssCallback::gnssSetSystemInfoCb(const IGnssCallback::GnssSystemInfo& info) {
     ALOGD("%s: yearOfHw=%d\n", __func__, info.yearOfHw);
 
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 372b5be..5d8aca1 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -59,7 +59,6 @@
     <uses-permission android:name="android.permission.STATUS_BAR_SERVICE" />
     <uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER" />
     <uses-permission android:name="android.permission.READ_FRAME_BUFFER" />
-    <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
 
     <!-- Uses API introduced in O (26) -->
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
index 96bf49b..10253c5 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
@@ -30,6 +30,7 @@
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.spy;
 
+import com.android.server.wm.DisplayWindowController;
 import org.mockito.invocation.InvocationOnMock;
 
 import android.app.IApplicationThread;
@@ -345,7 +346,7 @@
         }
     }
 
-    private static class TestActivityDisplay extends ActivityDisplay {
+    protected static class TestActivityDisplay extends ActivityDisplay {
 
         private final ActivityStackSupervisor mSupervisor;
         TestActivityDisplay(ActivityStackSupervisor supervisor, int displayId) {
@@ -374,6 +375,11 @@
                         this, stackId, mSupervisor, windowingMode, activityType, onTop);
             }
         }
+
+        @Override
+        protected DisplayWindowController createWindowContainerController() {
+            return mock(DisplayWindowController.class);
+        }
     }
 
     private static WindowManagerService prepareMockWindowManager() {
diff --git a/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java b/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java
index 5a21102..24566fc 100644
--- a/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java
@@ -573,7 +573,8 @@
         assertSecurityException(expectCallable, () -> mService.getTaskDescription(0));
         assertSecurityException(expectCallable, () -> mService.cancelTaskWindowTransition(0));
         assertSecurityException(expectCallable, () -> mService.startRecentsActivity(null, null,
-                null, 0));
+                null));
+        assertSecurityException(expectCallable, () -> mService.cancelRecentsAnimation());
     }
 
     private void testGetTasksApis(boolean expectCallable) {
@@ -676,8 +677,8 @@
         @Override
         public void initialize() {
             super.initialize();
-            mDisplay = new ActivityDisplay(this, DEFAULT_DISPLAY);
-            mOtherDisplay = new ActivityDisplay(this, DEFAULT_DISPLAY);
+            mDisplay = new TestActivityDisplay(this, DEFAULT_DISPLAY);
+            mOtherDisplay = new TestActivityDisplay(this, DEFAULT_DISPLAY);
             attachDisplay(mOtherDisplay);
             attachDisplay(mDisplay);
         }
diff --git a/services/tests/servicestests/src/com/android/server/am/RunningTasksTest.java b/services/tests/servicestests/src/com/android/server/am/RunningTasksTest.java
index fc75628..c6ce7e1 100644
--- a/services/tests/servicestests/src/com/android/server/am/RunningTasksTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/RunningTasksTest.java
@@ -68,7 +68,7 @@
         // Create a number of stacks with tasks (of incrementing active time)
         final ActivityStackSupervisor supervisor = mService.mStackSupervisor;
         final SparseArray<ActivityDisplay> displays = new SparseArray<>();
-        final ActivityDisplay display = new ActivityDisplay(supervisor, DEFAULT_DISPLAY);
+        final ActivityDisplay display = new TestActivityDisplay(supervisor, DEFAULT_DISPLAY);
         displays.put(DEFAULT_DISPLAY, display);
 
         final int numStacks = 2;
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java
index b1bff70..6fc9e08 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java
@@ -23,6 +23,7 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -48,6 +49,7 @@
 
 import java.io.File;
 import java.security.KeyStore;
+import java.security.UnrecoverableKeyException;
 import java.util.List;
 
 @SmallTest
@@ -258,6 +260,40 @@
     }
 
     @Test
+    public void getEncryptKey_generatesNewKeyIfOldOneIsInvalid() throws Exception {
+        doThrow(new UnrecoverableKeyException()).when(mKeyStoreProxy).getKey(
+                eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/encrypt"),
+                any());
+
+        mPlatformKeyManager.getEncryptKey(USER_ID_FIXTURE);
+
+        verify(mKeyStoreProxy).getKey(
+                eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/encrypt"),
+                any());
+        // Attempt to get regenerated key.
+        verify(mKeyStoreProxy).getKey(
+                eq("com.android.server.locksettings.recoverablekeystore/platform/42/2/encrypt"),
+                any());
+    }
+
+    @Test
+    public void getDecryptKey_generatesNewKeyIfOldOneIsInvalid() throws Exception {
+        doThrow(new UnrecoverableKeyException()).when(mKeyStoreProxy).getKey(
+                eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/decrypt"),
+                any());
+
+        mPlatformKeyManager.getDecryptKey(USER_ID_FIXTURE);
+
+        verify(mKeyStoreProxy).getKey(
+                eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/decrypt"),
+                any());
+        // Attempt to get regenerated key.
+        verify(mKeyStoreProxy).getKey(
+                eq("com.android.server.locksettings.recoverablekeystore/platform/42/2/decrypt"),
+                any());
+    }
+
+    @Test
     public void getEncryptKey_getsDecryptKeyWithCorrectAlias() throws Exception {
         mPlatformKeyManager.getEncryptKey(USER_ID_FIXTURE);
 
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java
index f0254c6..097d214 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java
@@ -315,6 +315,29 @@
         assertThat(statuses).hasSize(0);
     }
 
+    public void testInvalidateKeysWithOldGenerationId_withSingleKey() {
+        int userId = 12;
+        int uid = 1009;
+        int generationId = 6;
+        int status = 120;
+        int status2 = 121;
+        String alias = "test";
+        byte[] nonce = getUtf8Bytes("nonce");
+        byte[] keyMaterial = getUtf8Bytes("keymaterial");
+        WrappedKey wrappedKey = new WrappedKey(nonce, keyMaterial, generationId, status);
+        mRecoverableKeyStoreDb.insertKey(userId, uid, alias, wrappedKey);
+
+        WrappedKey retrievedKey = mRecoverableKeyStoreDb.getKey(uid, alias);
+        assertThat(retrievedKey.getRecoveryStatus()).isEqualTo(status);
+
+        mRecoverableKeyStoreDb.setRecoveryStatus(uid, alias, status2);
+        mRecoverableKeyStoreDb.invalidateKeysWithOldGenerationId(userId, generationId + 1);
+
+        retrievedKey = mRecoverableKeyStoreDb.getKey(uid, alias);
+        assertThat(retrievedKey.getRecoveryStatus())
+                .isEqualTo(RecoveryController.RECOVERY_STATUS_PERMANENT_FAILURE);
+    }
+
     @Test
     public void setRecoveryServicePublicKey_replaceOldKey() throws Exception {
         int userId = 12;
diff --git a/telephony/java/android/telephony/DataConnectionRealTimeInfo.java b/telephony/java/android/telephony/DataConnectionRealTimeInfo.java
index f71f58d..fc4e17a 100644
--- a/telephony/java/android/telephony/DataConnectionRealTimeInfo.java
+++ b/telephony/java/android/telephony/DataConnectionRealTimeInfo.java
@@ -28,10 +28,14 @@
 public class DataConnectionRealTimeInfo implements Parcelable {
     private long mTime;             // Time the info was collected since boot in nanos;
 
-    public static final int DC_POWER_STATE_LOW       = 1;
-    public static final int DC_POWER_STATE_MEDIUM    = 2;
-    public static final int DC_POWER_STATE_HIGH      = 3;
-    public static final int DC_POWER_STATE_UNKNOWN   = Integer.MAX_VALUE;
+    public static final int DC_POWER_STATE_LOW
+            = TelephonyProtoEnums.DATA_CONNECTION_POWER_STATE_LOW ; // = 1
+    public static final int DC_POWER_STATE_MEDIUM
+            = TelephonyProtoEnums.DATA_CONNECTION_POWER_STATE_MEDIUM; // = 2
+    public static final int DC_POWER_STATE_HIGH
+            = TelephonyProtoEnums.DATA_CONNECTION_POWER_STATE_HIGH; // = 3
+    public static final int DC_POWER_STATE_UNKNOWN
+            = TelephonyProtoEnums.DATA_CONNECTION_POWER_STATE_UNKNOWN; // = Integer.MAX_VALUE
 
     private int mDcPowerState;      // DC_POWER_STATE_[LOW | MEDIUM | HIGH | UNKNOWN]
 
diff --git a/telephony/java/android/telephony/DataSpecificRegistrationStates.java b/telephony/java/android/telephony/DataSpecificRegistrationStates.java
new file mode 100644
index 0000000..97e3037
--- /dev/null
+++ b/telephony/java/android/telephony/DataSpecificRegistrationStates.java
@@ -0,0 +1,72 @@
+package android.telephony;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+
+/**
+ * Class that stores information specific to data network registration.
+ * @hide
+ */
+public class DataSpecificRegistrationStates implements Parcelable{
+    /**
+     * The maximum number of simultaneous Data Calls that
+     * must be established using setupDataCall().
+     */
+    public final int maxDataCalls;
+
+    DataSpecificRegistrationStates(int maxDataCalls) {
+        this.maxDataCalls = maxDataCalls;
+    }
+
+    private DataSpecificRegistrationStates(Parcel source) {
+        maxDataCalls = source.readInt();
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(maxDataCalls);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public String toString() {
+        return "DataSpecificRegistrationStates {" + " mMaxDataCalls=" + maxDataCalls + "}";
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(maxDataCalls);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+
+        if (o == null || !(o instanceof DataSpecificRegistrationStates)) {
+            return false;
+        }
+
+        DataSpecificRegistrationStates other = (DataSpecificRegistrationStates) o;
+        return this.maxDataCalls == other.maxDataCalls;
+    }
+
+    public static final Parcelable.Creator<DataSpecificRegistrationStates> CREATOR =
+            new Parcelable.Creator<DataSpecificRegistrationStates>() {
+                @Override
+                public DataSpecificRegistrationStates createFromParcel(Parcel source) {
+                    return new DataSpecificRegistrationStates(source);
+                }
+
+                @Override
+                public DataSpecificRegistrationStates[] newArray(int size) {
+                    return new DataSpecificRegistrationStates[size];
+                }
+            };
+}
\ No newline at end of file
diff --git a/telephony/java/android/telephony/NetworkRegistrationState.java b/telephony/java/android/telephony/NetworkRegistrationState.java
index e051069..4f137be 100644
--- a/telephony/java/android/telephony/NetworkRegistrationState.java
+++ b/telephony/java/android/telephony/NetworkRegistrationState.java
@@ -105,6 +105,11 @@
     @Nullable
     private final CellIdentity mCellIdentity;
 
+    @Nullable
+    private VoiceSpecificRegistrationStates mVoiceSpecificStates;
+
+    @Nullable
+    private DataSpecificRegistrationStates mDataSpecificStates;
 
     /**
      * @param transportType Transport type. Must be {@link AccessNetworkConstants.TransportType}
@@ -128,6 +133,34 @@
         mEmergencyOnly = emergencyOnly;
     }
 
+    /**
+     * Constructor for voice network registration states.
+     * @hide
+     */
+    public NetworkRegistrationState(int transportType, int domain, int regState,
+            int accessNetworkTechnology, int reasonForDenial, boolean emergencyOnly,
+            int[] availableServices, @Nullable CellIdentity cellIdentity, boolean cssSupported,
+            int roamingIndicator, int systemIsInPrl, int defaultRoamingIndicator) {
+        this(transportType, domain, regState, accessNetworkTechnology,
+                reasonForDenial, emergencyOnly, availableServices, cellIdentity);
+
+        mVoiceSpecificStates = new VoiceSpecificRegistrationStates(cssSupported, roamingIndicator,
+                systemIsInPrl, defaultRoamingIndicator);
+    }
+
+    /**
+     * Constructor for data network registration states.
+     * @hide
+     */
+    public NetworkRegistrationState(int transportType, int domain, int regState,
+            int accessNetworkTechnology, int reasonForDenial, boolean emergencyOnly,
+            int[] availableServices, @Nullable CellIdentity cellIdentity, int maxDataCalls) {
+        this(transportType, domain, regState, accessNetworkTechnology,
+                reasonForDenial, emergencyOnly, availableServices, cellIdentity);
+
+        mDataSpecificStates = new DataSpecificRegistrationStates(maxDataCalls);
+    }
+
     protected NetworkRegistrationState(Parcel source) {
         mTransportType = source.readInt();
         mDomain = source.readInt();
@@ -137,6 +170,10 @@
         mEmergencyOnly = source.readBoolean();
         mAvailableServices = source.createIntArray();
         mCellIdentity = source.readParcelable(CellIdentity.class.getClassLoader());
+        mVoiceSpecificStates = source.readParcelable(
+                VoiceSpecificRegistrationStates.class.getClassLoader());
+        mDataSpecificStates = source.readParcelable(
+                DataSpecificRegistrationStates.class.getClassLoader());
     }
 
     /**
@@ -173,6 +210,36 @@
         return mAccessNetworkTechnology;
     }
 
+    /**
+     * @return Reason for denial from network.
+     */
+    public int getReasonForDenial() {
+        return mReasonForDenial;
+    }
+
+    /**
+     * @return The cell information.
+     */
+    public CellIdentity getCellIdentity() {
+        return mCellIdentity;
+    }
+
+    /**
+     * @hide
+     */
+    @Nullable
+    public VoiceSpecificRegistrationStates getVoiceSpecificStates() {
+        return mVoiceSpecificStates;
+    }
+
+    /**
+     * @hide
+     */
+    @Nullable
+    public DataSpecificRegistrationStates getDataSpecificStates() {
+        return mDataSpecificStates;
+    }
+
     @Override
     public int describeContents() {
         return 0;
@@ -202,13 +269,16 @@
                 .append(" emergencyEnabled=").append(mEmergencyOnly)
                 .append(" supportedServices=").append(mAvailableServices)
                 .append(" cellIdentity=").append(mCellIdentity)
+                .append(" voiceSpecificStates=").append(mVoiceSpecificStates)
+                .append(" dataSpecificStates=").append(mDataSpecificStates)
                 .append("}").toString();
     }
 
     @Override
     public int hashCode() {
         return Objects.hash(mTransportType, mDomain, mRegState, mAccessNetworkTechnology,
-                mReasonForDenial, mEmergencyOnly, mAvailableServices, mCellIdentity);
+                mReasonForDenial, mEmergencyOnly, mAvailableServices, mCellIdentity,
+                mVoiceSpecificStates, mDataSpecificStates);
     }
 
     @Override
@@ -228,7 +298,9 @@
                 && mEmergencyOnly == other.mEmergencyOnly
                 && (mAvailableServices == other.mAvailableServices
                     || Arrays.equals(mAvailableServices, other.mAvailableServices))
-                && mCellIdentity == other.mCellIdentity;
+                && mCellIdentity == other.mCellIdentity
+                && mVoiceSpecificStates == other.mVoiceSpecificStates
+                && mDataSpecificStates == other.mDataSpecificStates;
     }
 
     @Override
@@ -241,6 +313,8 @@
         dest.writeBoolean(mEmergencyOnly);
         dest.writeIntArray(mAvailableServices);
         dest.writeParcelable(mCellIdentity, 0);
+        dest.writeParcelable(mVoiceSpecificStates, 0);
+        dest.writeParcelable(mDataSpecificStates, 0);
     }
 
     public static final Parcelable.Creator<NetworkRegistrationState> CREATOR =
diff --git a/telephony/java/android/telephony/SignalStrength.java b/telephony/java/android/telephony/SignalStrength.java
index fc2ef27..778ca77 100644
--- a/telephony/java/android/telephony/SignalStrength.java
+++ b/telephony/java/android/telephony/SignalStrength.java
@@ -35,15 +35,20 @@
     private static final boolean DBG = false;
 
     /** @hide */
-    public static final int SIGNAL_STRENGTH_NONE_OR_UNKNOWN = 0;
+    public static final int SIGNAL_STRENGTH_NONE_OR_UNKNOWN
+            = TelephonyProtoEnums.SIGNAL_STRENGTH_NONE_OR_UNKNOWN; // = 0
     /** @hide */
-    public static final int SIGNAL_STRENGTH_POOR = 1;
+    public static final int SIGNAL_STRENGTH_POOR
+            = TelephonyProtoEnums.SIGNAL_STRENGTH_POOR; // = 1
     /** @hide */
-    public static final int SIGNAL_STRENGTH_MODERATE = 2;
+    public static final int SIGNAL_STRENGTH_MODERATE
+            = TelephonyProtoEnums.SIGNAL_STRENGTH_MODERATE; // = 2
     /** @hide */
-    public static final int SIGNAL_STRENGTH_GOOD = 3;
+    public static final int SIGNAL_STRENGTH_GOOD
+            = TelephonyProtoEnums.SIGNAL_STRENGTH_GOOD; // = 3
     /** @hide */
-    public static final int SIGNAL_STRENGTH_GREAT = 4;
+    public static final int SIGNAL_STRENGTH_GREAT
+            = TelephonyProtoEnums.SIGNAL_STRENGTH_GREAT; // = 4
     /** @hide */
     public static final int NUM_SIGNAL_STRENGTH_BINS = 5;
     /** @hide */
diff --git a/telephony/java/android/telephony/VoiceSpecificRegistrationStates.java b/telephony/java/android/telephony/VoiceSpecificRegistrationStates.java
new file mode 100644
index 0000000..871ee4d
--- /dev/null
+++ b/telephony/java/android/telephony/VoiceSpecificRegistrationStates.java
@@ -0,0 +1,114 @@
+package android.telephony;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+
+/**
+ * Class that stores information specific to voice network registration.
+ * @hide
+ */
+public class VoiceSpecificRegistrationStates implements Parcelable{
+    /**
+     * oncurrent services support indicator. if
+     * registered on a CDMA system.
+     * false - Concurrent services not supported,
+     * true - Concurrent services supported
+     */
+     public final boolean cssSupported;
+
+    /**
+     * TSB-58 Roaming Indicator if registered
+     * on a CDMA or EVDO system or -1 if not.
+     * Valid values are 0-255.
+     */
+    public final int roamingIndicator;
+
+    /**
+     * indicates whether the current system is in the
+     * PRL if registered on a CDMA or EVDO system or -1 if
+     * not. 0=not in the PRL, 1=in the PRL
+     */
+    public final int systemIsInPrl;
+
+    /**
+     * default Roaming Indicator from the PRL,
+     * if registered on a CDMA or EVDO system or -1 if not.
+     * Valid values are 0-255.
+     */
+    public final int defaultRoamingIndicator;
+
+    VoiceSpecificRegistrationStates(boolean cssSupported, int roamingIndicator, int systemIsInPrl,
+            int defaultRoamingIndicator) {
+        this.cssSupported = cssSupported;
+        this.roamingIndicator = roamingIndicator;
+        this.systemIsInPrl = systemIsInPrl;
+        this.defaultRoamingIndicator = defaultRoamingIndicator;
+    }
+
+    private VoiceSpecificRegistrationStates(Parcel source) {
+        this.cssSupported = source.readBoolean();
+        this.roamingIndicator = source.readInt();
+        this.systemIsInPrl = source.readInt();
+        this.defaultRoamingIndicator = source.readInt();
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeBoolean(cssSupported);
+        dest.writeInt(roamingIndicator);
+        dest.writeInt(systemIsInPrl);
+        dest.writeInt(defaultRoamingIndicator);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public String toString() {
+        return "VoiceSpecificRegistrationStates {"
+                + " mCssSupported=" + cssSupported
+                + " mRoamingIndicator=" + roamingIndicator
+                + " mSystemIsInPrl=" + systemIsInPrl
+                + " mDefaultRoamingIndicator=" + defaultRoamingIndicator + "}";
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(cssSupported, roamingIndicator, systemIsInPrl,
+                defaultRoamingIndicator);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+
+        if (o == null || !(o instanceof VoiceSpecificRegistrationStates)) {
+            return false;
+        }
+
+        VoiceSpecificRegistrationStates other = (VoiceSpecificRegistrationStates) o;
+        return this.cssSupported == other.cssSupported
+                && this.roamingIndicator == other.roamingIndicator
+                && this.systemIsInPrl == other.systemIsInPrl
+                && this.defaultRoamingIndicator == other.defaultRoamingIndicator;
+    }
+
+
+    public static final Parcelable.Creator<VoiceSpecificRegistrationStates> CREATOR =
+            new Parcelable.Creator<VoiceSpecificRegistrationStates>() {
+                @Override
+                public VoiceSpecificRegistrationStates createFromParcel(Parcel source) {
+                    return new VoiceSpecificRegistrationStates(source);
+                }
+
+                @Override
+                public VoiceSpecificRegistrationStates[] newArray(int size) {
+                    return new VoiceSpecificRegistrationStates[size];
+                }
+            };
+}
\ No newline at end of file
diff --git a/telephony/java/android/telephony/euicc/EuiccCardManager.java b/telephony/java/android/telephony/euicc/EuiccCardManager.java
index 88bae33..a1a6a5a 100644
--- a/telephony/java/android/telephony/euicc/EuiccCardManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccCardManager.java
@@ -110,6 +110,9 @@
     /** Result code of execution with no error. */
     public static final int RESULT_OK = 0;
 
+    /** Result code of an unknown error. */
+    public static final int RESULT_UNKNOWN_ERROR = -1;
+
     /**
      * Callback to receive the result of an eUICC card API.
      *
diff --git a/tests/FrameworkPerf/AndroidManifest.xml b/tests/FrameworkPerf/AndroidManifest.xml
index d62ef9e..2591aaf 100644
--- a/tests/FrameworkPerf/AndroidManifest.xml
+++ b/tests/FrameworkPerf/AndroidManifest.xml
@@ -1,6 +1,5 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
         package="com.android.frameworkperf">
-    <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
     <uses-permission android:name="android.permission.WAKE_LOCK" />
     <uses-sdk android:minSdkVersion="5" />
 
diff --git a/tests/OneMedia/AndroidManifest.xml b/tests/OneMedia/AndroidManifest.xml
index 8697f1b..c6824ec 100644
--- a/tests/OneMedia/AndroidManifest.xml
+++ b/tests/OneMedia/AndroidManifest.xml
@@ -5,7 +5,6 @@
     android:versionName="1.0" >
 
     <uses-sdk android:minSdkVersion="19"/>
-    <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
     <uses-permission android:name="android.permission.INTERNET" />
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
 
diff --git a/tests/libs-permissions/Android.mk b/tests/libs-permissions/Android.mk
new file mode 100644
index 0000000..eb38623
--- /dev/null
+++ b/tests/libs-permissions/Android.mk
@@ -0,0 +1,15 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := com.android.test.libs.product
+LOCAL_PRODUCT_MODULE := true
+LOCAL_SRC_FILES := $(call all-java-files-under, product/java)
+LOCAL_REQUIRED_MODULES := com.android.test.libs.product.xml
+include $(BUILD_JAVA_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := com.android.test.libs.product.xml
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT_PRODUCT_ETC)/permissions
+LOCAL_SRC_FILES:= product/com.android.test.libs.product.xml
+include $(BUILD_PREBUILT)
diff --git a/libs/androidfw/tests/data/basic/res/layout/layout.xml b/tests/libs-permissions/product/com.android.test.libs.product.xml
similarity index 61%
rename from libs/androidfw/tests/data/basic/res/layout/layout.xml
rename to tests/libs-permissions/product/com.android.test.libs.product.xml
index 045ede4..0a955e9 100644
--- a/libs/androidfw/tests/data/basic/res/layout/layout.xml
+++ b/tests/libs-permissions/product/com.android.test.libs.product.xml
@@ -4,22 +4,17 @@
      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.
 -->
-<Button xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/ok"
-    android:layout_width="0sp"
-    android:layout_height="fill_parent"
-    android:layout_weight="1"
-    android:layout_marginStart="2dip"
-    android:layout_marginEnd="2dip"
-    android:textAppearance="?android:attr/textAppearanceMedium"
-    android:textStyle="bold"
-    android:text="@android:string/ok" />
\ No newline at end of file
+
+<permissions>
+    <library name="com.android.test.libs.product"
+            file="/product/framework/com.android.test.libs.product.jar" />
+</permissions>
diff --git a/tests/libs-permissions/product/java/com/android/test/libs/product/LibsProductTest.java b/tests/libs-permissions/product/java/com/android/test/libs/product/LibsProductTest.java
new file mode 100644
index 0000000..f49b46e
--- /dev/null
+++ b/tests/libs-permissions/product/java/com/android/test/libs/product/LibsProductTest.java
@@ -0,0 +1,29 @@
+/*
+ * 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.test.libs.product;
+
+/**
+ * Test class for product libs.
+ */
+public class LibsProductTest {
+
+    /**
+     * Dummpy method for testing.
+     */
+    public static void test() {
+    }
+}
diff --git a/tests/privapp-permissions/Android.mk b/tests/privapp-permissions/Android.mk
index b001c8c..3c80ad8 100644
--- a/tests/privapp-permissions/Android.mk
+++ b/tests/privapp-permissions/Android.mk
@@ -29,3 +29,17 @@
 LOCAL_SRC_FILES:= vendor/privapp-permissions-test.xml
 include $(BUILD_PREBUILT)
 
+include $(CLEAR_VARS)
+LOCAL_PACKAGE_NAME := ProductPrivAppPermissionTest
+LOCAL_PRIVILEGED_MODULE := true
+LOCAL_MANIFEST_FILE := product/AndroidManifest.xml
+LOCAL_PRODUCT_MODULE := true
+LOCAL_REQUIRED_MODULES := productprivapp-permissions-test.xml
+include $(BUILD_PACKAGE)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := productprivapp-permissions-test.xml
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT_PRODUCT_ETC)/permissions
+LOCAL_SRC_FILES:= product/privapp-permissions-test.xml
+include $(BUILD_PREBUILT)
diff --git a/tests/privapp-permissions/product/AndroidManifest.xml b/tests/privapp-permissions/product/AndroidManifest.xml
new file mode 100644
index 0000000..3d9415c
--- /dev/null
+++ b/tests/privapp-permissions/product/AndroidManifest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2018 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.framework.permission.privapp.tests.product">
+
+    <!-- MANAGE_USB is signature|privileged -->
+    <uses-permission android:name="android.permission.MANAGE_USB"/>
+</manifest>
diff --git a/tests/privapp-permissions/product/privapp-permissions-test.xml b/tests/privapp-permissions/product/privapp-permissions-test.xml
new file mode 100644
index 0000000..f298f9d
--- /dev/null
+++ b/tests/privapp-permissions/product/privapp-permissions-test.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<permissions>
+    <privapp-permissions package="com.android.framework.permission.privapp.tests.product">
+        <permission name="android.permission.MANAGE_USB"/>
+    </privapp-permissions>
+</permissions>
diff --git a/tools/incident_report/main.cpp b/tools/incident_report/main.cpp
index bd1b973..302d739 100644
--- a/tools/incident_report/main.cpp
+++ b/tools/incident_report/main.cpp
@@ -452,9 +452,10 @@
     bool adbIncidentWorkaround = true;
     pid_t childPid = -1;
     vector<string> sections;
+    const char* privacy = NULL;
 
     int opt;
-    while ((opt = getopt(argc, argv, "bhi:o:s:tw")) != -1) {
+    while ((opt = getopt(argc, argv, "bhi:o:s:twp:")) != -1) {
         switch (opt) {
             case 'b':
                 outputFormat = OUTPUT_PROTO;
@@ -477,6 +478,9 @@
             case 'w':
                 adbIncidentWorkaround = false;
                 break;
+            case 'p':
+                privacy = optarg;
+                break;
             default:
                 usage(stderr);
                 return 1;
@@ -526,7 +530,7 @@
             }
 
             // TODO: This is what the real implementation will be...
-            char const** args = (char const**)malloc(sizeof(char*) * (6 + sections.size()));
+            char const** args = (char const**)malloc(sizeof(char*) * (8 + sections.size()));
             int argpos = 0;
             args[argpos++] = "adb";
             if (adbSerial != NULL) {
@@ -535,6 +539,10 @@
             }
             args[argpos++] = "shell";
             args[argpos++] = "incident";
+            if (privacy != NULL) {
+                args[argpos++] = "-p";
+                args[argpos++] = privacy;
+            }
             for (vector<string>::const_iterator it=sections.begin(); it!=sections.end(); it++) {
                 args[argpos++] = it->c_str();
             }
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 101b3e2..2a2ff0c 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -108,8 +108,6 @@
 
     boolean isDualBandSupported();
 
-    boolean saveConfiguration(String packageName);
-
     DhcpInfo getDhcpInfo();
 
     boolean isScanAlwaysAvailable();
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 05dcb33..b4885c5 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -1693,18 +1693,14 @@
      * existing networks. You should assume the network IDs can be different
      * after calling this method.
      *
-     * @return {@code true} if the operation succeeded
+     * @return {@code false} Will always return true.
      * @deprecated There is no need to call this method -
      * {@link #addNetwork(WifiConfiguration)}, {@link #updateNetwork(WifiConfiguration)}
      * and {@link #removeNetwork(int)} already persist the configurations automatically.
      */
     @Deprecated
     public boolean saveConfiguration() {
-        try {
-            return mService.saveConfiguration(mContext.getOpPackageName());
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
+        return true;
     }
 
     /**