Merge "Expose some methods in the recents lib."
diff --git a/api/current.txt b/api/current.txt
index 5b986bc..f5f4bf4 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -484,6 +484,7 @@
     field public static final int detailSocialSummary = 16843428; // 0x10102a4
     field public static final int detailsElementBackground = 16843598; // 0x101034e
     field public static final int dial = 16843010; // 0x1010102
+    field public static final int dialogCornerRadius = 16844145; // 0x1010571
     field public static final int dialogIcon = 16843252; // 0x10101f4
     field public static final int dialogLayout = 16843255; // 0x10101f7
     field public static final int dialogMessage = 16843251; // 0x10101f3
@@ -12016,6 +12017,7 @@
     method public java.lang.String[] getColumnNames();
     method public int getCount();
     method public android.database.sqlite.SQLiteDatabase getDatabase();
+    method public void setFillWindowForwardOnly(boolean);
     method public void setSelectionArguments(java.lang.String[]);
   }
 
@@ -18270,13 +18272,11 @@
     method public synchronized void applyLocalizedPattern(java.lang.String);
     method public synchronized void applyPattern(java.lang.String);
     method public synchronized boolean areSignificantDigitsUsed();
-    method public synchronized boolean equals(java.lang.Object);
     method public java.lang.StringBuffer format(double, java.lang.StringBuffer, java.text.FieldPosition);
     method public java.lang.StringBuffer format(long, java.lang.StringBuffer, java.text.FieldPosition);
     method public java.lang.StringBuffer format(java.math.BigInteger, java.lang.StringBuffer, java.text.FieldPosition);
     method public java.lang.StringBuffer format(java.math.BigDecimal, java.lang.StringBuffer, java.text.FieldPosition);
     method public java.lang.StringBuffer format(android.icu.math.BigDecimal, java.lang.StringBuffer, java.text.FieldPosition);
-    method public synchronized android.icu.util.Currency getCurrency();
     method public synchronized android.icu.text.CurrencyPluralInfo getCurrencyPluralInfo();
     method public synchronized android.icu.util.Currency.CurrencyUsage getCurrencyUsage();
     method public synchronized android.icu.text.DecimalFormatSymbols getDecimalFormatSymbols();
@@ -18284,12 +18284,8 @@
     method public synchronized int getGroupingSize();
     method public synchronized java.math.MathContext getMathContext();
     method public synchronized android.icu.math.MathContext getMathContextICU();
-    method public synchronized int getMaximumFractionDigits();
-    method public synchronized int getMaximumIntegerDigits();
     method public synchronized int getMaximumSignificantDigits();
     method public synchronized byte getMinimumExponentDigits();
-    method public synchronized int getMinimumFractionDigits();
-    method public synchronized int getMinimumIntegerDigits();
     method public synchronized int getMinimumSignificantDigits();
     method public synchronized int getMultiplier();
     method public synchronized java.lang.String getNegativePrefix();
@@ -18300,19 +18296,13 @@
     method public synchronized java.lang.String getPositivePrefix();
     method public synchronized java.lang.String getPositiveSuffix();
     method public synchronized java.math.BigDecimal getRoundingIncrement();
-    method public synchronized int getRoundingMode();
     method public synchronized int getSecondaryGroupingSize();
-    method public synchronized int hashCode();
     method public synchronized boolean isDecimalPatternMatchRequired();
     method public synchronized boolean isDecimalSeparatorAlwaysShown();
     method public synchronized boolean isExponentSignAlwaysShown();
-    method public synchronized boolean isGroupingUsed();
     method public synchronized boolean isParseBigDecimal();
-    method public synchronized boolean isParseIntegerOnly();
-    method public synchronized boolean isParseStrict();
     method public synchronized boolean isScientificNotation();
     method public java.lang.Number parse(java.lang.String, java.text.ParsePosition);
-    method public synchronized void setCurrency(android.icu.util.Currency);
     method public synchronized void setCurrencyPluralInfo(android.icu.text.CurrencyPluralInfo);
     method public synchronized void setCurrencyUsage(android.icu.util.Currency.CurrencyUsage);
     method public synchronized void setDecimalFormatSymbols(android.icu.text.DecimalFormatSymbols);
@@ -18321,15 +18311,10 @@
     method public synchronized void setExponentSignAlwaysShown(boolean);
     method public synchronized void setFormatWidth(int);
     method public synchronized void setGroupingSize(int);
-    method public synchronized void setGroupingUsed(boolean);
     method public synchronized void setMathContext(java.math.MathContext);
     method public synchronized void setMathContextICU(android.icu.math.MathContext);
-    method public synchronized void setMaximumFractionDigits(int);
-    method public synchronized void setMaximumIntegerDigits(int);
     method public synchronized void setMaximumSignificantDigits(int);
     method public synchronized void setMinimumExponentDigits(byte);
-    method public synchronized void setMinimumFractionDigits(int);
-    method public synchronized void setMinimumIntegerDigits(int);
     method public synchronized void setMinimumSignificantDigits(int);
     method public synchronized void setMultiplier(int);
     method public synchronized void setNegativePrefix(java.lang.String);
@@ -18337,15 +18322,12 @@
     method public synchronized void setPadCharacter(char);
     method public synchronized void setPadPosition(int);
     method public synchronized void setParseBigDecimal(boolean);
-    method public synchronized void setParseIntegerOnly(boolean);
     method public deprecated void setParseMaxDigits(int);
-    method public synchronized void setParseStrict(boolean);
     method public synchronized void setPositivePrefix(java.lang.String);
     method public synchronized void setPositiveSuffix(java.lang.String);
     method public synchronized void setRoundingIncrement(java.math.BigDecimal);
     method public synchronized void setRoundingIncrement(android.icu.math.BigDecimal);
     method public synchronized void setRoundingIncrement(double);
-    method public synchronized void setRoundingMode(int);
     method public synchronized void setScientificNotation(boolean);
     method public synchronized void setSecondaryGroupingSize(int);
     method public synchronized void setSignificantDigitsUsed(boolean);
@@ -25834,7 +25816,6 @@
 
   public static final class IpSecManager.SecurityParameterIndex implements java.lang.AutoCloseable {
     method public void close();
-    method protected void finalize();
     method public int getSpi();
   }
 
diff --git a/api/system-current.txt b/api/system-current.txt
index df8e034..d50fb4ec 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -616,6 +616,7 @@
     field public static final int detailSocialSummary = 16843428; // 0x10102a4
     field public static final int detailsElementBackground = 16843598; // 0x101034e
     field public static final int dial = 16843010; // 0x1010102
+    field public static final int dialogCornerRadius = 16844145; // 0x1010571
     field public static final int dialogIcon = 16843252; // 0x10101f4
     field public static final int dialogLayout = 16843255; // 0x10101f7
     field public static final int dialogMessage = 16843251; // 0x10101f3
@@ -10234,6 +10235,7 @@
     field public static final java.lang.String EXTRA_PROCESS_TEXT_READONLY = "android.intent.extra.PROCESS_TEXT_READONLY";
     field public static final java.lang.String EXTRA_QUICK_VIEW_FEATURES = "android.intent.extra.QUICK_VIEW_FEATURES";
     field public static final java.lang.String EXTRA_QUIET_MODE = "android.intent.extra.QUIET_MODE";
+    field public static final java.lang.String EXTRA_REASON = "android.intent.extra.REASON";
     field public static final java.lang.String EXTRA_REFERRER = "android.intent.extra.REFERRER";
     field public static final java.lang.String EXTRA_REFERRER_NAME = "android.intent.extra.REFERRER_NAME";
     field public static final java.lang.String EXTRA_REMOTE_CALLBACK = "android.intent.extra.REMOTE_CALLBACK";
@@ -12760,6 +12762,7 @@
     method public java.lang.String[] getColumnNames();
     method public int getCount();
     method public android.database.sqlite.SQLiteDatabase getDatabase();
+    method public void setFillWindowForwardOnly(boolean);
     method public void setSelectionArguments(java.lang.String[]);
   }
 
@@ -19826,13 +19829,11 @@
     method public synchronized void applyLocalizedPattern(java.lang.String);
     method public synchronized void applyPattern(java.lang.String);
     method public synchronized boolean areSignificantDigitsUsed();
-    method public synchronized boolean equals(java.lang.Object);
     method public java.lang.StringBuffer format(double, java.lang.StringBuffer, java.text.FieldPosition);
     method public java.lang.StringBuffer format(long, java.lang.StringBuffer, java.text.FieldPosition);
     method public java.lang.StringBuffer format(java.math.BigInteger, java.lang.StringBuffer, java.text.FieldPosition);
     method public java.lang.StringBuffer format(java.math.BigDecimal, java.lang.StringBuffer, java.text.FieldPosition);
     method public java.lang.StringBuffer format(android.icu.math.BigDecimal, java.lang.StringBuffer, java.text.FieldPosition);
-    method public synchronized android.icu.util.Currency getCurrency();
     method public synchronized android.icu.text.CurrencyPluralInfo getCurrencyPluralInfo();
     method public synchronized android.icu.util.Currency.CurrencyUsage getCurrencyUsage();
     method public synchronized android.icu.text.DecimalFormatSymbols getDecimalFormatSymbols();
@@ -19840,12 +19841,8 @@
     method public synchronized int getGroupingSize();
     method public synchronized java.math.MathContext getMathContext();
     method public synchronized android.icu.math.MathContext getMathContextICU();
-    method public synchronized int getMaximumFractionDigits();
-    method public synchronized int getMaximumIntegerDigits();
     method public synchronized int getMaximumSignificantDigits();
     method public synchronized byte getMinimumExponentDigits();
-    method public synchronized int getMinimumFractionDigits();
-    method public synchronized int getMinimumIntegerDigits();
     method public synchronized int getMinimumSignificantDigits();
     method public synchronized int getMultiplier();
     method public synchronized java.lang.String getNegativePrefix();
@@ -19856,19 +19853,13 @@
     method public synchronized java.lang.String getPositivePrefix();
     method public synchronized java.lang.String getPositiveSuffix();
     method public synchronized java.math.BigDecimal getRoundingIncrement();
-    method public synchronized int getRoundingMode();
     method public synchronized int getSecondaryGroupingSize();
-    method public synchronized int hashCode();
     method public synchronized boolean isDecimalPatternMatchRequired();
     method public synchronized boolean isDecimalSeparatorAlwaysShown();
     method public synchronized boolean isExponentSignAlwaysShown();
-    method public synchronized boolean isGroupingUsed();
     method public synchronized boolean isParseBigDecimal();
-    method public synchronized boolean isParseIntegerOnly();
-    method public synchronized boolean isParseStrict();
     method public synchronized boolean isScientificNotation();
     method public java.lang.Number parse(java.lang.String, java.text.ParsePosition);
-    method public synchronized void setCurrency(android.icu.util.Currency);
     method public synchronized void setCurrencyPluralInfo(android.icu.text.CurrencyPluralInfo);
     method public synchronized void setCurrencyUsage(android.icu.util.Currency.CurrencyUsage);
     method public synchronized void setDecimalFormatSymbols(android.icu.text.DecimalFormatSymbols);
@@ -19877,15 +19868,10 @@
     method public synchronized void setExponentSignAlwaysShown(boolean);
     method public synchronized void setFormatWidth(int);
     method public synchronized void setGroupingSize(int);
-    method public synchronized void setGroupingUsed(boolean);
     method public synchronized void setMathContext(java.math.MathContext);
     method public synchronized void setMathContextICU(android.icu.math.MathContext);
-    method public synchronized void setMaximumFractionDigits(int);
-    method public synchronized void setMaximumIntegerDigits(int);
     method public synchronized void setMaximumSignificantDigits(int);
     method public synchronized void setMinimumExponentDigits(byte);
-    method public synchronized void setMinimumFractionDigits(int);
-    method public synchronized void setMinimumIntegerDigits(int);
     method public synchronized void setMinimumSignificantDigits(int);
     method public synchronized void setMultiplier(int);
     method public synchronized void setNegativePrefix(java.lang.String);
@@ -19893,15 +19879,12 @@
     method public synchronized void setPadCharacter(char);
     method public synchronized void setPadPosition(int);
     method public synchronized void setParseBigDecimal(boolean);
-    method public synchronized void setParseIntegerOnly(boolean);
     method public deprecated void setParseMaxDigits(int);
-    method public synchronized void setParseStrict(boolean);
     method public synchronized void setPositivePrefix(java.lang.String);
     method public synchronized void setPositiveSuffix(java.lang.String);
     method public synchronized void setRoundingIncrement(java.math.BigDecimal);
     method public synchronized void setRoundingIncrement(android.icu.math.BigDecimal);
     method public synchronized void setRoundingIncrement(double);
-    method public synchronized void setRoundingMode(int);
     method public synchronized void setScientificNotation(boolean);
     method public synchronized void setSecondaryGroupingSize(int);
     method public synchronized void setSignificantDigitsUsed(boolean);
@@ -28076,7 +28059,6 @@
 
   public static final class IpSecManager.SecurityParameterIndex implements java.lang.AutoCloseable {
     method public void close();
-    method protected void finalize();
     method public int getSpi();
   }
 
diff --git a/api/test-current.txt b/api/test-current.txt
index 6f251e9..cee4789 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -484,6 +484,7 @@
     field public static final int detailSocialSummary = 16843428; // 0x10102a4
     field public static final int detailsElementBackground = 16843598; // 0x101034e
     field public static final int dial = 16843010; // 0x1010102
+    field public static final int dialogCornerRadius = 16844145; // 0x1010571
     field public static final int dialogIcon = 16843252; // 0x10101f4
     field public static final int dialogLayout = 16843255; // 0x10101f7
     field public static final int dialogMessage = 16843251; // 0x10101f3
@@ -3873,6 +3874,7 @@
     method public void resizeStack(int, android.graphics.Rect) throws java.lang.SecurityException;
     method public deprecated void restartPackage(java.lang.String);
     method public void setTaskWindowingMode(int, int, boolean) throws java.lang.SecurityException;
+    method public void setTaskWindowingModeSplitScreenPrimary(int, int, boolean, boolean, android.graphics.Rect) throws java.lang.SecurityException;
     method public static void setVrThread(int);
     method public void setWatchHeapLimit(long);
     method public static boolean supportsMultiWindow(android.content.Context);
@@ -3886,6 +3888,8 @@
     field public static final int MOVE_TASK_WITH_HOME = 1; // 0x1
     field public static final int RECENT_IGNORE_UNAVAILABLE = 2; // 0x2
     field public static final int RECENT_WITH_EXCLUDED = 1; // 0x1
+    field public static final int SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT = 1; // 0x1
+    field public static final int SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT = 0; // 0x0
   }
 
   public static class ActivityManager.AppTask {
@@ -12103,6 +12107,7 @@
     method public java.lang.String[] getColumnNames();
     method public int getCount();
     method public android.database.sqlite.SQLiteDatabase getDatabase();
+    method public void setFillWindowForwardOnly(boolean);
     method public void setSelectionArguments(java.lang.String[]);
   }
 
@@ -18412,13 +18417,11 @@
     method public synchronized void applyLocalizedPattern(java.lang.String);
     method public synchronized void applyPattern(java.lang.String);
     method public synchronized boolean areSignificantDigitsUsed();
-    method public synchronized boolean equals(java.lang.Object);
     method public java.lang.StringBuffer format(double, java.lang.StringBuffer, java.text.FieldPosition);
     method public java.lang.StringBuffer format(long, java.lang.StringBuffer, java.text.FieldPosition);
     method public java.lang.StringBuffer format(java.math.BigInteger, java.lang.StringBuffer, java.text.FieldPosition);
     method public java.lang.StringBuffer format(java.math.BigDecimal, java.lang.StringBuffer, java.text.FieldPosition);
     method public java.lang.StringBuffer format(android.icu.math.BigDecimal, java.lang.StringBuffer, java.text.FieldPosition);
-    method public synchronized android.icu.util.Currency getCurrency();
     method public synchronized android.icu.text.CurrencyPluralInfo getCurrencyPluralInfo();
     method public synchronized android.icu.util.Currency.CurrencyUsage getCurrencyUsage();
     method public synchronized android.icu.text.DecimalFormatSymbols getDecimalFormatSymbols();
@@ -18426,12 +18429,8 @@
     method public synchronized int getGroupingSize();
     method public synchronized java.math.MathContext getMathContext();
     method public synchronized android.icu.math.MathContext getMathContextICU();
-    method public synchronized int getMaximumFractionDigits();
-    method public synchronized int getMaximumIntegerDigits();
     method public synchronized int getMaximumSignificantDigits();
     method public synchronized byte getMinimumExponentDigits();
-    method public synchronized int getMinimumFractionDigits();
-    method public synchronized int getMinimumIntegerDigits();
     method public synchronized int getMinimumSignificantDigits();
     method public synchronized int getMultiplier();
     method public synchronized java.lang.String getNegativePrefix();
@@ -18442,19 +18441,13 @@
     method public synchronized java.lang.String getPositivePrefix();
     method public synchronized java.lang.String getPositiveSuffix();
     method public synchronized java.math.BigDecimal getRoundingIncrement();
-    method public synchronized int getRoundingMode();
     method public synchronized int getSecondaryGroupingSize();
-    method public synchronized int hashCode();
     method public synchronized boolean isDecimalPatternMatchRequired();
     method public synchronized boolean isDecimalSeparatorAlwaysShown();
     method public synchronized boolean isExponentSignAlwaysShown();
-    method public synchronized boolean isGroupingUsed();
     method public synchronized boolean isParseBigDecimal();
-    method public synchronized boolean isParseIntegerOnly();
-    method public synchronized boolean isParseStrict();
     method public synchronized boolean isScientificNotation();
     method public java.lang.Number parse(java.lang.String, java.text.ParsePosition);
-    method public synchronized void setCurrency(android.icu.util.Currency);
     method public synchronized void setCurrencyPluralInfo(android.icu.text.CurrencyPluralInfo);
     method public synchronized void setCurrencyUsage(android.icu.util.Currency.CurrencyUsage);
     method public synchronized void setDecimalFormatSymbols(android.icu.text.DecimalFormatSymbols);
@@ -18463,15 +18456,10 @@
     method public synchronized void setExponentSignAlwaysShown(boolean);
     method public synchronized void setFormatWidth(int);
     method public synchronized void setGroupingSize(int);
-    method public synchronized void setGroupingUsed(boolean);
     method public synchronized void setMathContext(java.math.MathContext);
     method public synchronized void setMathContextICU(android.icu.math.MathContext);
-    method public synchronized void setMaximumFractionDigits(int);
-    method public synchronized void setMaximumIntegerDigits(int);
     method public synchronized void setMaximumSignificantDigits(int);
     method public synchronized void setMinimumExponentDigits(byte);
-    method public synchronized void setMinimumFractionDigits(int);
-    method public synchronized void setMinimumIntegerDigits(int);
     method public synchronized void setMinimumSignificantDigits(int);
     method public synchronized void setMultiplier(int);
     method public synchronized void setNegativePrefix(java.lang.String);
@@ -18479,15 +18467,12 @@
     method public synchronized void setPadCharacter(char);
     method public synchronized void setPadPosition(int);
     method public synchronized void setParseBigDecimal(boolean);
-    method public synchronized void setParseIntegerOnly(boolean);
     method public deprecated void setParseMaxDigits(int);
-    method public synchronized void setParseStrict(boolean);
     method public synchronized void setPositivePrefix(java.lang.String);
     method public synchronized void setPositiveSuffix(java.lang.String);
     method public synchronized void setRoundingIncrement(java.math.BigDecimal);
     method public synchronized void setRoundingIncrement(android.icu.math.BigDecimal);
     method public synchronized void setRoundingIncrement(double);
-    method public synchronized void setRoundingMode(int);
     method public synchronized void setScientificNotation(boolean);
     method public synchronized void setSecondaryGroupingSize(int);
     method public synchronized void setSignificantDigitsUsed(boolean);
@@ -26034,7 +26019,6 @@
 
   public static final class IpSecManager.SecurityParameterIndex implements java.lang.AutoCloseable {
     method public void close();
-    method protected void finalize();
     method public int getSpi();
   }
 
@@ -41342,6 +41326,7 @@
   }
 
   public final class FileServiceInfo extends android.telephony.mbms.ServiceInfo implements android.os.Parcelable {
+    ctor public FileServiceInfo(java.util.Map<java.util.Locale, java.lang.String>, java.lang.String, java.util.List<java.util.Locale>, java.lang.String, java.util.Date, java.util.Date, java.util.List<android.telephony.mbms.FileInfo>);
     method public int describeContents();
     method public java.util.List<android.telephony.mbms.FileInfo> getFiles();
     method public void writeToParcel(android.os.Parcel, int);
@@ -41450,6 +41435,22 @@
 
 package android.telephony.mbms.vendor {
 
+  public class MbmsDownloadServiceBase extends android.os.Binder {
+    ctor public MbmsDownloadServiceBase();
+    method public int cancelDownload(android.telephony.mbms.DownloadRequest) throws android.os.RemoteException;
+    method public void dispose(int) throws android.os.RemoteException;
+    method public int download(android.telephony.mbms.DownloadRequest) throws android.os.RemoteException;
+    method public int getDownloadStatus(android.telephony.mbms.DownloadRequest, android.telephony.mbms.FileInfo) throws android.os.RemoteException;
+    method public int initialize(int, android.telephony.mbms.MbmsDownloadSessionCallback) throws android.os.RemoteException;
+    method public java.util.List<android.telephony.mbms.DownloadRequest> listPendingDownloads(int) throws android.os.RemoteException;
+    method public void onAppCallbackDied(int, int);
+    method public int registerStateCallback(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStateCallback) throws android.os.RemoteException;
+    method public int requestUpdateFileServices(int, java.util.List<java.lang.String>) throws android.os.RemoteException;
+    method public int resetDownloadKnowledge(android.telephony.mbms.DownloadRequest) throws android.os.RemoteException;
+    method public int setTempFileRootDirectory(int, java.lang.String) throws android.os.RemoteException;
+    method public int unregisterStateCallback(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStateCallback) throws android.os.RemoteException;
+  }
+
   public class MbmsStreamingServiceBase extends android.os.Binder {
     ctor public MbmsStreamingServiceBase();
     method public void dispose(int) throws android.os.RemoteException;
@@ -44980,25 +44981,25 @@
     field public static final long FIELD_COUNT_UNKNOWN = 0L; // 0x0L
     field public static final int FIELD_ID_MASK = -8; // 0xfffffff8
     field public static final int FIELD_ID_SHIFT = 3; // 0x3
-    field public static final long FIELD_TYPE_BOOL = 55834574848L; // 0xd00000000L
-    field public static final long FIELD_TYPE_BYTES = 64424509440L; // 0xf00000000L
+    field public static final long FIELD_TYPE_BOOL = 34359738368L; // 0x800000000L
+    field public static final long FIELD_TYPE_BYTES = 51539607552L; // 0xc00000000L
     field public static final long FIELD_TYPE_DOUBLE = 4294967296L; // 0x100000000L
-    field public static final long FIELD_TYPE_ENUM = 68719476736L; // 0x1000000000L
-    field public static final long FIELD_TYPE_FIXED32 = 38654705664L; // 0x900000000L
-    field public static final long FIELD_TYPE_FIXED64 = 42949672960L; // 0xa00000000L
+    field public static final long FIELD_TYPE_ENUM = 60129542144L; // 0xe00000000L
+    field public static final long FIELD_TYPE_FIXED32 = 30064771072L; // 0x700000000L
+    field public static final long FIELD_TYPE_FIXED64 = 25769803776L; // 0x600000000L
     field public static final long FIELD_TYPE_FLOAT = 8589934592L; // 0x200000000L
-    field public static final long FIELD_TYPE_INT32 = 12884901888L; // 0x300000000L
-    field public static final long FIELD_TYPE_INT64 = 17179869184L; // 0x400000000L
+    field public static final long FIELD_TYPE_INT32 = 21474836480L; // 0x500000000L
+    field public static final long FIELD_TYPE_INT64 = 12884901888L; // 0x300000000L
     field public static final long FIELD_TYPE_MASK = 1095216660480L; // 0xff00000000L
-    field public static final long FIELD_TYPE_OBJECT = 73014444032L; // 0x1100000000L
-    field public static final long FIELD_TYPE_SFIXED32 = 47244640256L; // 0xb00000000L
-    field public static final long FIELD_TYPE_SFIXED64 = 51539607552L; // 0xc00000000L
+    field public static final long FIELD_TYPE_MESSAGE = 47244640256L; // 0xb00000000L
+    field public static final long FIELD_TYPE_SFIXED32 = 64424509440L; // 0xf00000000L
+    field public static final long FIELD_TYPE_SFIXED64 = 68719476736L; // 0x1000000000L
     field public static final int FIELD_TYPE_SHIFT = 32; // 0x20
-    field public static final long FIELD_TYPE_SINT32 = 30064771072L; // 0x700000000L
-    field public static final long FIELD_TYPE_SINT64 = 34359738368L; // 0x800000000L
-    field public static final long FIELD_TYPE_STRING = 60129542144L; // 0xe00000000L
-    field public static final long FIELD_TYPE_UINT32 = 21474836480L; // 0x500000000L
-    field public static final long FIELD_TYPE_UINT64 = 25769803776L; // 0x600000000L
+    field public static final long FIELD_TYPE_SINT32 = 73014444032L; // 0x1100000000L
+    field public static final long FIELD_TYPE_SINT64 = 77309411328L; // 0x1200000000L
+    field public static final long FIELD_TYPE_STRING = 38654705664L; // 0x900000000L
+    field public static final long FIELD_TYPE_UINT32 = 55834574848L; // 0xd00000000L
+    field public static final long FIELD_TYPE_UINT64 = 17179869184L; // 0x400000000L
     field public static final long FIELD_TYPE_UNKNOWN = 0L; // 0x0L
     field public static final java.lang.String TAG = "ProtoOutputStream";
     field public static final int WIRE_TYPE_END_GROUP = 4; // 0x4
diff --git a/cmds/am/proto/instrumentation_data.proto b/cmds/am/proto/instrumentation_data.proto
index 12a18a2..8e29f96 100644
--- a/cmds/am/proto/instrumentation_data.proto
+++ b/cmds/am/proto/instrumentation_data.proto
@@ -28,6 +28,7 @@
     optional double value_double = 5;
     optional sint64 value_long = 6;
     optional ResultsBundle value_bundle = 7;
+    optional bytes value_bytes = 8;
 }
 
 message ResultsBundle {
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 79e7fac..813335a 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -160,7 +160,11 @@
             } else if (opt.equals("-r")) {
                 instrument.rawMode = true;
             } else if (opt.equals("-m")) {
-                instrument.proto = true;
+                instrument.protoStd = true;
+            } else if (opt.equals("-f")) {
+                instrument.protoFile = true;
+                if (peekNextArg() != null && !peekNextArg().startsWith("-"))
+                    instrument.logPath = nextArg();
             } else if (opt.equals("-e")) {
                 final String argKey = nextArgRequired();
                 final String argValue = nextArgRequired();
diff --git a/cmds/am/src/com/android/commands/am/Instrument.java b/cmds/am/src/com/android/commands/am/Instrument.java
index b69ef1c..93b9f58 100644
--- a/cmds/am/src/com/android/commands/am/Instrument.java
+++ b/cmds/am/src/com/android/commands/am/Instrument.java
@@ -25,23 +25,32 @@
 import android.content.pm.InstrumentationInfo;
 import android.os.Build;
 import android.os.Bundle;
+import android.os.Environment;
 import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.util.AndroidException;
 import android.util.proto.ProtoOutputStream;
 import android.view.IWindowManager;
 
+import java.io.File;
+import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.OutputStream;
+import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Date;
 import java.util.List;
+import java.util.Locale;
 
 
 /**
  * Runs the am instrument command
  */
 public class Instrument {
+    public static final String DEFAULT_LOG_DIR = "instrument-logs";
+
     private final IActivityManager mAm;
     private final IPackageManager mPm;
     private final IWindowManager mWm;
@@ -50,7 +59,9 @@
     public String profileFile = null;
     public boolean wait = false;
     public boolean rawMode = false;
-    public boolean proto = false;
+    boolean protoStd = false;  // write proto to stdout
+    boolean protoFile = false;  // write proto to a file
+    String logPath = null;
     public boolean noWindowAnimation = false;
     public String abi = null;
     public int userId = UserHandle.USER_CURRENT;
@@ -178,18 +189,49 @@
      * Printer for the protobuf based status reporting.
      */
     private class ProtoStatusReporter implements StatusReporter {
+
+        private File mLog;
+
+        ProtoStatusReporter() {
+            if (protoFile) {
+                if (logPath == null) {
+                    File logDir = new File(Environment.getLegacyExternalStorageDirectory(),
+                            DEFAULT_LOG_DIR);
+                    if (!logDir.exists() && !logDir.mkdirs()) {
+                        System.err.format("Unable to create log directory: %s\n",
+                                logDir.getAbsolutePath());
+                        protoFile = false;
+                        return;
+                    }
+                    SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd-hhmmss-SSS", Locale.US);
+                    String fileName = String.format("log-%s.instrumentation_data_proto",
+                            format.format(new Date()));
+                    mLog = new File(logDir, fileName);
+                } else {
+                    mLog = new File(Environment.getLegacyExternalStorageDirectory(), logPath);
+                    File logDir = mLog.getParentFile();
+                    if (!logDir.exists() && !logDir.mkdirs()) {
+                        System.err.format("Unable to create log directory: %s\n",
+                                logDir.getAbsolutePath());
+                        protoFile = false;
+                        return;
+                    }
+                }
+                if (mLog.exists()) mLog.delete();
+            }
+        }
+
         @Override
         public void onInstrumentationStatusLocked(ComponentName name, int resultCode,
                 Bundle results) {
             final ProtoOutputStream proto = new ProtoOutputStream();
 
-            final long token = proto.startRepeatedObject(InstrumentationData.Session.TEST_STATUS);
-
-            proto.writeSInt32(InstrumentationData.TestStatus.RESULT_CODE, resultCode);
+            final long token = proto.start(InstrumentationData.Session.TEST_STATUS);
+            proto.write(InstrumentationData.TestStatus.RESULT_CODE, resultCode);
             writeBundle(proto, InstrumentationData.TestStatus.RESULTS, results);
+            proto.end(token);
 
-            proto.endRepeatedObject(token);
-            writeProtoToStdout(proto);
+            outputProto(proto);
         }
 
         @Override
@@ -197,80 +239,87 @@
                 Bundle results) {
             final ProtoOutputStream proto = new ProtoOutputStream();
 
-            final long token = proto.startObject(InstrumentationData.Session.SESSION_STATUS);
-
-            proto.writeEnum(InstrumentationData.SessionStatus.STATUS_CODE,
+            final long token = proto.start(InstrumentationData.Session.SESSION_STATUS);
+            proto.write(InstrumentationData.SessionStatus.STATUS_CODE,
                     InstrumentationData.SESSION_FINISHED);
-            proto.writeSInt32(InstrumentationData.SessionStatus.RESULT_CODE, resultCode);
+            proto.write(InstrumentationData.SessionStatus.RESULT_CODE, resultCode);
             writeBundle(proto, InstrumentationData.SessionStatus.RESULTS, results);
+            proto.end(token);
 
-            proto.endObject(token);
-            writeProtoToStdout(proto);
+            outputProto(proto);
         }
 
         @Override
         public void onError(String errorText, boolean commandError) {
             final ProtoOutputStream proto = new ProtoOutputStream();
 
-            final long token = proto.startObject(InstrumentationData.Session.SESSION_STATUS);
-
-            proto.writeEnum(InstrumentationData.SessionStatus.STATUS_CODE,
+            final long token = proto.start(InstrumentationData.Session.SESSION_STATUS);
+            proto.write(InstrumentationData.SessionStatus.STATUS_CODE,
                     InstrumentationData.SESSION_ABORTED);
-            proto.writeString(InstrumentationData.SessionStatus.ERROR_TEXT, errorText);
+            proto.write(InstrumentationData.SessionStatus.ERROR_TEXT, errorText);
+            proto.end(token);
 
-            proto.endObject(token);
-            writeProtoToStdout(proto);
+            outputProto(proto);
         }
 
         private void writeBundle(ProtoOutputStream proto, long fieldId, Bundle bundle) {
-            final long bundleToken = proto.startObject(fieldId);
+            final long bundleToken = proto.start(fieldId);
 
             for (final String key: sorted(bundle.keySet())) {
                 final long entryToken = proto.startRepeatedObject(
                         InstrumentationData.ResultsBundle.ENTRIES);
 
-                proto.writeString(InstrumentationData.ResultsBundleEntry.KEY, key);
+                proto.write(InstrumentationData.ResultsBundleEntry.KEY, key);
 
                 final Object val = bundle.get(key);
                 if (val instanceof String) {
-                    proto.writeString(InstrumentationData.ResultsBundleEntry.VALUE_STRING,
+                    proto.write(InstrumentationData.ResultsBundleEntry.VALUE_STRING,
                             (String)val);
                 } else if (val instanceof Byte) {
-                    proto.writeSInt32(InstrumentationData.ResultsBundleEntry.VALUE_INT,
+                    proto.write(InstrumentationData.ResultsBundleEntry.VALUE_INT,
                             ((Byte)val).intValue());
                 } else if (val instanceof Double) {
-                    proto.writeDouble(InstrumentationData.ResultsBundleEntry.VALUE_DOUBLE,
-                            ((Double)val).doubleValue());
+                    proto.write(InstrumentationData.ResultsBundleEntry.VALUE_DOUBLE, (double)val);
                 } else if (val instanceof Float) {
-                    proto.writeFloat(InstrumentationData.ResultsBundleEntry.VALUE_FLOAT,
-                            ((Float)val).floatValue());
+                    proto.write(InstrumentationData.ResultsBundleEntry.VALUE_FLOAT, (float)val);
                 } else if (val instanceof Integer) {
-                    proto.writeSInt32(InstrumentationData.ResultsBundleEntry.VALUE_INT,
-                            ((Integer)val).intValue());
+                    proto.write(InstrumentationData.ResultsBundleEntry.VALUE_INT, (int)val);
                 } else if (val instanceof Long) {
-                    proto.writeSInt64(InstrumentationData.ResultsBundleEntry.VALUE_LONG,
-                            ((Long)val).longValue());
+                    proto.write(InstrumentationData.ResultsBundleEntry.VALUE_LONG, (long)val);
                 } else if (val instanceof Short) {
-                    proto.writeSInt32(InstrumentationData.ResultsBundleEntry.VALUE_INT,
-                            ((Short)val).intValue());
+                    proto.write(InstrumentationData.ResultsBundleEntry.VALUE_INT, (short)val);
                 } else if (val instanceof Bundle) {
                     writeBundle(proto, InstrumentationData.ResultsBundleEntry.VALUE_BUNDLE,
                             (Bundle)val);
+                } else if (val instanceof byte[]) {
+                    proto.write(InstrumentationData.ResultsBundleEntry.VALUE_BYTES, (byte[])val);
                 }
 
-                proto.endRepeatedObject(entryToken);
+                proto.end(entryToken);
             }
 
-            proto.endObject(bundleToken);
+            proto.end(bundleToken);
         }
 
-        private void writeProtoToStdout(ProtoOutputStream proto) {
-            try {
-                System.out.write(proto.getBytes());
-                System.out.flush();
-            } catch (IOException ex) {
-                System.err.println("Error writing finished response: ");
-                ex.printStackTrace(System.err);
+        private void outputProto(ProtoOutputStream proto) {
+            byte[] out = proto.getBytes();
+            if (protoStd) {
+                try {
+                    System.out.write(out);
+                    System.out.flush();
+                } catch (IOException ex) {
+                    System.err.println("Error writing finished response: ");
+                    ex.printStackTrace(System.err);
+                }
+            }
+            if (protoFile) {
+                try (OutputStream os = new FileOutputStream(mLog, true)) {
+                    os.write(proto.getBytes());
+                    os.flush();
+                } catch (IOException ex) {
+                    System.err.format("Cannot write to %s:\n", mLog.getAbsolutePath());
+                    ex.printStackTrace();
+                }
             }
         }
     }
@@ -374,7 +423,7 @@
 
         try {
             // Choose which output we will do.
-            if (proto) {
+            if (protoFile || protoStd) {
                 reporter = new ProtoStatusReporter();
             } else if (wait) {
                 reporter = new TextStatusReporter(rawMode);
@@ -396,7 +445,7 @@
                 mWm.setAnimationScale(2, 0.0f);
             }
 
-            // Figure out which component we are tring to do.
+            // Figure out which component we are trying to do.
             final ComponentName cn = parseComponentName(componentNameArg);
 
             // Choose an ABI if necessary
diff --git a/cmds/incidentd/src/PrivacyBuffer.cpp b/cmds/incidentd/src/PrivacyBuffer.cpp
index d926ea7..77ae1a7 100644
--- a/cmds/incidentd/src/PrivacyBuffer.cpp
+++ b/cmds/incidentd/src/PrivacyBuffer.cpp
@@ -87,12 +87,12 @@
     // current field is message type and its sub-fields have extra privacy policies
     uint32_t msgSize = mData.readRawVarint();
     EncodedBuffer::Pointer start = mData.rp()->copy();
+    long long token = mProto.start(policy->EncodedFieldId());
     while (mData.rp()->pos() - start.pos() != msgSize) {
-        long long token = mProto.start(policy->EncodedFieldId());
         status_t err = stripField(policy, spec);
         if (err != NO_ERROR) return err;
-        mProto.end(token);
     }
+    mProto.end(token);
     return NO_ERROR;
 }
 
diff --git a/cmds/incidentd/src/section_list.h b/cmds/incidentd/src/section_list.h
index da82b00..dfd2312 100644
--- a/cmds/incidentd/src/section_list.h
+++ b/cmds/incidentd/src/section_list.h
@@ -30,7 +30,7 @@
  * This is the mapping of section IDs to each section's privacy policy.
  * The section IDs are guaranteed in ascending order, not NULL-terminated since size is provided.
  */
-extern const Privacy* PRIVACY_POLICY_LIST[];
+extern const Privacy** PRIVACY_POLICY_LIST;
 
 extern const int PRIVACY_POLICY_COUNT;
 
diff --git a/cmds/incidentd/tests/PrivacyBuffer_test.cpp b/cmds/incidentd/tests/PrivacyBuffer_test.cpp
index 8f6e355..84a2a82 100644
--- a/cmds/incidentd/tests/PrivacyBuffer_test.cpp
+++ b/cmds/incidentd/tests/PrivacyBuffer_test.cpp
@@ -260,3 +260,13 @@
     PrivacySpec spec;
     ASSERT_EQ(privacyBuf.strip(spec), BAD_VALUE);
 }
+
+TEST_F(PrivacyBufferTest, SelfRecursionMessage) {
+    string input = "\x2a\"" + VARINT_FIELD_1 + STRING_FIELD_2 + MESSAGE_FIELD_5;
+    writeToFdBuffer(input);
+    Privacy* field5 = create_message_privacy(5, NULL);
+    Privacy* list[] = { create_privacy(1, OTHER_TYPE, LOCAL), field5, NULL };
+    field5->children = list;
+    string expected = "\x2a\x1c" + STRING_FIELD_2 + "\x2a\xd" + STRING_FIELD_2;
+    assertStrip(EXPLICIT, expected, field5);
+}
diff --git a/cmds/incidentd/tests/section_list.cpp b/cmds/incidentd/tests/section_list.cpp
index e47b61cf..4acc429 100644
--- a/cmds/incidentd/tests/section_list.cpp
+++ b/cmds/incidentd/tests/section_list.cpp
@@ -20,9 +20,11 @@
 Privacy field_0 { 0, 11, list, EXPLICIT, NULL };
 Privacy field_1 { 1, 9, NULL, AUTOMATIC, NULL };
 
-const Privacy* PRIVACY_POLICY_LIST[] = {
+Privacy* final_list[] = {
     &field_0,
     &field_1
 };
 
-const int PRIVACY_POLICY_COUNT = 2;
\ No newline at end of file
+const Privacy** PRIVACY_POLICY_LIST = const_cast<const Privacy**>(final_list);
+
+const int PRIVACY_POLICY_COUNT = 2;
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index 58ba42f..54ade35 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -44,6 +44,7 @@
     src/metrics/DurationMetricProducer.cpp \
     src/metrics/duration_helper/OringDurationTracker.cpp \
     src/metrics/duration_helper/MaxDurationTracker.cpp \
+    src/metrics/ValueMetricProducer.cpp \
     src/metrics/MetricsManager.cpp \
     src/metrics/metrics_manager_util.cpp \
     src/packages/UidMap.cpp \
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index a856a27..edb1a0f 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -65,7 +65,6 @@
 StatsService::StatsService(const sp<Looper>& handlerLooper)
     : mAnomalyMonitor(new AnomalyMonitor(2))  // TODO: Put this comment somewhere better
 {
-    mStatsPullerManager = new StatsPullerManager();
     mUidMap = new UidMap();
     mConfigManager = new ConfigManager();
     mProcessor = new StatsLogProcessor(mUidMap, [this](const vector<uint8_t>& log) {
@@ -374,7 +373,7 @@
 
 status_t StatsService::cmd_print_pulled_metrics(FILE* out, const Vector<String8>& args) {
     int s = atoi(args[1].c_str());
-    auto stats = mStatsPullerManager->Pull(s);
+    auto stats = m_stats_puller_manager.Pull(s, time(nullptr));
     for (const auto& it : stats) {
         fprintf(out, "Pull from %d: %s\n", s, it->ToString().c_str());
     }
@@ -441,8 +440,9 @@
                                          "Only system uid can call informPollAlarmFired");
     }
 
+    m_stats_puller_manager.OnAlarmFired();
+
     if (DEBUG) ALOGD("StatsService::informPollAlarmFired succeeded");
-    // TODO: determine what services to poll and poll (or ask StatsCompanionService to poll) them.
 
     return Status::ok();
 }
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index 7f04658..3930d31 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -27,7 +27,6 @@
 #include <android/os/IStatsCallbacks.h>
 #include <android/os/IStatsCompanionService.h>
 #include <binder/IResultReceiver.h>
-#include <binder/IShellCallback.h>
 #include <utils/Looper.h>
 
 #include <deque>
@@ -158,7 +157,7 @@
     /**
      * Fetches external metrics.
      */
-    sp<StatsPullerManager> mStatsPullerManager;
+    StatsPullerManager& m_stats_puller_manager = StatsPullerManager::GetInstance();
 
     /**
      * Tracks the configurations that have been passed to statsd.
diff --git a/cmds/statsd/src/config/ConfigManager.cpp b/cmds/statsd/src/config/ConfigManager.cpp
index e3ccb06..8812719 100644
--- a/cmds/statsd/src/config/ConfigManager.cpp
+++ b/cmds/statsd/src/config/ConfigManager.cpp
@@ -139,6 +139,9 @@
     int UID_PROCESS_STATE_TAG_ID = 27;
     int UID_PROCESS_STATE_UID_KEY = 1;
 
+    int KERNEL_WAKELOCK_TAG_ID = 41;
+    int KERNEL_WAKELOCK_NAME_KEY = 4;
+
     // Count Screen ON events.
     CountMetric* metric = config.add_count_metric();
     metric->set_metric_id(1);
@@ -228,6 +231,17 @@
     durationMetric->set_type(DurationMetric_AggregationType_DURATION_SUM);
     durationMetric->set_what("SCREEN_IS_ON");
 
+    // Value metric to count KERNEL_WAKELOCK when screen turned on
+    ValueMetric* valueMetric = config.add_value_metric();
+    valueMetric->set_metric_id(6);
+    valueMetric->set_what("KERNEL_WAKELOCK");
+    valueMetric->set_value_field(1);
+    valueMetric->set_condition("SCREEN_IS_ON");
+    keyMatcher = valueMetric->add_dimension();
+    keyMatcher->set_key(KERNEL_WAKELOCK_NAME_KEY);
+    // This is for testing easier. We should never set bucket size this small.
+    valueMetric->mutable_bucket()->set_bucket_size_millis(60 * 1000L);
+
     // Add an EventMetric to log process state change events.
     EventMetric* eventMetric = config.add_event_metric();
     eventMetric->set_metric_id(9);
diff --git a/cmds/statsd/src/external/KernelWakelockPuller.cpp b/cmds/statsd/src/external/KernelWakelockPuller.cpp
index ee072f8..00259a8 100644
--- a/cmds/statsd/src/external/KernelWakelockPuller.cpp
+++ b/cmds/statsd/src/external/KernelWakelockPuller.cpp
@@ -14,14 +14,14 @@
  * limitations under the License.
  */
 
+#define DEBUG true
 #include "Log.h"
 
 #include <android/os/IStatsCompanionService.h>
 #include <binder/IPCThreadState.h>
 #include <private/android_filesystem_config.h>
+#include "KernelWakelockPuller.h"
 #include "StatsService.h"
-#include "external/KernelWakelockPuller.h"
-#include "external/StatsPuller.h"
 
 using namespace android;
 using namespace android::base;
@@ -33,11 +33,11 @@
 namespace os {
 namespace statsd {
 
-const int KernelWakelockPuller::PULL_CODE_KERNEL_WAKELOCKS = 20;
+const int KernelWakelockPuller::PULL_CODE_KERNEL_WAKELOCKS = 1004;
 
 // The reading and parsing are implemented in Java. It is not difficult to port over. But for now
 // let StatsCompanionService handle that and send the data back.
-vector<StatsLogEventWrapper> KernelWakelockPuller::pull() {
+vector<StatsLogEventWrapper> KernelWakelockPuller::Pull() {
     sp<IStatsCompanionService> statsCompanion = StatsService::getStatsCompanionService();
     vector<StatsLogEventWrapper> returned_value;
     if (statsCompanion != NULL) {
diff --git a/cmds/statsd/src/external/KernelWakelockPuller.h b/cmds/statsd/src/external/KernelWakelockPuller.h
index c12806c..cc8059d 100644
--- a/cmds/statsd/src/external/KernelWakelockPuller.h
+++ b/cmds/statsd/src/external/KernelWakelockPuller.h
@@ -14,11 +14,10 @@
  * limitations under the License.
  */
 
-#ifndef STATSD_KERNELWAKELOCKPULLER_H
-#define STATSD_KERNELWAKELOCKPULLER_H
+#pragma once
 
 #include <utils/String16.h>
-#include "external/StatsPuller.h"
+#include "StatsPuller.h"
 
 namespace android {
 namespace os {
@@ -29,11 +28,9 @@
     // a number of stats need to be pulled from StatsCompanionService
     //
     const static int PULL_CODE_KERNEL_WAKELOCKS;
-    vector<StatsLogEventWrapper> pull() override;
+    vector<StatsLogEventWrapper> Pull() override;
 };
 
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
-
-#endif  // STATSD_KERNELWAKELOCKPULLER_H
diff --git a/cmds/statsd/src/external/PullDataReceiver.h b/cmds/statsd/src/external/PullDataReceiver.h
new file mode 100644
index 0000000..0d505cb
--- /dev/null
+++ b/cmds/statsd/src/external/PullDataReceiver.h
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#include <utils/String16.h>
+#include <unordered_map>
+#include <utils/RefBase.h>
+#include "StatsPuller.h"
+#include "logd/LogEvent.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+class PullDataReceiver : virtual public RefBase{
+ public:
+  virtual ~PullDataReceiver() {}
+  virtual void onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& data) = 0;
+};
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
\ No newline at end of file
diff --git a/cmds/statsd/src/external/StatsPuller.h b/cmds/statsd/src/external/StatsPuller.h
index 6655629..774e7f0 100644
--- a/cmds/statsd/src/external/StatsPuller.h
+++ b/cmds/statsd/src/external/StatsPuller.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef STATSD_STATSPULLER_H
-#define STATSD_STATSPULLER_H
+#pragma once
 
 #include <android/os/StatsLogEventWrapper.h>
 #include <utils/String16.h>
@@ -32,11 +31,9 @@
 public:
     virtual ~StatsPuller(){};
 
-    virtual vector<StatsLogEventWrapper> pull() = 0;
+    virtual vector<StatsLogEventWrapper> Pull() = 0;
 };
 
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
-
-#endif  // STATSD_STATSPULLER_H
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index 7f554d3..f45cb1c 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -18,44 +18,58 @@
 #include "Log.h"
 
 #include <android/os/IStatsCompanionService.h>
-#include "KernelWakelockPuller.h"
-#include "StatsService.h"
-#include "external/StatsPullerManager.h"
-#include "logd/LogEvent.h"
 #include <cutils/log.h>
 #include <algorithm>
+#include <climits>
+#include "KernelWakelockPuller.h"
+#include "StatsPullerManager.h"
+#include "StatsService.h"
+#include "logd/LogEvent.h"
 
 #include <iostream>
 
-using namespace android;
+using std::string;
+using std::vector;
 
 namespace android {
 namespace os {
 namespace statsd {
 
-const int StatsPullerManager::KERNEL_WAKELOCKS = 1;
+const int kernel_wakelock = 1;
+const unordered_map<string, int> StatsPullerManager::kPullCodes({{"KERNEL_WAKELOCK",
+                                                                  kernel_wakelock}});
 
-StatsPullerManager::StatsPullerManager() {
-    mStatsPullers.insert(
-            {static_cast<int>(KERNEL_WAKELOCKS), std::make_unique<KernelWakelockPuller>()});
+StatsPullerManager::StatsPullerManager()
+    : mCurrentPullingInterval(LONG_MAX), mPullStartTimeMs(get_pull_start_time_ms()) {
+    mPullers.insert({kernel_wakelock, make_unique<KernelWakelockPuller>()});
+    mStatsCompanionService = get_stats_companion_service();
+    if (mStatsCompanionService != nullptr) {
+        mStatsCompanionService->cancelPullingAlarms();
+    } else {
+        VLOG("Failed to update pulling interval");
+    }
 }
 
-vector<std::shared_ptr<LogEvent>> StatsPullerManager::Pull(int pullCode) {
+static const int log_msg_header_size = 28;
+
+vector<shared_ptr<LogEvent>> StatsPullerManager::Pull(int pullCode, uint64_t timestampSec) {
     if (DEBUG) ALOGD("Initiating pulling %d", pullCode);
 
-    vector<std::shared_ptr<LogEvent>> ret;
-    if (mStatsPullers.find(pullCode) != mStatsPullers.end()) {
-        vector<StatsLogEventWrapper> outputs = (mStatsPullers.find(pullCode)->second)->pull();
+    vector<shared_ptr<LogEvent>> ret;
+    auto itr = mPullers.find(pullCode);
+    if (itr != mPullers.end()) {
+        vector<StatsLogEventWrapper> outputs = itr->second->Pull();
         for (const StatsLogEventWrapper& it : outputs) {
             log_msg tmp;
+            tmp.entry_v1.sec = timestampSec;
+            tmp.entry_v1.nsec = 0;
             tmp.entry_v1.len = it.bytes.size();
             // Manually set the header size to 28 bytes to match the pushed log events.
-            tmp.entry.hdr_size = 28;
+            tmp.entry.hdr_size = log_msg_header_size;
             // And set the received bytes starting after the 28 bytes reserved for header.
-            std::copy(it.bytes.begin(), it.bytes.end(), tmp.buf + 28);
-            std::shared_ptr<LogEvent> evt = std::make_shared<LogEvent>(tmp);
+            copy(it.bytes.begin(), it.bytes.end(), tmp.buf + log_msg_header_size);
+            shared_ptr<LogEvent> evt = make_shared<LogEvent>(tmp);
             ret.push_back(evt);
-            // ret.emplace_back(tmp);
         }
         return ret;
     } else {
@@ -64,6 +78,112 @@
     }
 }
 
+sp<IStatsCompanionService> StatsPullerManager::get_stats_companion_service() {
+    sp<IStatsCompanionService> statsCompanion = nullptr;
+    // Get statscompanion service from service manager
+    const sp<IServiceManager> sm(defaultServiceManager());
+    if (sm != nullptr) {
+        const String16 name("statscompanion");
+        statsCompanion = interface_cast<IStatsCompanionService>(sm->checkService(name));
+        if (statsCompanion == nullptr) {
+            ALOGW("statscompanion service unavailable!");
+            return nullptr;
+        }
+    }
+    return statsCompanion;
+}
+
+StatsPullerManager& StatsPullerManager::GetInstance() {
+    static StatsPullerManager instance;
+    return instance;
+}
+
+int StatsPullerManager::GetPullCode(string atomName) {
+    if (kPullCodes.find(atomName) != kPullCodes.end()) {
+        return kPullCodes.find(atomName)->second;
+    } else {
+        return -1;
+    }
+}
+
+long StatsPullerManager::get_pull_start_time_ms() {
+    // TODO: limit and align pull intervals to 10min boundaries if this turns out to be a problem
+    return time(nullptr) * 1000;
+}
+
+void StatsPullerManager::RegisterReceiver(int pullCode, sp<PullDataReceiver> receiver, long intervalMs) {
+    AutoMutex _l(mReceiversLock);
+    vector<ReceiverInfo>& receivers = mReceivers[pullCode];
+    for (auto it = receivers.begin(); it != receivers.end(); it++) {
+        if (it->receiver.get() == receiver.get()) {
+            VLOG("Receiver already registered of %d", (int)receivers.size());
+            return;
+        }
+    }
+    ReceiverInfo receiverInfo;
+    receiverInfo.receiver = receiver;
+    receiverInfo.timeInfo.first = intervalMs;
+    receivers.push_back(receiverInfo);
+
+    // There is only one alarm for all pulled events. So only set it to the smallest denom.
+    if (intervalMs < mCurrentPullingInterval) {
+        VLOG("Updating pulling interval %ld", intervalMs);
+        mCurrentPullingInterval = intervalMs;
+        if (mStatsCompanionService != nullptr) {
+            mStatsCompanionService->setPullingAlarms(mPullStartTimeMs, mCurrentPullingInterval);
+        } else {
+            VLOG("Failed to update pulling interval");
+        }
+    }
+    VLOG("Puller for pullcode %d registered of %d", pullCode, (int)receivers.size());
+}
+
+void StatsPullerManager::UnRegisterReceiver(int pullCode, sp<PullDataReceiver> receiver) {
+    AutoMutex _l(mReceiversLock);
+    if (mReceivers.find(pullCode) == mReceivers.end()) {
+        VLOG("Unknown pull code or no receivers: %d", pullCode);
+        return;
+    }
+    auto& receivers = mReceivers.find(pullCode)->second;
+    for (auto it = receivers.begin(); it != receivers.end(); it++) {
+        if (receiver.get() == it->receiver.get()) {
+            receivers.erase(it);
+            VLOG("Puller for pullcode %d unregistered of %d", pullCode, (int)receivers.size());
+            return;
+        }
+    }
+}
+
+void StatsPullerManager::OnAlarmFired() {
+    AutoMutex _l(mReceiversLock);
+
+    uint64_t currentTimeMs = time(nullptr) * 1000;
+
+    vector<pair<int, vector<ReceiverInfo*>>> needToPull =
+            vector<pair<int, vector<ReceiverInfo*>>>();
+    for (auto& pair : mReceivers) {
+        vector<ReceiverInfo*> receivers = vector<ReceiverInfo*>();
+        if (pair.second.size() != 0){
+            for(auto& receiverInfo : pair.second) {
+                if (receiverInfo.timeInfo.first + receiverInfo.timeInfo.second > currentTimeMs) {
+                    receivers.push_back(&receiverInfo);
+                }
+            }
+            if (receivers.size() > 0) {
+                needToPull.push_back(make_pair(pair.first, receivers));
+            }
+        }
+    }
+
+    for (const auto& pullInfo : needToPull) {
+        const vector<shared_ptr<LogEvent>>& data = Pull(pullInfo.first, currentTimeMs/1000);
+        for(const auto& receiverInfo : pullInfo.second) {
+            receiverInfo->receiver->onDataPulled(data);
+            receiverInfo->timeInfo.second = currentTimeMs;
+        }
+    }
+}
+
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
diff --git a/cmds/statsd/src/external/StatsPullerManager.h b/cmds/statsd/src/external/StatsPullerManager.h
index e46aec1..e599b69 100644
--- a/cmds/statsd/src/external/StatsPullerManager.h
+++ b/cmds/statsd/src/external/StatsPullerManager.h
@@ -14,38 +14,79 @@
  * limitations under the License.
  */
 
-#ifndef STATSD_STATSPULLERMANAGER_H
-#define STATSD_STATSPULLERMANAGER_H
+#pragma once
 
+#include <android/os/IStatsCompanionService.h>
+#include <binder/IServiceManager.h>
+#include <utils/RefBase.h>
 #include <utils/String16.h>
+#include <utils/String8.h>
+#include <utils/threads.h>
+#include <string>
 #include <unordered_map>
-#include "external/StatsPuller.h"
+#include <vector>
+#include "PullDataReceiver.h"
+#include "StatsPuller.h"
 #include "logd/LogEvent.h"
-#include "matchers/matcher_util.h"
 
 namespace android {
 namespace os {
 namespace statsd {
 
-const static int KERNEL_WAKELOCKS = 1;
-
 class StatsPullerManager : public virtual RefBase {
 public:
-    // Enums of pulled data types (pullCodes)
-    // These values must be kept in sync with com/android/server/stats/StatsCompanionService.java.
-    // TODO: pull the constant from stats_events.proto instead
-    const static int KERNEL_WAKELOCKS;
-    StatsPullerManager();
+    static StatsPullerManager& GetInstance();
+
+    void RegisterReceiver(int pullCode, sp<PullDataReceiver> receiver, long intervalMs);
+
+    void UnRegisterReceiver(int pullCode, sp<PullDataReceiver> receiver);
 
     // We return a vector of shared_ptr since LogEvent's copy constructor is not available.
-    vector<std::shared_ptr<LogEvent>> Pull(const int pullCode);
+    vector<std::shared_ptr<LogEvent>> Pull(const int pullCode, const uint64_t timestampSec);
+
+    // Translate metric name to pullCodes.
+    // return -1 if no valid pullCode is found
+    int GetPullCode(std::string metricName);
+
+    void OnAlarmFired();
 
 private:
-    std::unordered_map<int, std::unique_ptr<StatsPuller>> mStatsPullers;
+    StatsPullerManager();
+
+    sp<IStatsCompanionService> mStatsCompanionService = nullptr;
+
+    sp<IStatsCompanionService> get_stats_companion_service();
+
+    std::unordered_map<int, std::unique_ptr<StatsPuller>> mPullers;
+
+
+
+      // internal state of a bucket.
+      typedef struct {
+        // pull_interval_sec : last_pull_time_sec
+        std::pair<uint64_t, uint64_t> timeInfo;
+        sp<PullDataReceiver> receiver;
+      } ReceiverInfo;
+
+    std::map<int, std::vector<ReceiverInfo>> mReceivers;
+
+    Mutex mReceiversLock;
+
+    long mCurrentPullingInterval;
+
+    // for value metrics, it is important for the buckets to be aligned to multiple of smallest
+    // bucket size. All pulled metrics start pulling based on this time, so that they can be
+    // correctly attributed to the correct buckets. Pulled data attach a timestamp which is the
+    // request time.
+    const long mPullStartTimeMs;
+
+    long get_pull_start_time_ms();
+
+    LogEvent parse_pulled_data(String16 data);
+
+    static const std::unordered_map<std::string, int> kPullCodes;
 };
 
 }  // namespace statsd
 }  // namespace os
-}  // namespace android
-
-#endif  // STATSD_STATSPULLERMANAGER_H
+}  // namespace android
\ No newline at end of file
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
index 1a039f6..8220fcb 100644
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#define DEBUG true  // STOPSHIP if true
 #include "logd/LogEvent.h"
 
 #include <sstream>
@@ -23,13 +24,14 @@
 namespace os {
 namespace statsd {
 
+using namespace android::util;
 using std::ostringstream;
 using std::string;
 using android::util::ProtoOutputStream;
 
 // We need to keep a copy of the android_log_event_list owned by this instance so that the char*
 // for strings is not cleared before we can read them.
-LogEvent::LogEvent(log_msg msg) : mList(msg) {
+LogEvent::LogEvent(log_msg& msg) : mList(msg) {
     init(msg.entry_v1.sec * NS_PER_SEC + msg.entry_v1.nsec, &mList);
 }
 
@@ -206,20 +208,20 @@
 }
 
 void LogEvent::ToProto(ProtoOutputStream& proto) const {
-    long long atomToken = proto.start(TYPE_MESSAGE + mTagId);
+    long long atomToken = proto.start(FIELD_TYPE_MESSAGE | mTagId);
     const size_t N = mElements.size();
     for (size_t i=0; i<N; i++) {
         const int key = i + 1;
 
         const android_log_list_element& elem = mElements[i];
         if (elem.type == EVENT_TYPE_INT) {
-            proto.write(TYPE_INT32 + key, elem.data.int32);
+            proto.write(FIELD_TYPE_INT32 | key, elem.data.int32);
         } else if (elem.type == EVENT_TYPE_LONG) {
-            proto.write(TYPE_INT64 + key, (long long)elem.data.int64);
+            proto.write(FIELD_TYPE_INT64 | key, (long long)elem.data.int64);
         } else if (elem.type == EVENT_TYPE_FLOAT) {
-            proto.write(TYPE_FLOAT + key, elem.data.float32);
+            proto.write(FIELD_TYPE_FLOAT | key, elem.data.float32);
         } else if (elem.type == EVENT_TYPE_STRING) {
-            proto.write(TYPE_STRING + key, elem.data.string);
+            proto.write(FIELD_TYPE_STRING | key, elem.data.string);
         }
     }
     proto.end(atomToken);
diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h
index 9ef20ea..df75d9f 100644
--- a/cmds/statsd/src/logd/LogEvent.h
+++ b/cmds/statsd/src/logd/LogEvent.h
@@ -42,7 +42,7 @@
     /**
      * Read a LogEvent from a log_msg.
      */
-    explicit LogEvent(log_msg msg);
+    explicit LogEvent(log_msg& msg);
 
     /**
      * Constructs a LogEvent with the specified tag and creates an android_log_event_list in write
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
index 10816f6..71cb7717 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -24,6 +24,8 @@
 #include <limits.h>
 #include <stdlib.h>
 
+using namespace android::util;
+using android::util::ProtoOutputStream;
 using std::map;
 using std::string;
 using std::unordered_map;
@@ -33,6 +35,27 @@
 namespace os {
 namespace statsd {
 
+// for StatsLogReport
+const int FIELD_ID_METRIC_ID = 1;
+const int FIELD_ID_START_REPORT_NANOS = 2;
+const int FIELD_ID_END_REPORT_NANOS = 3;
+const int FIELD_ID_COUNT_METRICS = 5;
+// for CountMetricDataWrapper
+const int FIELD_ID_DATA = 1;
+// for CountMetricData
+const int FIELD_ID_DIMENSION = 1;
+const int FIELD_ID_BUCKET_INFO = 2;
+// for KeyValuePair
+const int FIELD_ID_KEY = 1;
+const int FIELD_ID_VALUE_STR = 2;
+const int FIELD_ID_VALUE_INT = 3;
+const int FIELD_ID_VALUE_BOOL = 4;
+const int FIELD_ID_VALUE_FLOAT = 5;
+// for CountBucketInfo
+const int FIELD_ID_START_BUCKET_NANOS = 1;
+const int FIELD_ID_END_BUCKET_NANOS = 2;
+const int FIELD_ID_COUNT = 3;
+
 // TODO: add back AnomalyTracker.
 CountMetricProducer::CountMetricProducer(const CountMetric& metric, const int conditionIndex,
                                          const sp<ConditionWizard>& wizard)
@@ -66,6 +89,8 @@
         mConditionSliced = true;
     }
 
+    startNewProtoOutputStream(mStartTimeNs);
+
     VLOG("metric %lld created. bucket size %lld start_time: %lld", metric.metric_id(),
          (long long)mBucketSizeNs, (long long)mStartTimeNs);
 }
@@ -74,23 +99,14 @@
     VLOG("~CountMetricProducer() called");
 }
 
-void CountMetricProducer::finish() {
-    // TODO: write the StatsLogReport to dropbox using
-    // DropboxWriter.
+void CountMetricProducer::startNewProtoOutputStream(long long startTime) {
+    mProto = std::make_unique<ProtoOutputStream>();
+    mProto->write(FIELD_TYPE_INT32 | FIELD_ID_METRIC_ID, mMetric.metric_id());
+    mProto->write(FIELD_TYPE_INT64 | FIELD_ID_START_REPORT_NANOS, startTime);
+    mProtoToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_COUNT_METRICS);
 }
 
-static void addSlicedCounterToReport(StatsLogReport_CountMetricDataWrapper& wrapper,
-                                     const vector<KeyValuePair>& key,
-                                     const vector<CountBucketInfo>& buckets) {
-    CountMetricData* data = wrapper.add_data();
-    for (const auto& kv : key) {
-        data->add_dimension()->CopyFrom(kv);
-    }
-    for (const auto& bucket : buckets) {
-        data->add_bucket_info()->CopyFrom(bucket);
-        VLOG("\t bucket [%lld - %lld] count: %lld", bucket.start_bucket_nanos(),
-             bucket.end_bucket_nanos(), bucket.count());
-    }
+void CountMetricProducer::finish() {
 }
 
 void CountMetricProducer::onSlicedConditionMayChange(const uint64_t eventTime) {
@@ -98,33 +114,81 @@
 }
 
 StatsLogReport CountMetricProducer::onDumpReport() {
-    VLOG("metric %lld dump report now...", mMetric.metric_id());
-
-    StatsLogReport report;
-    report.set_metric_id(mMetric.metric_id());
-    report.set_start_report_nanos(mStartTimeNs);
+    long long endTime = time(nullptr) * NANO_SECONDS_IN_A_SECOND;
 
     // Dump current bucket if it's stale.
     // If current bucket is still on-going, don't force dump current bucket.
     // In finish(), We can force dump current bucket.
-    flushCounterIfNeeded(time(nullptr) * NANO_SECONDS_IN_A_SECOND);
-    report.set_end_report_nanos(mCurrentBucketStartTimeNs);
+    flushCounterIfNeeded(endTime);
 
-    StatsLogReport_CountMetricDataWrapper* wrapper = report.mutable_count_metrics();
-
-    for (const auto& pair : mPastBuckets) {
-        const HashableDimensionKey& hashableKey = pair.first;
+    for (const auto& counter : mPastBucketProtos) {
+        const HashableDimensionKey& hashableKey = counter.first;
         auto it = mDimensionKeyMap.find(hashableKey);
         if (it == mDimensionKeyMap.end()) {
             ALOGE("Dimension key %s not found?!?! skip...", hashableKey.c_str());
             continue;
         }
+        long long wrapperToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_DATA);
 
-        VLOG("  dimension key %s", hashableKey.c_str());
-        addSlicedCounterToReport(*wrapper, it->second, pair.second);
+        // First fill dimension (KeyValuePairs).
+        for (const auto& kv : it->second) {
+            long long dimensionToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION);
+            mProto->write(FIELD_TYPE_INT32 | FIELD_ID_KEY, kv.key());
+            if (kv.has_value_str()) {
+                mProto->write(FIELD_TYPE_INT32 | FIELD_ID_VALUE_STR, kv.value_str());
+            } else if (kv.has_value_int()) {
+                mProto->write(FIELD_TYPE_INT64 | FIELD_ID_VALUE_INT, kv.value_int());
+            } else if (kv.has_value_bool()) {
+                mProto->write(FIELD_TYPE_BOOL | FIELD_ID_VALUE_BOOL, kv.value_bool());
+            } else if (kv.has_value_float()) {
+                mProto->write(FIELD_TYPE_FLOAT | FIELD_ID_VALUE_FLOAT, kv.value_float());
+            }
+            mProto->end(dimensionToken);
+        }
+
+        // Then fill bucket_info (CountBucketInfo).
+        for (const auto& proto : counter.second) {
+            size_t bufferSize = proto->size();
+            char* buffer(new char[bufferSize]);
+            size_t pos = 0;
+            auto it = proto->data();
+            while (it.readBuffer() != NULL) {
+                size_t toRead = it.currentToRead();
+                std::memcpy(&buffer[pos], it.readBuffer(), toRead);
+                pos += toRead;
+                it.rp()->move(toRead);
+            }
+            mProto->write(FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION, buffer, bufferSize);
+        }
+
+        mProto->end(wrapperToken);
     }
-    return report;
-    // TODO: Clear mPastBuckets, mDimensionKeyMap once the report is dumped.
+
+    mProto->end(mProtoToken);
+    mProto->write(FIELD_TYPE_INT64 | FIELD_ID_END_REPORT_NANOS,
+                  (long long)mCurrentBucketStartTimeNs);
+
+    size_t bufferSize = mProto->size();
+    VLOG("metric %lld dump report now...", mMetric.metric_id());
+    std::unique_ptr<uint8_t[]> buffer(new uint8_t[bufferSize]);
+    size_t pos = 0;
+    auto it = mProto->data();
+    while (it.readBuffer() != NULL) {
+        size_t toRead = it.currentToRead();
+        std::memcpy(&buffer[pos], it.readBuffer(), toRead);
+        pos += toRead;
+        it.rp()->move(toRead);
+    }
+
+    startNewProtoOutputStream(endTime);
+    mPastBucketProtos.clear();
+    mByteSize = 0;
+
+    // TODO: Once we migrate all MetricProducers to use ProtoOutputStream, we should return this:
+    // return std::move(buffer);
+    return StatsLogReport();
+
+    // TODO: Clear mDimensionKeyMap once the report is dumped.
 }
 
 void CountMetricProducer::onConditionChanged(const bool conditionMet, const uint64_t eventTime) {
@@ -135,7 +199,7 @@
 void CountMetricProducer::onMatchedLogEventInternal(
         const size_t matcherIndex, const HashableDimensionKey& eventKey,
         const map<string, HashableDimensionKey>& conditionKey, bool condition,
-        const LogEvent& event) {
+        const LogEvent& event, bool scheduledPull) {
     uint64_t eventTimeNs = event.GetTimestampNs();
 
     flushCounterIfNeeded(eventTimeNs);
@@ -175,15 +239,17 @@
     // adjust the bucket start time
     int64_t numBucketsForward = (eventTimeNs - mCurrentBucketStartTimeNs) / mBucketSizeNs;
 
-    CountBucketInfo info;
-    info.set_start_bucket_nanos(mCurrentBucketStartTimeNs);
-    info.set_end_bucket_nanos(mCurrentBucketStartTimeNs + mBucketSizeNs);
-
     for (const auto& counter : mCurrentSlicedCounter) {
-        info.set_count(counter.second);
-        // it will auto create new vector of CountbucketInfo if the key is not found.
-        auto& bucketList = mPastBuckets[counter.first];
-        bucketList.push_back(info);
+        unique_ptr<ProtoOutputStream> proto = make_unique<ProtoOutputStream>();
+        proto->write(FIELD_TYPE_INT64 | FIELD_ID_START_BUCKET_NANOS,
+                     (long long)mCurrentBucketStartTimeNs);
+        proto->write(FIELD_TYPE_INT64 | FIELD_ID_END_BUCKET_NANOS,
+                      (long long)mCurrentBucketStartTimeNs + mBucketSizeNs);
+        proto->write(FIELD_TYPE_INT64 | FIELD_ID_COUNT, (long long)counter.second);
+
+        auto& bucketList = mPastBucketProtos[counter.first];
+        bucketList.push_back(std::move(proto));
+        mByteSize += proto->size();
 
         VLOG("metric %lld, dump key value: %s -> %d", mMetric.metric_id(), counter.first.c_str(),
              counter.second);
@@ -202,11 +268,11 @@
          (long long)mCurrentBucketStartTimeNs);
 }
 
+// Rough estimate of CountMetricProducer buffer stored. This number will be
+// greater than actual data size as it contains each dimension of
+// CountMetricData is  duplicated.
 size_t CountMetricProducer::byteSize() {
-// TODO: return actual proto size when ProtoOutputStream is ready for use for
-// CountMetricsProducer.
-//    return mProto->size();
-    return 0;
+    return mByteSize;
 }
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.h b/cmds/statsd/src/metrics/CountMetricProducer.h
index 5d1889a..473a4ba 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.h
+++ b/cmds/statsd/src/metrics/CountMetricProducer.h
@@ -19,6 +19,7 @@
 
 #include <unordered_map>
 
+#include <android/util/ProtoOutputStream.h>
 #include "../condition/ConditionTracker.h"
 #include "../matchers/matcher_util.h"
 #include "CountAnomalyTracker.h"
@@ -59,13 +60,16 @@
 protected:
     void onMatchedLogEventInternal(const size_t matcherIndex, const HashableDimensionKey& eventKey,
                                    const std::map<std::string, HashableDimensionKey>& conditionKey,
-                                   bool condition, const LogEvent& event) override;
+                                   bool condition, const LogEvent& event,
+                                   bool scheduledPull) override;
 
 private:
     const CountMetric mMetric;
 
-    // Save the past buckets and we can clear when the StatsLogReport is dumped.
-    std::unordered_map<HashableDimensionKey, std::vector<CountBucketInfo>> mPastBuckets;
+    std::unordered_map<HashableDimensionKey,
+        std::vector<unique_ptr<android::util::ProtoOutputStream>>> mPastBucketProtos;
+
+    size_t mByteSize;
 
     // The current bucket.
     std::unordered_map<HashableDimensionKey, int> mCurrentSlicedCounter;
@@ -73,6 +77,12 @@
     vector<unique_ptr<CountAnomalyTracker>> mAnomalyTrackers;
 
     void flushCounterIfNeeded(const uint64_t newEventTime);
+
+    std::unique_ptr<android::util::ProtoOutputStream> mProto;
+
+    long long mProtoToken;
+
+    void startNewProtoOutputStream(long long timestamp);
 };
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index dfed275..340f503 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -168,7 +168,7 @@
 void DurationMetricProducer::onMatchedLogEventInternal(
         const size_t matcherIndex, const HashableDimensionKey& eventKey,
         const map<string, HashableDimensionKey>& conditionKeys, bool condition,
-        const LogEvent& event) {
+        const LogEvent& event, bool scheduledPull) {
     flushIfNeeded(event.GetTimestampNs());
 
     if (matcherIndex == mStopAllIndex) {
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.h b/cmds/statsd/src/metrics/DurationMetricProducer.h
index 5b302b4..febf25d 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.h
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.h
@@ -62,7 +62,8 @@
 protected:
     void onMatchedLogEventInternal(const size_t matcherIndex, const HashableDimensionKey& eventKey,
                                    const std::map<std::string, HashableDimensionKey>& conditionKeys,
-                                   bool condition, const LogEvent& event) override;
+                                   bool condition, const LogEvent& event,
+                                   bool scheduledPull) override;
 
 private:
     const DurationMetric mMetric;
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.cpp b/cmds/statsd/src/metrics/EventMetricProducer.cpp
index dd23d66..cbae1d3 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/EventMetricProducer.cpp
@@ -23,6 +23,7 @@
 #include <limits.h>
 #include <stdlib.h>
 
+using namespace android::util;
 using android::util::ProtoOutputStream;
 using std::map;
 using std::string;
@@ -36,13 +37,13 @@
 // for StatsLogReport
 const int FIELD_ID_METRIC_ID = 1;
 const int FIELD_ID_START_REPORT_NANOS = 2;
-const int FIELD_ID_END_REPORT_NANOS = 2;
+const int FIELD_ID_END_REPORT_NANOS = 3;
 const int FIELD_ID_EVENT_METRICS = 4;
+// for EventMetricDataWrapper
+const int FIELD_ID_DATA = 1;
 // for EventMetricData
 const int FIELD_ID_TIMESTAMP_NANOS = 1;
 const int FIELD_ID_STATS_EVENTS = 2;
-// for CountMetricDataWrapper
-const int FIELD_ID_DATA = 1;
 
 EventMetricProducer::EventMetricProducer(const EventMetric& metric, const int conditionIndex,
                                          const sp<ConditionWizard>& wizard)
@@ -69,9 +70,9 @@
     mProto = std::make_unique<ProtoOutputStream>();
     // TODO: We need to auto-generate the field IDs for StatsLogReport, EventMetricData,
     // and StatsEvent.
-    mProto->write(TYPE_INT32 + FIELD_ID_METRIC_ID, mMetric.metric_id());
-    mProto->write(TYPE_INT64 + FIELD_ID_START_REPORT_NANOS, startTime);
-    mProtoToken = mProto->start(TYPE_MESSAGE + FIELD_ID_EVENT_METRICS);
+    mProto->write(FIELD_TYPE_INT32 | FIELD_ID_METRIC_ID, mMetric.metric_id());
+    mProto->write(FIELD_TYPE_INT64 | FIELD_ID_START_REPORT_NANOS, startTime);
+    mProtoToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_EVENT_METRICS);
 }
 
 void EventMetricProducer::finish() {
@@ -83,7 +84,7 @@
 StatsLogReport EventMetricProducer::onDumpReport() {
     long long endTime = time(nullptr) * NANO_SECONDS_IN_A_SECOND;
     mProto->end(mProtoToken);
-    mProto->write(TYPE_INT64 + FIELD_ID_END_REPORT_NANOS, endTime);
+    mProto->write(FIELD_TYPE_INT64 | FIELD_ID_END_REPORT_NANOS, endTime);
 
     size_t bufferSize = mProto->size();
     VLOG("metric %lld dump report now... proto size: %zu ", mMetric.metric_id(), bufferSize);
@@ -112,15 +113,15 @@
 void EventMetricProducer::onMatchedLogEventInternal(
         const size_t matcherIndex, const HashableDimensionKey& eventKey,
         const std::map<std::string, HashableDimensionKey>& conditionKey, bool condition,
-        const LogEvent& event) {
+        const LogEvent& event, bool scheduledPull) {
 
     if (!condition) {
         return;
     }
 
-    long long wrapperToken = mProto->start(TYPE_MESSAGE + FIELD_ID_DATA);
-    mProto->write(TYPE_INT64 + FIELD_ID_TIMESTAMP_NANOS, (long long)event.GetTimestampNs());
-    long long eventToken = mProto->start(TYPE_MESSAGE + FIELD_ID_STATS_EVENTS);
+    long long wrapperToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_DATA);
+    mProto->write(FIELD_TYPE_INT64 | FIELD_ID_TIMESTAMP_NANOS, (long long)event.GetTimestampNs());
+    long long eventToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_STATS_EVENTS);
     event.ToProto(*mProto);
     mProto->end(eventToken);
     mProto->end(wrapperToken);
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.h b/cmds/statsd/src/metrics/EventMetricProducer.h
index 72df0a7..7dd0e38 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.h
+++ b/cmds/statsd/src/metrics/EventMetricProducer.h
@@ -41,7 +41,7 @@
 
     void onMatchedLogEventInternal(const size_t matcherIndex, const HashableDimensionKey& eventKey,
                                    const std::map<std::string, HashableDimensionKey>& conditionKey,
-                                   bool condition, const LogEvent& event) override;
+                                   bool condition, const LogEvent& event, bool scheduledPull) override;
 
     void onConditionChanged(const bool conditionMet, const uint64_t eventTime) override;
 
diff --git a/cmds/statsd/src/metrics/MetricProducer.cpp b/cmds/statsd/src/metrics/MetricProducer.cpp
index 3c8ce6e..535f4a2 100644
--- a/cmds/statsd/src/metrics/MetricProducer.cpp
+++ b/cmds/statsd/src/metrics/MetricProducer.cpp
@@ -21,7 +21,8 @@
 
 using std::map;
 
-void MetricProducer::onMatchedLogEvent(const size_t matcherIndex, const LogEvent& event) {
+void MetricProducer::onMatchedLogEvent(const size_t matcherIndex, const LogEvent& event,
+                                       bool scheduledPull) {
     uint64_t eventTimeNs = event.GetTimestampNs();
     // this is old event, maybe statsd restarted?
     if (eventTimeNs < mStartTimeNs) {
@@ -59,7 +60,8 @@
         condition = mCondition;
     }
 
-    onMatchedLogEventInternal(matcherIndex, eventKey, conditionKeys, condition, event);
+    onMatchedLogEventInternal(matcherIndex, eventKey, conditionKeys, condition, event,
+                              scheduledPull);
 }
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index 2083695..3b117ec 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -48,7 +48,7 @@
     virtual ~MetricProducer(){};
 
     // Consume the parsed stats log entry that already matched the "what" of the metric.
-    void onMatchedLogEvent(const size_t matcherIndex, const LogEvent& event);
+    void onMatchedLogEvent(const size_t matcherIndex, const LogEvent& event, bool scheduledPull);
 
     virtual void onConditionChanged(const bool condition, const uint64_t eventTime) = 0;
 
@@ -107,7 +107,7 @@
     virtual void onMatchedLogEventInternal(
             const size_t matcherIndex, const HashableDimensionKey& eventKey,
             const std::map<std::string, HashableDimensionKey>& conditionKey, bool condition,
-            const LogEvent& event) = 0;
+            const LogEvent& event, bool scheduledPull) = 0;
 };
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index d1df8aa..521fcc3 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -145,7 +145,8 @@
             if (pair != mTrackerToMetricMap.end()) {
                 auto& metricList = pair->second;
                 for (const int metricIndex : metricList) {
-                    mAllMetricProducers[metricIndex]->onMatchedLogEvent(i, event);
+                    // pushed metrics are never scheduled pulls
+                    mAllMetricProducers[metricIndex]->onMatchedLogEvent(i, event, false);
                 }
             }
         }
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
new file mode 100644
index 0000000..cb6166d
--- /dev/null
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define DEBUG true  // STOPSHIP if true
+#include "Log.h"
+
+#include "ValueMetricProducer.h"
+
+#include <cutils/log.h>
+#include <limits.h>
+#include <stdlib.h>
+
+using std::map;
+using std::unordered_map;
+using std::list;
+using std::make_shared;
+using std::shared_ptr;
+using std::unique_ptr;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+// ValueMetric has a minimum bucket size of 10min so that we don't pull too frequently
+ValueMetricProducer::ValueMetricProducer(const ValueMetric& metric, const int conditionIndex,
+                                         const sp<ConditionWizard>& wizard)
+    : MetricProducer((time(nullptr) / 600 * 600 * NANO_SECONDS_IN_A_SECOND), conditionIndex,
+                     wizard),
+      mMetric(metric),
+      mPullCode(mStatsPullerManager.GetPullCode(mMetric.what())) {
+  // TODO: valuemetric for pushed events may need unlimited bucket length
+  mBucketSizeNs = mMetric.bucket().bucket_size_millis() * 1000 * 1000;
+
+  mDimension.insert(mDimension.begin(), metric.dimension().begin(), metric.dimension().end());
+
+  if (metric.links().size() > 0) {
+    mConditionLinks.insert(mConditionLinks.begin(), metric.links().begin(),
+                           metric.links().end());
+    mConditionSliced = true;
+  }
+
+  if (!metric.has_condition() && mPullCode != -1) {
+    mStatsPullerManager.RegisterReceiver(mPullCode, this, metric.bucket().bucket_size_millis());
+  }
+
+  VLOG("value metric %lld created. bucket size %lld start_time: %lld", metric.metric_id(),
+       (long long)mBucketSizeNs, (long long)mStartTimeNs);
+}
+
+ValueMetricProducer::~ValueMetricProducer() {
+  VLOG("~ValueMetricProducer() called");
+}
+
+void ValueMetricProducer::finish() {
+  // TODO: write the StatsLogReport to dropbox using
+  // DropboxWriter.
+}
+
+static void addSlicedCounterToReport(StatsLogReport_ValueMetricDataWrapper& wrapper,
+                                     const vector<KeyValuePair>& key,
+                                     const vector<ValueBucketInfo>& buckets) {
+  ValueMetricData* data = wrapper.add_data();
+  for (const auto& kv : key) {
+    data->add_dimension()->CopyFrom(kv);
+  }
+  for (const auto& bucket : buckets) {
+    data->add_bucket_info()->CopyFrom(bucket);
+    VLOG("\t bucket [%lld - %lld] value: %lld", bucket.start_bucket_nanos(),
+         bucket.end_bucket_nanos(), bucket.value());
+  }
+}
+
+void ValueMetricProducer::onSlicedConditionMayChange(const uint64_t eventTime) {
+    VLOG("Metric %lld onSlicedConditionMayChange", mMetric.metric_id());
+}
+
+StatsLogReport ValueMetricProducer::onDumpReport() {
+  VLOG("metric %lld dump report now...", mMetric.metric_id());
+
+  StatsLogReport report;
+  report.set_metric_id(mMetric.metric_id());
+  report.set_start_report_nanos(mStartTimeNs);
+
+  // Dump current bucket if it's stale.
+  // If current bucket is still on-going, don't force dump current bucket.
+  // In finish(), We can force dump current bucket.
+  //    flush_if_needed(time(nullptr) * NANO_SECONDS_IN_A_SECOND);
+  report.set_end_report_nanos(mCurrentBucketStartTimeNs);
+
+  StatsLogReport_ValueMetricDataWrapper* wrapper = report.mutable_value_metrics();
+
+  for (const auto& pair : mPastBuckets) {
+    const HashableDimensionKey& hashableKey = pair.first;
+    auto it = mDimensionKeyMap.find(hashableKey);
+    if (it == mDimensionKeyMap.end()) {
+      ALOGE("Dimension key %s not found?!?! skip...", hashableKey.c_str());
+      continue;
+    }
+
+    VLOG("  dimension key %s", hashableKey.c_str());
+    addSlicedCounterToReport(*wrapper, it->second, pair.second);
+  }
+  return report;
+  // TODO: Clear mPastBuckets, mDimensionKeyMap once the report is dumped.
+}
+
+void ValueMetricProducer::onConditionChanged(const bool condition, const uint64_t eventTime) {
+    mCondition = condition;
+
+    if (mPullCode != -1) {
+        vector<shared_ptr<LogEvent>> allData = mStatsPullerManager.Pull(mPullCode, eventTime);
+        if (mCondition == true) {
+            mStatsPullerManager.RegisterReceiver(mPullCode, this,
+                                                 mMetric.bucket().bucket_size_millis());
+        } else if (mCondition == ConditionState::kFalse) {
+            mStatsPullerManager.UnRegisterReceiver(mPullCode, this);
+        }
+        if (allData.size() == 0) {
+            return;
+        }
+        AutoMutex _l(mLock);
+        if (allData.size() == 0) {
+            return;
+        }
+        for (const auto& data : allData) {
+            onMatchedLogEvent(0, *data, false);
+        }
+        flush_if_needed(eventTime);
+    }
+    return;
+}
+
+void ValueMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& allData) {
+    if (mCondition == ConditionState::kTrue || !mMetric.has_condition()) {
+        AutoMutex _l(mLock);
+        if (allData.size() == 0) {
+            return;
+        }
+        uint64_t eventTime = allData.at(0)->GetTimestampNs();
+        for (const auto& data : allData) {
+            onMatchedLogEvent(0, *data, true);
+        }
+        flush_if_needed(eventTime);
+    }
+}
+
+void ValueMetricProducer::onMatchedLogEventInternal(
+    const size_t matcherIndex, const HashableDimensionKey& eventKey,
+    const map<string, HashableDimensionKey>& conditionKey, bool condition,
+    const LogEvent& event, bool scheduledPull) {
+  uint64_t eventTimeNs = event.GetTimestampNs();
+  if (eventTimeNs < mCurrentBucketStartTimeNs) {
+      VLOG("Skip event due to late arrival: %lld vs %lld", (long long)eventTimeNs,
+           (long long)mCurrentBucketStartTimeNs);
+      return;
+  }
+
+  Interval& interval = mCurrentSlicedBucket[eventKey];
+
+  long value = get_value(event);
+
+  if (scheduledPull) {
+    if (interval.raw.size() > 0) {
+      interval.raw.back().second = value;
+    } else {
+      interval.raw.push_back(std::make_pair(value, value));
+    }
+    mNextSlicedBucket[eventKey].raw[0].first = value;
+  } else {
+    if (mCondition == ConditionState::kTrue) {
+      interval.raw.push_back(std::make_pair(value, 0));
+    } else {
+      if (interval.raw.size() != 0) {
+        interval.raw.back().second = value;
+      }
+    }
+  }
+  if (mPullCode == -1) {
+      flush_if_needed(eventTimeNs);
+  }
+}
+
+long ValueMetricProducer::get_value(const LogEvent& event) {
+  status_t err = NO_ERROR;
+  long val = event.GetLong(mMetric.value_field(), &err);
+  if (err == NO_ERROR) {
+    return val;
+  } else {
+    VLOG("Can't find value in message.");
+    return 0;
+  }
+}
+
+void ValueMetricProducer::flush_if_needed(const uint64_t eventTimeNs) {
+    if (mCurrentBucketStartTimeNs + mBucketSizeNs > eventTimeNs) {
+        VLOG("eventTime is %lld, less than next bucket start time %lld", (long long)eventTimeNs,
+             (long long)(mCurrentBucketStartTimeNs + mBucketSizeNs));
+        return;
+    }
+
+    VLOG("finalizing bucket for %ld, dumping %d slices", (long)mCurrentBucketStartTimeNs,
+         (int)mCurrentSlicedBucket.size());
+    ValueBucketInfo info;
+    info.set_start_bucket_nanos(mCurrentBucketStartTimeNs);
+    info.set_end_bucket_nanos(mCurrentBucketStartTimeNs + mBucketSizeNs);
+
+    for (const auto& slice : mCurrentSlicedBucket) {
+      long value = 0;
+      for (const auto& pair : slice.second.raw) {
+        value += pair.second - pair.first;
+      }
+      info.set_value(value);
+      VLOG(" %s, %ld", slice.first.c_str(), value);
+      // it will auto create new vector of ValuebucketInfo if the key is not found.
+      auto& bucketList = mPastBuckets[slice.first];
+      bucketList.push_back(info);
+    }
+
+    // Reset counters
+    mCurrentSlicedBucket.swap(mNextSlicedBucket);
+    mNextSlicedBucket.clear();
+    int64_t numBucketsForward = (eventTimeNs - mCurrentBucketStartTimeNs) / mBucketSizeNs;
+    if (numBucketsForward >1) {
+        VLOG("Skipping forward %lld buckets", (long long)numBucketsForward);
+    }
+    mCurrentBucketStartTimeNs = mCurrentBucketStartTimeNs + numBucketsForward * mBucketSizeNs;
+    VLOG("metric %lld: new bucket start time: %lld", mMetric.metric_id(),
+         (long long)mCurrentBucketStartTimeNs);
+}
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
\ No newline at end of file
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
new file mode 100644
index 0000000..4f17913
--- /dev/null
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <utils/threads.h>
+#include <list>
+#include "../condition/ConditionTracker.h"
+#include "../external/PullDataReceiver.h"
+#include "../external/StatsPullerManager.h"
+#include "CountAnomalyTracker.h"
+#include "MetricProducer.h"
+#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+class ValueMetricProducer : public virtual MetricProducer, public virtual PullDataReceiver {
+public:
+    ValueMetricProducer(const ValueMetric& valueMetric, const int conditionIndex,
+                        const sp<ConditionWizard>& wizard);
+
+    virtual ~ValueMetricProducer();
+
+    void onConditionChanged(const bool condition, const uint64_t eventTime) override;
+
+    void finish() override;
+
+    StatsLogReport onDumpReport() override;
+
+    void onSlicedConditionMayChange(const uint64_t eventTime);
+
+    void onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& data) override;
+    // TODO: Implement this later.
+    size_t byteSize() override{return 0;};
+
+    // TODO: Implement this later.
+    virtual void notifyAppUpgrade(const string& apk, const int uid, const int version) override{};
+    // TODO: Implement this later.
+    virtual void notifyAppRemoved(const string& apk, const int uid) override{};
+
+protected:
+    void onMatchedLogEventInternal(const size_t matcherIndex, const HashableDimensionKey& eventKey,
+                                   const std::map<std::string, HashableDimensionKey>& conditionKey,
+                                   bool condition, const LogEvent& event,
+                                   bool scheduledPull) override;
+
+private:
+    const ValueMetric mMetric;
+
+    StatsPullerManager& mStatsPullerManager = StatsPullerManager::GetInstance();
+
+    Mutex mLock;
+
+    const int mPullCode;
+
+    // internal state of a bucket.
+    typedef struct {
+        std::vector<std::pair<long, long>> raw;
+    } Interval;
+
+    std::unordered_map<HashableDimensionKey, Interval> mCurrentSlicedBucket;
+    // If condition is true and pulling on schedule, the previous bucket value needs to be carried
+    // over to the next bucket.
+    std::unordered_map<HashableDimensionKey, Interval> mNextSlicedBucket;
+
+    // Save the past buckets and we can clear when the StatsLogReport is dumped.
+    std::unordered_map<HashableDimensionKey, std::vector<ValueBucketInfo>> mPastBuckets;
+
+    long get_value(const LogEvent& event);
+
+    void flush_if_needed(const uint64_t eventTimeNs);
+};
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp
index 3b3ffb7..3d4036e 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -16,11 +16,13 @@
 
 #include "../condition/CombinationConditionTracker.h"
 #include "../condition/SimpleConditionTracker.h"
+#include "../external/StatsPullerManager.h"
 #include "../matchers/CombinationLogMatchingTracker.h"
 #include "../matchers/SimpleLogMatchingTracker.h"
 #include "CountMetricProducer.h"
 #include "DurationMetricProducer.h"
 #include "EventMetricProducer.h"
+#include "ValueMetricProducer.h"
 #include "stats_util.h"
 
 using std::set;
@@ -192,6 +194,7 @@
     const int allMetricsCount =
             config.count_metric_size() + config.duration_metric_size() + config.event_metric_size();
     allMetricProducers.reserve(allMetricsCount);
+    StatsPullerManager& statsPullerManager = StatsPullerManager::GetInstance();
 
     // Build MetricProducers for each metric defined in config.
     // (1) build CountMetricProducer
@@ -307,6 +310,34 @@
         allMetricProducers.push_back(eventMetric);
     }
 
+    // value metrics
+    for (int i = 0; i < config.value_metric_size(); i++) {
+        const ValueMetric& metric = config.value_metric(i);
+        if (!metric.has_what()) {
+            ALOGW("cannot find what in ValueMetric %lld", metric.metric_id());
+            return false;
+        }
+
+        int pullCode = statsPullerManager.GetPullCode(metric.what());
+        if (pullCode == -1) {
+            ALOGW("cannot find %s in pulled metrics", metric.what().c_str());
+            return false;
+        }
+
+        sp<MetricProducer> valueProducer;
+        auto condition_it = conditionTrackerMap.find(metric.condition());
+        if (condition_it == conditionTrackerMap.end()) {
+            ALOGW("cannot find the Condition %s in the config", metric.condition().c_str());
+            return false;
+        }
+        int metricIndex = allMetricProducers.size();
+        valueProducer = new ValueMetricProducer(metric, condition_it->second, wizard);
+        // will create new vector if not exist before.
+        auto& metricList = conditionToMetricMap[condition_it->second];
+        metricList.push_back(metricIndex);
+
+        allMetricProducers.push_back(valueProducer);
+    }
     return true;
 }
 
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.h b/cmds/statsd/src/metrics/metrics_manager_util.h
index c91b7fc..e089d065 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.h
+++ b/cmds/statsd/src/metrics/metrics_manager_util.h
@@ -21,6 +21,7 @@
 #include <vector>
 
 #include "../condition/ConditionTracker.h"
+#include "../external/StatsPullerManager.h"
 #include "../matchers/LogMatchingTracker.h"
 
 namespace android {
diff --git a/cmds/statsd/src/stats_events.proto b/cmds/statsd/src/stats_events.proto
index 3789baf..51244c6 100644
--- a/cmds/statsd/src/stats_events.proto
+++ b/cmds/statsd/src/stats_events.proto
@@ -35,7 +35,8 @@
  * in the format defined here and in stats_log.proto.
  */
 message StatsEvent {
-    oneof event {
+    // Pushed events start at 2.
+    oneof pushed {
         // For StatsLog reasons, 1 is illegal and will not work. Must start at 2.
         BleScanStateChanged ble_scan_state_changed = 2;
         BleUnoptimizedScanStateChanged ble_unoptimized_scan_state_changed = 3;
@@ -70,8 +71,18 @@
         WifiScanStateChanged wifi_scan_state_changed = 39;
         PhoneSignalStrengthChanged phone_signal_strength_changed = 40;
         SettingChanged setting_changed = 41;
+        ActivityForegroundStateChanged activity_foreground_state_changed = 42;
         // TODO: Reorder the numbering so that the most frequent occur events occur in the first 15.
     }
+
+    // Pulled events will start at field 1000.
+    oneof pulled {
+        WifiBytesTransferred wifi_bytes_transferred = 1000;
+        WifiBytesTransferredByFgBg wifi_bytes_transferred_by_fg_bg = 1001;
+        MobileBytesTransferred mobile_bytes_transferred = 1002;
+        MobileBytesTransferredByFgBg mobile_bytes_transferred_by_fg_bg = 1003;
+        KernelWakelocksReported kernel_wakelocks_reported = 1004;
+    }
 }
 
 /**
@@ -679,3 +690,116 @@
     // The user ID associated. Defined in android/os/UserHandle.java
     optional int32 user = 7;
 }
+
+
+/*
+ * Logs activity going to foreground or background
+ *
+ * Logged from:
+  *   frameworks/base/services/core/java/com/android/server/am/ActivityRecord.java
+ */
+message ActivityForegroundStateChanged {
+    enum Activity {
+        MOVE_TO_BACKGROUND = 0;
+        MOVE_TO_FOREGROUND = 1;
+    }
+    optional int32 uid = 1;
+    optional string pkg_name = 2;
+    optional string class_name = 3;
+    optional Activity activity = 4;
+}
+
+/**
+ * Pulls bytes transferred via wifi (Sum of foreground and background usage).
+ *
+ * Pulled from:
+ *   StatsCompanionService (using BatteryStats to get which interfaces are wifi)
+ */
+message WifiBytesTransferred {
+    optional int32 uid = 1;
+
+    optional int64 rx_bytes = 2;
+
+    optional int64 rx_packets = 3;
+
+    optional int64 tx_bytes = 4;
+
+    optional int64 tx_packets = 5;
+}
+
+/**
+ * Pulls bytes transferred via wifi (separated by foreground and background usage).
+ *
+ * Pulled from:
+ *   StatsCompanionService (using BatteryStats to get which interfaces are wifi)
+ */
+message WifiBytesTransferredByFgBg {
+    optional int32 uid = 1;
+
+    // 1 denotes foreground and 0 denotes background. This is called Set in NetworkStats.
+    optional int32 is_foreground = 2;
+
+    optional int64 rx_bytes = 3;
+
+    optional int64 rx_packets = 4;
+
+    optional int64 tx_bytes = 5;
+
+    optional int64 tx_packets = 6;
+}
+
+/**
+ * Pulls bytes transferred via mobile networks (Sum of foreground and background usage).
+ *
+ * Pulled from:
+ *   StatsCompanionService (using BatteryStats to get which interfaces are mobile data)
+ */
+message MobileBytesTransferred {
+    optional int32 uid = 1;
+
+    optional int64 rx_bytes = 2;
+
+    optional int64 rx_packets = 3;
+
+    optional int64 tx_bytes = 4;
+
+    optional int64 tx_packets = 5;
+}
+
+/**
+ * Pulls bytes transferred via mobile networks (separated by foreground and background usage).
+ *
+ * Pulled from:
+ *   StatsCompanionService (using BatteryStats to get which interfaces are mobile data)
+ */
+message MobileBytesTransferredByFgBg {
+    optional int32 uid = 1;
+
+    // 1 denotes foreground and 0 denotes background. This is called Set in NetworkStats.
+    optional int32 is_foreground = 2;
+
+    optional int64 rx_bytes = 3;
+
+    optional int64 rx_packets = 4;
+
+    optional int64 tx_bytes = 5;
+
+    optional int64 tx_packets = 6;
+}
+
+/**
+ * Pulls the kernel wakelock durations. This atom is adapted from
+ * android/internal/os/KernelWakelockStats.java
+ *
+ * Pulled from:
+ *   StatsCompanionService using KernelWakelockReader.
+ */
+message KernelWakelocksReported {
+    optional string name = 1;
+
+    optional int32 count = 2;
+
+    optional int32 version = 3;
+
+    optional int64 time = 4;
+}
diff --git a/cmds/statsd/src/stats_events_copy.proto b/cmds/statsd/src/stats_events_copy.proto
index 5e8ef24..9470372 100644
--- a/cmds/statsd/src/stats_events_copy.proto
+++ b/cmds/statsd/src/stats_events_copy.proto
@@ -40,9 +40,28 @@
  */
 message StatsEvent {
     oneof event {
-        ScreenStateChanged screen_state_changed = 1;
-        ProcessStateChanged process_state_changed = 2;
-        WakeLockChanged wakelock_changed = 3;
+        // For StatsLog reasons, 1 is illegal and will not work. Must start at 2.
+        BleScanStateChanged ble_scan_state_changed = 2;
+        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
+        SyncStateChanged sync_state_changed = 7;
+        ScheduledJobStateChanged scheduled_job_state_changed = 8;
+        ScreenBrightnessChanged screen_brightness_changed = 9;
+        // 10-20 are temporarily reserved for wakelocks etc.
+        UidWakelockStateChanged uid_wakelock_state_changed = 11;
+        LongPartialWakelockStateChanged long_partial_wakelock_state_changed = 12;
+        BatterySaverModeStateChanged battery_saver_mode_state_changed = 21;
+        DeviceIdleModeStateChanged device_idle_mode_state_changed = 22;
+        AudioStateChanged audio_state_changed = 23;
+        MediaCodecActivityChanged media_codec_activity_changed = 24;
+        CameraStateChanged camera_state_changed = 25;
+        FlashlightStateChanged flashlight_state_changed = 26;
+        UidProcessStateChanged uid_process_state_changed = 27;
+        ProcessLifeCycleStateChanged process_life_cycle_state_changed = 28;
+        ScreenStateChanged screen_state_changed = 29;
+        // TODO: Reorder the numbering so that the most frequent occur events occur in the first 15.
     }
 }
 
@@ -76,7 +95,7 @@
  *     and those UIDs will be translated in xxx to those strings.
  *
  * CONVENTIONS:
- *   - Events are past tense. e.g. ScreenStateChanged, not ScreenStateChange
+ *   - Events are past tense. e.g. ScreenStateChanged, not ScreenStateChange.
  *   - If there is a UID, it goes first. Think in an object-oriented fashion.
  * *****************************************************************************
  */
@@ -102,33 +121,347 @@
 }
 
 /**
- * Logs that the state of a process state, as per the activity manager has changed.
+ * Logs that the state of a process state, as per the activity manager, has changed.
  *
  * Logged from:
  *   frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
  */
-message ProcessStateChanged {
-    // TODO: Use the real (mapped) process states.
+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 int32 state = 2;
 }
 
 /**
- * Logs that the state of a wakelock has changed.
+ * Logs that a process started, finished, crashed, or ANRed.
+ *
+ * Logged from:
+ *   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?
+    optional string name = 2;
+
+    // The state.
+    // TODO: Use an enum.
+    optional int32 event = 3;
+}
+
+
+
+/**
+ * Logs when the ble scan state changes.
+ *
+ * Logged from:
+ *   frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ */
+message BleScanStateChanged {
+    // TODO: Add attribution instead of uid.
+    optional int32 uid = 1;
+
+    enum State {
+        OFF = 0;
+        ON = 1;
+    }
+    optional State state = 2;
+}
+
+/**
+ * Logs when an unoptimized ble scan state changes.
+ *
+ * Logged from:
+ *   frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ */
+// TODO: Consider changing to tracking per-scanner-id (log from AppScanStats).
+message BleUnoptimizedScanStateChanged {
+    // TODO: Add attribution instead of uid.
+    optional int32 uid = 1;
+
+    enum State {
+        OFF = 0;
+        ON = 1;
+    }
+    optional State state = 2;
+}
+
+/**
+ * Logs reporting of a ble scan finding results.
+ *
+ * Logged from:
+ *   frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ */
+// TODO: Consider changing to tracking per-scanner-id (log from AppScanStats).
+message BleScanResultReceived {
+    // TODO: Add attribution instead of uid.
+    optional int32 uid = 1;
+
+    // Number of ble scan results returned.
+    optional int32 num_of_results = 2;
+}
+
+/**
+ * Logs when a sensor state changes.
+ *
+ * Logged from:
+ *   frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ */
+message SensorStateChanged {
+    // TODO: Add attribution instead of uid.
+    optional int32 uid = 1;
+
+    // TODO: Is there a way to get the actual name of the sensor?
+    // The id (int) of the sensor.
+    optional int32 sensor_id = 2;
+
+    enum State {
+        OFF = 0;
+        ON = 1;
+    }
+    optional State state = 3;
+}
+
+
+/**
+ * Logs when GPS state changes.
+ *
+ * Logged from:
+ *   frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ */
+message GpsScanStateChanged {
+    // TODO: Add attribution instead of uid.
+    optional int32 uid = 1;
+
+    enum State {
+        OFF = 0;
+        ON = 1;
+    }
+    optional State state = 2;
+}
+
+
+/**
+ * Logs when a sync manager sync state changes.
+ *
+ * Logged from:
+ *   frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ */
+message SyncStateChanged {
+    // TODO: Add attribution instead of uid.
+    optional int32 uid = 1;
+
+    // Name of the sync (as named in the app)
+    optional string name = 2;
+
+    enum State {
+        OFF = 0;
+        ON = 1;
+    }
+    optional State state = 3;
+}
+
+/**
+ * Logs when a job scheduler job state changes.
+ *
+ * Logged from:
+ *   frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ */
+message ScheduledJobStateChanged {
+    // TODO: Add attribution instead of uid.
+    optional int32 uid = 1;
+
+    // Name of the job (as named in the app)
+    optional string name = 2;
+
+    enum State {
+        OFF = 0;
+        ON = 1;
+    }
+    optional State state = 3;
+
+    // TODO: Consider adding the stopReason (int)
+}
+
+/**
+ * Logs when the audio state changes.
+ *
+ * Logged from:
+ *   frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ */
+message AudioStateChanged {
+    // TODO: Add attribution instead of uid.
+    optional int32 uid = 1;
+
+    enum State {
+        OFF = 0;
+        ON = 1;
+    }
+    optional State state = 2;
+}
+
+/**
+ * Logs when the video codec state changes.
+ *
+ * Logged from:
+ *   frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ */
+message MediaCodecActivityChanged {
+    // TODO: Add attribution instead of uid.
+    optional int32 uid = 1;
+
+    enum State {
+        OFF = 0;
+        ON = 1;
+    }
+    optional State state = 2;
+}
+
+/**
+ * Logs when the flashlight state changes.
+ *
+ * Logged from:
+ *   frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ */
+message FlashlightStateChanged {
+    // TODO: Add attribution instead of uid.
+    optional int32 uid = 1;
+
+    enum State {
+        OFF = 0;
+        ON = 1;
+    }
+    optional State state = 2;
+}
+
+/**
+ * Logs when the camera state changes.
+ *
+ * Logged from:
+ *   frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ */
+message CameraStateChanged {
+    // TODO: Add attribution instead of uid.
+    optional int32 uid = 1;
+
+    enum State {
+        OFF = 0;
+        ON = 1;
+    }
+    optional State state = 2;
+}
+
+/**
+ * Logs that the state of a wakelock (per app and per wakelock name) has changed.
  *
  * Logged from:
  *   TODO
  */
-message WakeLockChanged {
+message WakelockChanged {
     // TODO: Add attribution instead of uid.
     optional int32 uid = 1;
 
+    // Type of wakelock.
+    enum Type {
+        PARTIAL = 0;
+        FULL = 1;
+        WINDOW = 2;
+    }
+    optional int32 type = 2;
+
+    // The wakelock tag (Called tag in the Java API, sometimes name elsewhere).
+    optional string tag = 3;
+
+    enum State {
+        OFF = 0;
+        ON = 1;
+    }
+    optional State state = 4;
+}
+
+/**
+ * Logs when an app is holding a wakelock, regardless of the wakelock's name.
+ *
+ * Logged from:
+ *   frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ */
+message UidWakelockStateChanged {
+    // TODO: Add attribution instead of uid.
+    optional int32 uid = 1;
+
+    // Type of wakelock.
+    enum Type {
+        PARTIAL = 0;
+        FULL = 1;
+        WINDOW = 2;
+    }
+    optional int32 type = 2;
+
+    enum State {
+        OFF = 0;
+        ON = 1;
+    }
+    optional State state = 3;
+}
+
+/**
+ * Logs when a partial wakelock is considered 'long' (over 1 min).
+ *
+ * Logged from:
+ *   frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ */
+message LongPartialWakelockStateChanged {
+    // TODO: Add attribution instead of uid?
+    optional int32 uid = 1;
+
     // The wakelock tag (Called tag in the Java API, sometimes name elsewhere).
     optional string tag = 2;
 
-    // TODO: Use a constant instead of boolean?
-    optional bool state = 3;
+    // TODO: I have no idea what this is.
+    optional string history_tag = 3;
+
+    enum State {
+        OFF = 0;
+        ON = 1;
+    }
+    optional State state = 4;
 }
 
+/**
+ * Logs Battery Saver state change.
+ *
+ * Logged from:
+ *   frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ */
+message BatterySaverModeStateChanged {
+    enum State {
+        OFF = 0;
+        ON = 1;
+    }
+    optional State state = 1;
+}
+
+/**
+ * Logs Doze mode state change.
+ *
+ * Logged from:
+ *   frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
+ */
+message DeviceIdleModeStateChanged {
+    // TODO: Use the enum matching BatteryStats.DEVICE_IDLE_MODE_.
+    optional int32 state = 1;
+}
+
+/**
+ * Logs screen brightness level.
+ *
+ * Logged from:
+ *   frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
+ */
+message ScreenBrightnessChanged {
+    // Screen brightness level. Should be in [-1, 255] according to PowerManager.java.
+    optional int32 level = 1;
+}
\ No newline at end of file
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index 66a31a5..1e37ff8 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -143,9 +143,11 @@
   message ValueMetricDataWrapper {
     repeated ValueMetricData data = 1;
   }
+
   message GaugeMetricDataWrapper {
     repeated GaugeMetricData data = 1;
   }
+
   oneof data {
     EventMetricDataWrapper event_metrics = 4;
     CountMetricDataWrapper count_metrics = 5;
diff --git a/cmds/statsd/src/stats_util.h b/cmds/statsd/src/stats_util.h
index a428752..d3d7e37 100644
--- a/cmds/statsd/src/stats_util.h
+++ b/cmds/statsd/src/stats_util.h
@@ -30,14 +30,6 @@
 #define MATCHER_NOT_FOUND -2
 #define NANO_SECONDS_IN_A_SECOND (1000 * 1000 * 1000)
 
-// TODO: Remove the following constants once they are exposed in ProtOutputStream.h
-const uint64_t FIELD_TYPE_SHIFT = 32;
-const uint64_t TYPE_MESSAGE = 11ULL << FIELD_TYPE_SHIFT;
-const uint64_t TYPE_INT64 = 3ULL << FIELD_TYPE_SHIFT;
-const uint64_t TYPE_INT32 = 5ULL << FIELD_TYPE_SHIFT;
-const uint64_t TYPE_FLOAT = 2ULL << FIELD_TYPE_SHIFT;
-const uint64_t TYPE_STRING = 9ULL << FIELD_TYPE_SHIFT;
-
 typedef std::string HashableDimensionKey;
 
 typedef std::map<std::string, HashableDimensionKey> ConditionKey;
diff --git a/cmds/statsd/tests/MetricsManager_test.cpp b/cmds/statsd/tests/MetricsManager_test.cpp
index 2af17c2..e8e4d8b 100644
--- a/cmds/statsd/tests/MetricsManager_test.cpp
+++ b/cmds/statsd/tests/MetricsManager_test.cpp
@@ -18,6 +18,7 @@
 #include "src/matchers/LogMatchingTracker.h"
 #include "src/metrics/CountMetricProducer.h"
 #include "src/metrics/MetricProducer.h"
+#include "src/metrics/ValueMetricProducer.h"
 #include "src/metrics/metrics_manager_util.h"
 
 #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 2305957..064e978 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -687,6 +687,7 @@
      * in portrait mode or at the left half of the screen if in landscape mode.
      * @hide
      */
+    @TestApi
     public static final int SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT = 0;
 
     /**
@@ -696,6 +697,7 @@
      * in portrait mode or at the right half of the screen if in landscape mode.
      * @hide
      */
+    @TestApi
     public static final int SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT = 1;
 
     /**
@@ -1926,6 +1928,33 @@
     }
 
     /**
+     * Moves the input task to the primary-split-screen stack.
+     * @param taskId Id of task to move.
+     * @param createMode The mode the primary split screen stack should be created in if it doesn't
+     *                  exist already. See
+     *                   {@link android.app.ActivityManager#SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT}
+     *                   and
+     *                   {@link android.app.ActivityManager
+     *                        #SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT}
+     * @param toTop If the task and stack should be moved to the top.
+     * @param animate Whether we should play an animation for the moving the task
+     * @param initialBounds If the primary stack gets created, it will use these bounds for the
+     *                      docked stack. Pass {@code null} to use default bounds.
+     * @hide
+     */
+    @TestApi
+    @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
+    public void setTaskWindowingModeSplitScreenPrimary(int taskId, int createMode, boolean toTop,
+            boolean animate, Rect initialBounds) throws SecurityException {
+        try {
+            getService().setTaskWindowingModeSplitScreenPrimary(taskId, createMode, toTop, animate,
+                    initialBounds);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Resizes the input stack id to the given bounds.
      * @param stackId Id of the stack to resize.
      * @param bounds Bounds to resize the stack to or {@code null} for fullscreen.
diff --git a/core/java/android/app/VrManager.java b/core/java/android/app/VrManager.java
index 5c6ffa3..392387a 100644
--- a/core/java/android/app/VrManager.java
+++ b/core/java/android/app/VrManager.java
@@ -198,4 +198,20 @@
             e.rethrowFromSystemServer();
         }
     }
+
+    /**
+     * Sets the current standby status of the VR device. Standby mode is only used on standalone vr
+     * devices. Standby mode is a deep sleep state where it's appropriate to turn off vr mode.
+     *
+     * @param standby True if the device is entering standby, false if it's exiting standby.
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.ACCESS_VR_MANAGER)
+    public void setStandbyEnabled(boolean standby) {
+        try {
+            mService.setStandbyEnabled(standby);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
 }
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index e47de75..dd729a3 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3444,11 +3444,12 @@
     /**
      * A broadcast action to trigger a factory reset.
      *
-     * <p> The sender must hold the {@link android.Manifest.permission#MASTER_CLEAR} permission.
+     * <p>The sender must hold the {@link android.Manifest.permission#MASTER_CLEAR} permission. The
+     * reason for the factory reset should be specified as {@link #EXTRA_REASON}.
      *
      * <p>Not for use by third-party applications.
      *
-     * @see #EXTRA_FORCE_MASTER_CLEAR
+     * @see #EXTRA_FORCE_FACTORY_RESET
      *
      * {@hide}
      */
@@ -4827,7 +4828,13 @@
     /** @hide */
     public static final int EXTRA_TIME_PREF_VALUE_USE_LOCALE_DEFAULT = 2;
 
-    /** {@hide} */
+    /**
+     * Intent extra: the reason that the operation associated with this intent is being performed.
+     *
+     * <p>Type: String
+     * @hide
+     */
+    @SystemApi
     public static final String EXTRA_REASON = "android.intent.extra.REASON";
 
     /**
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index b94a410..05c5556 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -671,9 +671,13 @@
     }
 
     /**
-     * Returns whether the caller can access the shortcut information.
+     * Returns whether the caller can access the shortcut information.  Access is currently
+     * available to:
      *
-     * <p>Only the default launcher can access the shortcut information.
+     * <ul>
+     *     <li>The current launcher (or default launcher if there is no set current launcher).</li>
+     *     <li>The currently active voice interaction service.</li>
+     * </ul>
      *
      * <p>Note when this method returns {@code false}, it may be a temporary situation because
      * the user is trying a new launcher application.  The user may decide to change the default
diff --git a/core/java/android/content/pm/ShortcutServiceInternal.java b/core/java/android/content/pm/ShortcutServiceInternal.java
index 7fc25d8..dadfaa9 100644
--- a/core/java/android/content/pm/ShortcutServiceInternal.java
+++ b/core/java/android/content/pm/ShortcutServiceInternal.java
@@ -73,6 +73,9 @@
     public abstract boolean hasShortcutHostPermission(int launcherUserId,
             @NonNull String callingPackage, int callingPid, int callingUid);
 
+    public abstract void setShortcutHostPackage(@NonNull String type, @Nullable String packageName,
+            int userId);
+
     public abstract boolean requestPinAppWidget(@NonNull String callingPackage,
             @NonNull AppWidgetProviderInfo appWidget, @Nullable Bundle extras,
             @Nullable IntentSender resultIntent, int userId);
diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java
index 386239c..3239212 100644
--- a/core/java/android/content/res/ResourcesImpl.java
+++ b/core/java/android/content/res/ResourcesImpl.java
@@ -49,6 +49,8 @@
 import android.util.Xml;
 import android.view.DisplayAdjustments;
 
+import com.android.internal.util.GrowingArrayUtils;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -117,6 +119,13 @@
     private final ConfigurationBoundResourceCache<StateListAnimator> mStateListAnimatorCache =
             new ConfigurationBoundResourceCache<>();
 
+    // A stack of all the resourceIds already referenced when parsing a resource. This is used to
+    // detect circular references in the xml.
+    // Using a ThreadLocal variable ensures that we have different stacks for multiple parallel
+    // calls to ResourcesImpl
+    private final ThreadLocal<LookupStack> mLookupStack =
+            ThreadLocal.withInitial(() -> new LookupStack());
+
     /** Size of the cyclical cache used to map XML files to blocks. */
     private static final int XML_BLOCK_CACHE_SIZE = 4;
 
@@ -784,19 +793,29 @@
         final Drawable dr;
 
         Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
+        LookupStack stack = mLookupStack.get();
         try {
-            if (file.endsWith(".xml")) {
-                final XmlResourceParser rp = loadXmlResourceParser(
-                        file, id, value.assetCookie, "drawable");
-                dr = Drawable.createFromXmlForDensity(wrapper, rp, density, theme);
-                rp.close();
-            } else {
-                final InputStream is = mAssets.openNonAsset(
-                        value.assetCookie, file, AssetManager.ACCESS_STREAMING);
-                dr = Drawable.createFromResourceStream(wrapper, value, is, file, null);
-                is.close();
+            // Perform a linear search to check if we have already referenced this resource before.
+            if (stack.contains(id)) {
+                throw new Exception("Recursive reference in drawable");
             }
-        } catch (Exception | StackOverflowError e) {
+            stack.push(id);
+            try {
+                if (file.endsWith(".xml")) {
+                    final XmlResourceParser rp = loadXmlResourceParser(
+                            file, id, value.assetCookie, "drawable");
+                    dr = Drawable.createFromXmlForDensity(wrapper, rp, density, theme);
+                    rp.close();
+                } else {
+                    final InputStream is = mAssets.openNonAsset(
+                            value.assetCookie, file, AssetManager.ACCESS_STREAMING);
+                    dr = Drawable.createFromResourceStream(wrapper, value, is, file, null);
+                    is.close();
+                }
+            } finally {
+                stack.pop();
+            }
+        } catch (Exception e) {
             Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
             final NotFoundException rnf = new NotFoundException(
                     "File " + file + " from drawable resource ID #0x" + Integer.toHexString(id));
@@ -1377,4 +1396,29 @@
             }
         }
     }
+
+    private static class LookupStack {
+
+        // Pick a reasonable default size for the array, it is grown as needed.
+        private int[] mIds = new int[4];
+        private int mSize = 0;
+
+        public void push(int id) {
+            mIds = GrowingArrayUtils.append(mIds, mSize, id);
+            mSize++;
+        }
+
+        public boolean contains(int id) {
+            for (int i = 0; i < mSize; i++) {
+                if (mIds[i] == id) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public void pop() {
+            mSize--;
+        }
+    }
 }
diff --git a/core/java/android/database/sqlite/SQLiteConnection.java b/core/java/android/database/sqlite/SQLiteConnection.java
index c28583e..361b81b 100644
--- a/core/java/android/database/sqlite/SQLiteConnection.java
+++ b/core/java/android/database/sqlite/SQLiteConnection.java
@@ -289,7 +289,9 @@
 
     private void setWalModeFromConfiguration() {
         if (!mConfiguration.isInMemoryDb() && !mIsReadOnlyConnection) {
-            if ((mConfiguration.openFlags & SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING) != 0) {
+            boolean walEnabled =
+                    (mConfiguration.openFlags & SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING) != 0;
+            if (walEnabled || mConfiguration.useCompatibilityWal) {
                 setJournalMode("WAL");
                 setSyncMode(SQLiteGlobal.getWALSyncMode());
             } else {
diff --git a/core/java/android/database/sqlite/SQLiteCursor.java b/core/java/android/database/sqlite/SQLiteCursor.java
index 2dc5ca4..13e6f71 100644
--- a/core/java/android/database/sqlite/SQLiteCursor.java
+++ b/core/java/android/database/sqlite/SQLiteCursor.java
@@ -22,6 +22,8 @@
 import android.os.StrictMode;
 import android.util.Log;
 
+import com.android.internal.util.Preconditions;
+
 import java.util.HashMap;
 import java.util.Map;
 
@@ -60,6 +62,9 @@
     /** Used to find out where a cursor was allocated in case it never got released. */
     private final Throwable mStackTrace;
 
+    /** Controls fetching of rows relative to requested position **/
+    private boolean mFillWindowForwardOnly;
+
     /**
      * Execute a query and provide access to its result set through a Cursor
      * interface. For a query such as: {@code SELECT name, birth, phone FROM
@@ -136,18 +141,19 @@
 
     private void fillWindow(int requiredPos) {
         clearOrCreateWindow(getDatabase().getPath());
-
         try {
+            Preconditions.checkArgumentNonnegative(requiredPos,
+                    "requiredPos cannot be negative, but was " + requiredPos);
+
             if (mCount == NO_COUNT) {
-                int startPos = DatabaseUtils.cursorPickFillWindowStartPosition(requiredPos, 0);
-                mCount = mQuery.fillWindow(mWindow, startPos, requiredPos, true);
+                mCount = mQuery.fillWindow(mWindow, requiredPos, requiredPos, true);
                 mCursorWindowCapacity = mWindow.getNumRows();
                 if (Log.isLoggable(TAG, Log.DEBUG)) {
                     Log.d(TAG, "received count(*) from native_fill_window: " + mCount);
                 }
             } else {
-                int startPos = DatabaseUtils.cursorPickFillWindowStartPosition(requiredPos,
-                        mCursorWindowCapacity);
+                int startPos = mFillWindowForwardOnly ? requiredPos : DatabaseUtils
+                        .cursorPickFillWindowStartPosition(requiredPos, mCursorWindowCapacity);
                 mQuery.fillWindow(mWindow, startPos, requiredPos, false);
             }
         } catch (RuntimeException ex) {
@@ -252,6 +258,20 @@
     }
 
     /**
+     * Controls fetching of rows relative to requested position.
+     *
+     * <p>Calling this method defines how rows will be loaded, but it doesn't affect rows that
+     * are already in the window. This setting is preserved if a new window is
+     * {@link #setWindow(CursorWindow) set}
+     *
+     * @param fillWindowForwardOnly if true, rows will be fetched starting from requested position
+     * up to the window's capacity. Default value is false.
+     */
+    public void setFillWindowForwardOnly(boolean fillWindowForwardOnly) {
+        mFillWindowForwardOnly = fillWindowForwardOnly;
+    }
+
+    /**
      * Release the native resources, if they haven't been released yet.
      */
     @Override
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index df0e262..83b8dc7 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -285,6 +285,7 @@
             }
         }
         mConfigurationLocked.idleConnectionTimeoutMs = effectiveTimeoutMs;
+        mConfigurationLocked.useCompatibilityWal = SQLiteGlobal.isCompatibilityWalSupported();
     }
 
     @Override
@@ -2070,15 +2071,21 @@
         synchronized (mLock) {
             throwIfNotOpenLocked();
 
-            if ((mConfigurationLocked.openFlags & ENABLE_WRITE_AHEAD_LOGGING) == 0) {
+            final boolean oldUseCompatibilityWal = mConfigurationLocked.useCompatibilityWal;
+            final int oldFlags = mConfigurationLocked.openFlags;
+            if (!oldUseCompatibilityWal && (oldFlags & ENABLE_WRITE_AHEAD_LOGGING) == 0) {
                 return;
             }
 
             mConfigurationLocked.openFlags &= ~ENABLE_WRITE_AHEAD_LOGGING;
+            // If an app explicitly disables WAL, do not even use compatibility mode
+            mConfigurationLocked.useCompatibilityWal = false;
+
             try {
                 mConnectionPoolLocked.reconfigure(mConfigurationLocked);
             } catch (RuntimeException ex) {
-                mConfigurationLocked.openFlags |= ENABLE_WRITE_AHEAD_LOGGING;
+                mConfigurationLocked.openFlags = oldFlags;
+                mConfigurationLocked.useCompatibilityWal = oldUseCompatibilityWal;
                 throw ex;
             }
         }
diff --git a/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java b/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java
index 34c9b33..905da724 100644
--- a/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java
+++ b/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java
@@ -111,6 +111,15 @@
     public long idleConnectionTimeoutMs = Long.MAX_VALUE;
 
     /**
+     * Enables compatibility WAL mode. Applications cannot explicitly choose compatibility WAL mode,
+     * therefore it is not exposed as a flag.
+     *
+     * <p>In this mode, only database journal mode will be changed, connection pool
+     * size will still be limited to a single connection.
+     */
+    public boolean useCompatibilityWal;
+
+    /**
      * Creates a database configuration with the required parameters for opening a
      * database and default values for all other parameters.
      *
@@ -170,6 +179,7 @@
         lookasideSlotSize = other.lookasideSlotSize;
         lookasideSlotCount = other.lookasideSlotCount;
         idleConnectionTimeoutMs = other.idleConnectionTimeoutMs;
+        useCompatibilityWal = other.useCompatibilityWal;
     }
 
     /**
diff --git a/core/java/android/database/sqlite/SQLiteGlobal.java b/core/java/android/database/sqlite/SQLiteGlobal.java
index 94d5555..bb2a517 100644
--- a/core/java/android/database/sqlite/SQLiteGlobal.java
+++ b/core/java/android/database/sqlite/SQLiteGlobal.java
@@ -81,6 +81,17 @@
     }
 
     /**
+     * Returns true if compatibility WAL mode is supported. In this mode, only
+     * database journal mode is changed. Connection pool will use at most one connection.
+     * @hide
+     */
+    public static boolean isCompatibilityWalSupported() {
+        return SystemProperties.getBoolean("debug.sqlite.compatibility_wal_supported",
+                Resources.getSystem().getBoolean(
+                        com.android.internal.R.bool.db_compatibility_wal_supported));
+    }
+
+    /**
      * Gets the journal size limit in bytes.
      */
     public static int getJournalSizeLimit() {
diff --git a/core/java/android/os/BatteryStatsInternal.java b/core/java/android/os/BatteryStatsInternal.java
new file mode 100644
index 0000000..b0436eb
--- /dev/null
+++ b/core/java/android/os/BatteryStatsInternal.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 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.os;
+
+/**
+ * Battery stats local system service interface. This is used to pass internal data out of
+ * BatteryStatsImpl.
+ *
+ * @hide Only for use within Android OS.
+ */
+public abstract class BatteryStatsInternal {
+    /**
+     * Returns the wifi interfaces.
+     */
+    public abstract String[] getWifiIfaces();
+
+    /**
+     * Returns the mobile data interfaces.
+     */
+    public abstract String[] getMobileIfaces();
+}
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 5b0e5bbc..f977c1d 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -836,7 +836,6 @@
      *         physically removed.
      */
     public static boolean isExternalStorageRemovable() {
-        if (isStorageDisabled()) return false;
         final File externalDir = sCurrentUser.getExternalDirs()[0];
         return isExternalStorageRemovable(externalDir);
     }
@@ -875,7 +874,6 @@
      *      boolean)
      */
     public static boolean isExternalStorageEmulated() {
-        if (isStorageDisabled()) return false;
         final File externalDir = sCurrentUser.getExternalDirs()[0];
         return isExternalStorageEmulated(externalDir);
     }
@@ -951,9 +949,6 @@
         return cur;
     }
 
-    private static boolean isStorageDisabled() {
-        return SystemProperties.getBoolean("config.disable_storage", false);
-    }
 
     /**
      * If the given path exists on emulated external storage, return the
diff --git a/core/java/android/os/HidlSupport.java b/core/java/android/os/HidlSupport.java
index 7dec4d7..3544ea1 100644
--- a/core/java/android/os/HidlSupport.java
+++ b/core/java/android/os/HidlSupport.java
@@ -156,4 +156,27 @@
         // Should not reach here.
         throw new UnsupportedOperationException();
     }
+
+    /**
+     * Test that two interfaces are equal. This is the Java equivalent to C++
+     * interfacesEqual function.
+     * This essentially calls .equals on the internal binder objects (via Binder()).
+     * - If both interfaces are proxies, asBinder() returns a {@link HwRemoteBinder}
+     *   object, and they are compared in {@link HwRemoteBinder#equals}.
+     * - If both interfaces are stubs, asBinder() returns the object itself. By default,
+     *   auto-generated IFoo.Stub does not override equals(), but an implementation can
+     *   optionally override it, and {@code interfacesEqual} will use it here.
+     */
+    public static boolean interfacesEqual(IHwInterface lft, Object rgt) {
+        if (lft == rgt) {
+            return true;
+        }
+        if (lft == null || rgt == null) {
+            return false;
+        }
+        if (!(rgt instanceof IHwInterface)) {
+            return false;
+        }
+        return Objects.equals(lft.asBinder(), ((IHwInterface) rgt).asBinder());
+    }
 }
diff --git a/core/java/android/os/HwBinder.java b/core/java/android/os/HwBinder.java
index 5e2a081..dd9e774 100644
--- a/core/java/android/os/HwBinder.java
+++ b/core/java/android/os/HwBinder.java
@@ -63,6 +63,13 @@
 
     public static native final void joinRpcThreadpool();
 
+    /**
+     * Call configureRpcThreadpool, then actually spawn
+     * (maxThreads - (callerWillJoin ? 0 : 1)) threads.
+     */
+    public static final native void startRpcThreadPool(
+            long maxThreads, boolean callerWillJoin);
+
     // Returns address of the "freeFunction".
     private static native final long native_init();
 
diff --git a/core/java/android/os/HwRemoteBinder.java b/core/java/android/os/HwRemoteBinder.java
index 2f89ce6..a07e42c 100644
--- a/core/java/android/os/HwRemoteBinder.java
+++ b/core/java/android/os/HwRemoteBinder.java
@@ -63,4 +63,9 @@
     }
 
     private long mNativeContext;
+
+    @Override
+    public final native boolean equals(Object other);
+    @Override
+    public final native int hashCode();
 }
diff --git a/core/java/android/os/IStatsCompanionService.aidl b/core/java/android/os/IStatsCompanionService.aidl
index 20f6c8e..c0a95cc 100644
--- a/core/java/android/os/IStatsCompanionService.aidl
+++ b/core/java/android/os/IStatsCompanionService.aidl
@@ -46,10 +46,10 @@
       * Uses AlarmManager.setRepeating API, so if the timestamp is in past, alarm fires immediately,
       * and alarm is inexact.
       */
-    oneway void setPollingAlarms(long timestampMs, long intervalMs);
+    oneway void setPullingAlarms(long timestampMs, long intervalMs);
 
     /** Cancel any repeating polling alarm. */
-    oneway void cancelPollingAlarms();
+    oneway void cancelPullingAlarms();
 
     /** Pull the specified data. Results will be sent to statsd when complete. */
     StatsLogEventWrapper[] pullData(int pullCode);
diff --git a/core/java/android/os/TokenWatcher.java b/core/java/android/os/TokenWatcher.java
index 9b3a2d6..00333dad 100644
--- a/core/java/android/os/TokenWatcher.java
+++ b/core/java/android/os/TokenWatcher.java
@@ -16,17 +16,23 @@
 
 package android.os;
 
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.WeakHashMap;
-import java.util.Set;
 import android.util.Log;
 
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Set;
+import java.util.WeakHashMap;
+
 /**
- * Helper class that helps you use IBinder objects as reference counted
- * tokens.  IBinders make good tokens because we find out when they are
- * removed
+ * A TokenWatcher watches a collection of {@link IBinder}s. IBinders are added
+ * to the collection by calling {@link #acquire}, and removed by calling {@link
+ * #release}. IBinders are also implicitly removed when they become weakly
+ * reachable. Each IBinder may be added at most once.
  *
+ * The {@link #acquired} method is invoked by posting to the specified handler
+ * whenever the size of the watched collection becomes nonzero.  The {@link
+ * #released} method is invoked on the specified handler whenever the size of
+ * the watched collection becomes zero.
  */
 public abstract class TokenWatcher
 {
@@ -59,15 +65,23 @@
      * Record that this token has been acquired.  When acquire is called, and
      * the current count is 0, the acquired method is called on the given
      * handler.
-     * 
-     * @param token An IBinder object.  If this token has already been acquired,
-     *              no action is taken.
+     *
+     * Note that the same {@code token} can only be acquired once. If this
+     * {@code token} has already been acquired, no action is taken. The first
+     * subsequent call to {@link #release} will release this {@code token}
+     * immediately.
+     *
+     * @param token An IBinder object.
      * @param tag   A string used by the {@link #dump} method for debugging,
      *              to see who has references.
      */
     public void acquire(IBinder token, String tag)
     {
         synchronized (mTokens) {
+            if (mTokens.containsKey(token)) {
+                return;
+            }
+
             // explicitly checked to avoid bogus sendNotification calls because
             // of the WeakHashMap and the GC
             int oldSize = mTokens.size();
diff --git a/core/java/android/service/vr/IVrManager.aidl b/core/java/android/service/vr/IVrManager.aidl
index fef9223..7285fb4 100644
--- a/core/java/android/service/vr/IVrManager.aidl
+++ b/core/java/android/service/vr/IVrManager.aidl
@@ -101,5 +101,13 @@
      * application's compositor process to bind to, or null to clear the current binding.
      */
     void setAndBindCompositor(in String componentName);
+
+    /**
+     * Sets the current standby status of the VR device. Standby mode is only used on standalone vr
+     * devices. Standby mode is a deep sleep state where it's appropriate to turn off vr mode.
+     *
+     * @param standy True if the device is entering standby, false if it's exiting standby.
+     */
+    void setStandbyEnabled(boolean standby);
 }
 
diff --git a/core/java/android/util/proto/ProtoOutputStream.java b/core/java/android/util/proto/ProtoOutputStream.java
index 43a9789..a94806a 100644
--- a/core/java/android/util/proto/ProtoOutputStream.java
+++ b/core/java/android/util/proto/ProtoOutputStream.java
@@ -127,42 +127,48 @@
 
     public static final long FIELD_TYPE_UNKNOWN = 0;
 
+    /**
+     * The types are copied from external/protobuf/src/google/protobuf/descriptor.h directly,
+     * so no extra mapping needs to be maintained in this case.
+     */
     public static final long FIELD_TYPE_DOUBLE = 1L << FIELD_TYPE_SHIFT;
     public static final long FIELD_TYPE_FLOAT = 2L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_INT32 = 3L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_INT64 = 4L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_UINT32 = 5L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_UINT64 = 6L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_SINT32 = 7L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_SINT64 = 8L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_FIXED32 = 9L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_FIXED64 = 10L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_SFIXED32 = 11L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_SFIXED64 = 12L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_BOOL = 13L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_STRING = 14L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_BYTES = 15L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_ENUM = 16L << FIELD_TYPE_SHIFT;
-    public static final long FIELD_TYPE_OBJECT = 17L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_INT64 = 3L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_UINT64 = 4L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_INT32 = 5L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_FIXED64 = 6L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_FIXED32 = 7L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_BOOL = 8L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_STRING = 9L << FIELD_TYPE_SHIFT;
+//  public static final long FIELD_TYPE_GROUP = 10L << FIELD_TYPE_SHIFT; // Deprecated.
+    public static final long FIELD_TYPE_MESSAGE = 11L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_BYTES = 12L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_UINT32 = 13L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_ENUM = 14L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_SFIXED32 = 15L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_SFIXED64 = 16L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_SINT32 = 17L << FIELD_TYPE_SHIFT;
+    public static final long FIELD_TYPE_SINT64 = 18L << FIELD_TYPE_SHIFT;
 
     private static final String[] FIELD_TYPE_NAMES = new String[] {
         "Double",
         "Float",
-        "Int32",
         "Int64",
-        "UInt32",
         "UInt64",
-        "SInt32",
-        "SInt64",
-        "Fixed32",
+        "Int32",
         "Fixed64",
-        "SFixed32",
-        "SFixed64",
+        "Fixed32",
         "Bool",
         "String",
+        "Group",  // This field is deprecated but reserved here for indexing.
+        "Message",
         "Bytes",
+        "UInt32",
         "Enum",
-        "Object",
+        "SFixed32",
+        "SFixed64",
+        "SInt32",
+        "SInt64",
     };
 
     //
@@ -867,21 +873,21 @@
         assertNotCompacted();
         final int id = (int)fieldId;
 
-        switch ((int)((fieldId & (FIELD_TYPE_MASK | FIELD_COUNT_MASK)) >> FIELD_TYPE_SHIFT)) {
+        switch ((int) ((fieldId & (FIELD_TYPE_MASK | FIELD_COUNT_MASK)) >> FIELD_TYPE_SHIFT)) {
             // bytes
-            case (int)((FIELD_TYPE_BYTES | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
+            case (int) ((FIELD_TYPE_BYTES | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
                 writeBytesImpl(id, val);
                 break;
-            case (int)((FIELD_TYPE_BYTES | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
-            case (int)((FIELD_TYPE_BYTES | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
+            case (int) ((FIELD_TYPE_BYTES | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
+            case (int) ((FIELD_TYPE_BYTES | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
                 writeRepeatedBytesImpl(id, val);
                 break;
             // Object
-            case (int)((FIELD_TYPE_OBJECT | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
+            case (int) ((FIELD_TYPE_MESSAGE | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
                 writeObjectImpl(id, val);
                 break;
-            case (int)((FIELD_TYPE_OBJECT | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
-            case (int)((FIELD_TYPE_OBJECT | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
+            case (int) ((FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
+            case (int) ((FIELD_TYPE_MESSAGE | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
                 writeRepeatedObjectImpl(id, val);
                 break;
             // nothing else allowed
@@ -899,7 +905,7 @@
         assertNotCompacted();
         final int id = (int)fieldId;
 
-        if ((fieldId & FIELD_TYPE_MASK) == FIELD_TYPE_OBJECT) {
+        if ((fieldId & FIELD_TYPE_MASK) == FIELD_TYPE_MESSAGE) {
             final long count = fieldId & FIELD_COUNT_MASK;
             if (count == FIELD_COUNT_SINGLE) {
                 return startObjectImpl(id, false);
@@ -2091,7 +2097,7 @@
     @Deprecated
     public long startObject(long fieldId) {
         assertNotCompacted();
-        final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_OBJECT);
+        final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_MESSAGE);
 
         return startObjectImpl(id, false);
     }
@@ -2119,7 +2125,7 @@
     @Deprecated
     public long startRepeatedObject(long fieldId) {
         assertNotCompacted();
-        final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_OBJECT);
+        final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_MESSAGE);
 
         return startObjectImpl(id, true);
     }
@@ -2217,7 +2223,7 @@
     @Deprecated
     public void writeObject(long fieldId, byte[] value) {
         assertNotCompacted();
-        final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_OBJECT);
+        final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_MESSAGE);
 
         writeObjectImpl(id, value);
     }
@@ -2237,7 +2243,7 @@
     @Deprecated
     public void writeRepeatedObject(long fieldId, byte[] value) {
         assertNotCompacted();
-        final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_OBJECT);
+        final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_MESSAGE);
 
         writeRepeatedObjectImpl(id, value);
     }
@@ -2296,7 +2302,7 @@
             final String typeString = getFieldTypeString(fieldType);
             if (typeString != null && countString != null) {
                 final StringBuilder sb = new StringBuilder();
-                if (expectedType == FIELD_TYPE_OBJECT) {
+                if (expectedType == FIELD_TYPE_MESSAGE) {
                     sb.append("start");
                 } else {
                     sb.append("write");
@@ -2306,7 +2312,7 @@
                 sb.append(" called for field ");
                 sb.append((int)fieldId);
                 sb.append(" which should be used with ");
-                if (fieldType == FIELD_TYPE_OBJECT) {
+                if (fieldType == FIELD_TYPE_MESSAGE) {
                     sb.append("start");
                 } else {
                     sb.append("write");
@@ -2321,7 +2327,7 @@
                 throw new IllegalArgumentException(sb.toString());
             } else {
                 final StringBuilder sb = new StringBuilder();
-                if (expectedType == FIELD_TYPE_OBJECT) {
+                if (expectedType == FIELD_TYPE_MESSAGE) {
                     sb.append("start");
                 } else {
                     sb.append("write");
diff --git a/core/java/android/view/NotificationHeaderView.java b/core/java/android/view/NotificationHeaderView.java
index 5804560..ab0b3ee 100644
--- a/core/java/android/view/NotificationHeaderView.java
+++ b/core/java/android/view/NotificationHeaderView.java
@@ -20,6 +20,7 @@
 import android.app.Notification;
 import android.content.Context;
 import android.content.res.Resources;
+import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.Outline;
 import android.graphics.Rect;
@@ -43,6 +44,7 @@
     public static final int NO_COLOR = Notification.COLOR_INVALID;
     private final int mChildMinWidth;
     private final int mContentEndMargin;
+    private final int mGravity;
     private View mAppName;
     private View mHeaderText;
     private OnClickListener mExpandClickListener;
@@ -50,7 +52,6 @@
     private ImageView mExpandButton;
     private CachingIconView mIcon;
     private View mProfileBadge;
-    private View mInfo;
     private int mIconColor;
     private int mOriginalNotificationColor;
     private boolean mExpanded;
@@ -61,6 +62,7 @@
     private boolean mEntireHeaderClickable;
     private boolean mExpandOnlyOnButton;
     private boolean mAcceptAllTouches;
+    private int mTotalWidth;
 
     ViewOutlineProvider mProvider = new ViewOutlineProvider() {
         @Override
@@ -92,6 +94,11 @@
         mHeaderBackgroundHeight = res.getDimensionPixelSize(
                 R.dimen.notification_header_background_height);
         mEntireHeaderClickable = res.getBoolean(R.bool.config_notificationHeaderClickableForExpand);
+
+        int[] attrIds = { android.R.attr.gravity };
+        TypedArray ta = context.obtainStyledAttributes(attrs, attrIds, defStyleAttr, defStyleRes);
+        mGravity = ta.getInt(0, 0);
+        ta.recycle();
     }
 
     @Override
@@ -146,6 +153,7 @@
                 mHeaderText.measure(childWidthSpec, wrapContentHeightSpec);
             }
         }
+        mTotalWidth = Math.min(totalWidth, givenWidth);
         setMeasuredDimension(givenWidth, givenHeight);
     }
 
@@ -153,6 +161,10 @@
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
         int left = getPaddingStart();
         int end = getMeasuredWidth();
+        final boolean centerAligned = (mGravity & Gravity.CENTER_HORIZONTAL) != 0;
+        if (centerAligned) {
+            left += getMeasuredWidth() / 2 - mTotalWidth / 2;
+        }
         int childCount = getChildCount();
         int ownHeight = getMeasuredHeight() - getPaddingTop() - getPaddingBottom();
         for (int i = 0; i < childCount; i++) {
diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
index 19213ca..c3d6c69 100644
--- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
@@ -187,8 +187,11 @@
                     Log.i(LOG_TAG, "Window cache miss");
                 }
                 final long identityToken = Binder.clearCallingIdentity();
-                window = connection.getWindow(accessibilityWindowId);
-                Binder.restoreCallingIdentity(identityToken);
+                try {
+                    window = connection.getWindow(accessibilityWindowId);
+                } finally {
+                    Binder.restoreCallingIdentity(identityToken);
+                }
                 if (window != null) {
                     sAccessibilityCache.addWindow(window);
                     return window;
@@ -225,8 +228,11 @@
                     Log.i(LOG_TAG, "Windows cache miss");
                 }
                 final long identityToken = Binder.clearCallingIdentity();
-                windows = connection.getWindows();
-                Binder.restoreCallingIdentity(identityToken);
+                try {
+                    windows = connection.getWindows();
+                } finally {
+                    Binder.restoreCallingIdentity(identityToken);
+                }
                 if (windows != null) {
                     sAccessibilityCache.setWindows(windows);
                     return windows;
@@ -283,10 +289,14 @@
                 }
                 final int interactionId = mInteractionIdCounter.getAndIncrement();
                 final long identityToken = Binder.clearCallingIdentity();
-                final boolean success = connection.findAccessibilityNodeInfoByAccessibilityId(
-                        accessibilityWindowId, accessibilityNodeId, interactionId, this,
-                        prefetchFlags, Thread.currentThread().getId(), arguments);
-                Binder.restoreCallingIdentity(identityToken);
+                final boolean success;
+                try {
+                    success = connection.findAccessibilityNodeInfoByAccessibilityId(
+                            accessibilityWindowId, accessibilityNodeId, interactionId, this,
+                            prefetchFlags, Thread.currentThread().getId(), arguments);
+                } finally {
+                    Binder.restoreCallingIdentity(identityToken);
+                }
                 if (success) {
                     List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
                             interactionId);
@@ -333,10 +343,15 @@
             if (connection != null) {
                 final int interactionId = mInteractionIdCounter.getAndIncrement();
                 final long identityToken = Binder.clearCallingIdentity();
-                final boolean success = connection.findAccessibilityNodeInfosByViewId(
-                        accessibilityWindowId, accessibilityNodeId, viewId, interactionId, this,
-                        Thread.currentThread().getId());
-                Binder.restoreCallingIdentity(identityToken);
+                final boolean success;
+                try {
+                    success = connection.findAccessibilityNodeInfosByViewId(
+                            accessibilityWindowId, accessibilityNodeId, viewId, interactionId, this,
+                            Thread.currentThread().getId());
+                } finally {
+                    Binder.restoreCallingIdentity(identityToken);
+                }
+
                 if (success) {
                     List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
                             interactionId);
@@ -381,10 +396,15 @@
             if (connection != null) {
                 final int interactionId = mInteractionIdCounter.getAndIncrement();
                 final long identityToken = Binder.clearCallingIdentity();
-                final boolean success = connection.findAccessibilityNodeInfosByText(
-                        accessibilityWindowId, accessibilityNodeId, text, interactionId, this,
-                        Thread.currentThread().getId());
-                Binder.restoreCallingIdentity(identityToken);
+                final boolean success;
+                try {
+                    success = connection.findAccessibilityNodeInfosByText(
+                            accessibilityWindowId, accessibilityNodeId, text, interactionId, this,
+                            Thread.currentThread().getId());
+                } finally {
+                    Binder.restoreCallingIdentity(identityToken);
+                }
+
                 if (success) {
                     List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
                             interactionId);
@@ -428,10 +448,15 @@
             if (connection != null) {
                 final int interactionId = mInteractionIdCounter.getAndIncrement();
                 final long identityToken = Binder.clearCallingIdentity();
-                final boolean success = connection.findFocus(accessibilityWindowId,
-                        accessibilityNodeId, focusType, interactionId, this,
-                        Thread.currentThread().getId());
-                Binder.restoreCallingIdentity(identityToken);
+                final boolean success;
+                try {
+                    success = connection.findFocus(accessibilityWindowId,
+                            accessibilityNodeId, focusType, interactionId, this,
+                            Thread.currentThread().getId());
+                } finally {
+                    Binder.restoreCallingIdentity(identityToken);
+                }
+
                 if (success) {
                     AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear(
                             interactionId);
@@ -472,10 +497,15 @@
             if (connection != null) {
                 final int interactionId = mInteractionIdCounter.getAndIncrement();
                 final long identityToken = Binder.clearCallingIdentity();
-                final boolean success = connection.focusSearch(accessibilityWindowId,
-                        accessibilityNodeId, direction, interactionId, this,
-                        Thread.currentThread().getId());
-                Binder.restoreCallingIdentity(identityToken);
+                final boolean success;
+                try {
+                    success = connection.focusSearch(accessibilityWindowId,
+                            accessibilityNodeId, direction, interactionId, this,
+                            Thread.currentThread().getId());
+                } finally {
+                    Binder.restoreCallingIdentity(identityToken);
+                }
+
                 if (success) {
                     AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear(
                             interactionId);
@@ -515,10 +545,15 @@
             if (connection != null) {
                 final int interactionId = mInteractionIdCounter.getAndIncrement();
                 final long identityToken = Binder.clearCallingIdentity();
-                final boolean success = connection.performAccessibilityAction(
-                        accessibilityWindowId, accessibilityNodeId, action, arguments,
-                        interactionId, this, Thread.currentThread().getId());
-                Binder.restoreCallingIdentity(identityToken);
+                final boolean success;
+                try {
+                    success = connection.performAccessibilityAction(
+                            accessibilityWindowId, accessibilityNodeId, action, arguments,
+                            interactionId, this, Thread.currentThread().getId());
+                } finally {
+                    Binder.restoreCallingIdentity(identityToken);
+                }
+
                 if (success) {
                     return getPerformAccessibilityActionResultAndClear(interactionId);
                 }
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index 0b9bc57..35f6acb 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -436,8 +436,11 @@
             // client using it is called through Binder from another process. Example: MMS
             // app adds a SMS notification and the NotificationManagerService calls this method
             long identityToken = Binder.clearCallingIdentity();
-            service.sendAccessibilityEvent(event, userId);
-            Binder.restoreCallingIdentity(identityToken);
+            try {
+                service.sendAccessibilityEvent(event, userId);
+            } finally {
+                Binder.restoreCallingIdentity(identityToken);
+            }
             if (DEBUG) {
                 Log.i(LOG_TAG, event + " sent");
             }
diff --git a/core/java/com/android/internal/colorextraction/types/Tonal.java b/core/java/com/android/internal/colorextraction/types/Tonal.java
index e6ef10b..71baaf1 100644
--- a/core/java/com/android/internal/colorextraction/types/Tonal.java
+++ b/core/java/com/android/internal/colorextraction/types/Tonal.java
@@ -51,9 +51,11 @@
 
     private static final boolean DEBUG = true;
 
+    public static final int THRESHOLD_COLOR_LIGHT = 0xffe0e0e0;
     public static final int MAIN_COLOR_LIGHT = 0xffe0e0e0;
     public static final int SECONDARY_COLOR_LIGHT = 0xff9e9e9e;
-    public static final int MAIN_COLOR_DARK = 0xff212121;
+    public static final int THRESHOLD_COLOR_DARK = 0xff212121;
+    public static final int MAIN_COLOR_DARK = 0xff000000;
     public static final int SECONDARY_COLOR_DARK = 0xff000000;
 
     private final TonalPalette mGreyPalette;
@@ -197,12 +199,12 @@
         // light fallback or darker than our dark fallback.
         ColorUtils.colorToHSL(mainColor, mTmpHSL);
         final float mainLuminosity = mTmpHSL[2];
-        ColorUtils.colorToHSL(MAIN_COLOR_LIGHT, mTmpHSL);
+        ColorUtils.colorToHSL(THRESHOLD_COLOR_LIGHT, mTmpHSL);
         final float lightLuminosity = mTmpHSL[2];
         if (mainLuminosity > lightLuminosity) {
             return false;
         }
-        ColorUtils.colorToHSL(MAIN_COLOR_DARK, mTmpHSL);
+        ColorUtils.colorToHSL(THRESHOLD_COLOR_DARK, mTmpHSL);
         final float darkLuminosity = mTmpHSL[2];
         if (mainLuminosity < darkLuminosity) {
             return false;
diff --git a/core/java/com/android/internal/os/BaseCommand.java b/core/java/com/android/internal/os/BaseCommand.java
index 3baccee..05ec9e9 100644
--- a/core/java/com/android/internal/os/BaseCommand.java
+++ b/core/java/com/android/internal/os/BaseCommand.java
@@ -106,6 +106,14 @@
     }
 
     /**
+     * Peek the next argument on the command line, whatever it is; if there are
+     * no arguments left, return null.
+     */
+    public String peekNextArg() {
+        return mArgs.peekNextArg();
+    }
+
+    /**
      * Return the next argument on the command line, whatever it is; if there are
      * no arguments left, throws an IllegalArgumentException to report this to the user.
      */
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index f0d05da..0535ebe 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -5412,6 +5412,18 @@
         }
     }
 
+    public String[] getWifiIfaces() {
+        synchronized (mWifiNetworkLock) {
+            return mWifiIfaces;
+        }
+    }
+
+    public String[] getMobileIfaces() {
+        synchronized (mModemNetworkLock) {
+            return mModemIfaces;
+        }
+    }
+
     @Override public long getScreenOnTime(long elapsedRealtimeUs, int which) {
         return mScreenOnTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
     }
diff --git a/core/java/com/android/internal/policy/DividerSnapAlgorithm.java b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
index fb6b8b0..3af3e2a 100644
--- a/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
+++ b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
@@ -16,6 +16,10 @@
 
 package com.android.internal.policy;
 
+import static android.view.WindowManager.DOCKED_INVALID;
+import static android.view.WindowManager.DOCKED_LEFT;
+import static android.view.WindowManager.DOCKED_RIGHT;
+
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
@@ -99,11 +103,12 @@
 
     public DividerSnapAlgorithm(Resources res, int displayWidth, int displayHeight, int dividerSize,
             boolean isHorizontalDivision, Rect insets) {
-        this(res, displayWidth, displayHeight, dividerSize, isHorizontalDivision, insets, false);
+        this(res, displayWidth, displayHeight, dividerSize, isHorizontalDivision, insets,
+                DOCKED_INVALID, false);
     }
 
     public DividerSnapAlgorithm(Resources res, int displayWidth, int displayHeight, int dividerSize,
-            boolean isHorizontalDivision, Rect insets, boolean isMinimizedMode) {
+            boolean isHorizontalDivision, Rect insets, int dockSide, boolean isMinimizedMode) {
         mMinFlingVelocityPxPerSecond =
                 MIN_FLING_VELOCITY_DP_PER_SECOND * res.getDisplayMetrics().density;
         mMinDismissVelocityPxPerSecond =
@@ -121,7 +126,7 @@
                 com.android.internal.R.dimen.default_minimal_size_resizable_task);
         mTaskHeightInMinimizedMode = res.getDimensionPixelSize(
                 com.android.internal.R.dimen.task_height_of_minimized_mode);
-        calculateTargets(isHorizontalDivision);
+        calculateTargets(isHorizontalDivision, dockSide);
         mFirstSplitTarget = mTargets.get(1);
         mLastSplitTarget = mTargets.get(mTargets.size() - 2);
         mDismissStartTarget = mTargets.get(0);
@@ -254,7 +259,7 @@
         return mTargets.get(minIndex);
     }
 
-    private void calculateTargets(boolean isHorizontalDivision) {
+    private void calculateTargets(boolean isHorizontalDivision, int dockedSide) {
         mTargets.clear();
         int dividerMax = isHorizontalDivision
                 ? mDisplayHeight
@@ -273,7 +278,7 @@
                 addMiddleTarget(isHorizontalDivision);
                 break;
             case SNAP_MODE_MINIMIZED:
-                addMinimizedTarget(isHorizontalDivision);
+                addMinimizedTarget(isHorizontalDivision, dockedSide);
                 break;
         }
         mTargets.add(new SnapTarget(dividerMax - navBarSize, dividerMax,
@@ -331,12 +336,16 @@
         mTargets.add(new SnapTarget(position, position, SnapTarget.FLAG_NONE));
     }
 
-    private void addMinimizedTarget(boolean isHorizontalDivision) {
+    private void addMinimizedTarget(boolean isHorizontalDivision, int dockedSide) {
         // In portrait offset the position by the statusbar height, in landscape add the statusbar
         // height as well to match portrait offset
         int position = mTaskHeightInMinimizedMode + mInsets.top;
         if (!isHorizontalDivision) {
-            position += mInsets.left;
+            if (dockedSide == DOCKED_LEFT) {
+                position += mInsets.left;
+            } else if (dockedSide == DOCKED_RIGHT) {
+                position = mDisplayWidth - position - mInsets.right;
+            }
         }
         mTargets.add(new SnapTarget(position, position, SnapTarget.FLAG_NONE));
     }
diff --git a/core/java/com/android/internal/widget/NotificationActionListLayout.java b/core/java/com/android/internal/widget/NotificationActionListLayout.java
index 073aac5..26023b4 100644
--- a/core/java/com/android/internal/widget/NotificationActionListLayout.java
+++ b/core/java/com/android/internal/widget/NotificationActionListLayout.java
@@ -16,7 +16,10 @@
 
 package com.android.internal.widget;
 
+import android.annotation.Nullable;
 import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.util.Pair;
@@ -37,6 +40,7 @@
 @RemoteViews.RemoteView
 public class NotificationActionListLayout extends LinearLayout {
 
+    private final int mGravity;
     private int mTotalWidth = 0;
     private ArrayList<Pair<Integer, TextView>> mMeasureOrderTextViews = new ArrayList<>();
     private ArrayList<View> mMeasureOrderOther = new ArrayList<>();
@@ -45,7 +49,20 @@
     private Drawable mDefaultBackground;
 
     public NotificationActionListLayout(Context context, AttributeSet attrs) {
-        super(context, attrs);
+        this(context, attrs, 0);
+    }
+
+    public NotificationActionListLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    public NotificationActionListLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+
+        int[] attrIds = { android.R.attr.gravity };
+        TypedArray ta = context.obtainStyledAttributes(attrs, attrIds, defStyleAttr, defStyleRes);
+        mGravity = ta.getInt(0, 0);
+        ta.recycle();
     }
 
     @Override
@@ -95,6 +112,7 @@
 
         final boolean constrained =
                 MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.UNSPECIFIED;
+        final boolean centerAligned = (mGravity & Gravity.CENTER_HORIZONTAL) != 0;
 
         final int innerWidth = MeasureSpec.getSize(widthMeasureSpec) - mPaddingLeft - mPaddingRight;
         final int otherSize = mMeasureOrderOther.size();
@@ -137,7 +155,7 @@
 
         // Make sure to measure the last child full-width if we didn't use up the entire width,
         // or we didn't measure yet because there's just one child.
-        if (lastNotGoneChild != null && (constrained && usedWidth < innerWidth
+        if (lastNotGoneChild != null && !centerAligned && (constrained && usedWidth < innerWidth
                 || notGoneChildren == 1)) {
             MarginLayoutParams lp = (MarginLayoutParams) lastNotGoneChild.getLayoutParams();
             if (notGoneChildren > 1) {
@@ -201,9 +219,10 @@
         }
         final boolean isLayoutRtl = isLayoutRtl();
         final int paddingTop = mPaddingTop;
+        final boolean centerAligned = (mGravity & Gravity.CENTER_HORIZONTAL) != 0;
 
         int childTop;
-        int childLeft;
+        int childLeft = centerAligned ? left + (right - left) / 2 - mTotalWidth / 2 : 0;
 
         // Where bottom of child should go
         final int height = bottom - top;
@@ -216,13 +235,12 @@
         final int layoutDirection = getLayoutDirection();
         switch (Gravity.getAbsoluteGravity(Gravity.START, layoutDirection)) {
             case Gravity.RIGHT:
-                // mTotalWidth contains the padding already
-                childLeft = mPaddingLeft + right - left - mTotalWidth;
+                childLeft += mPaddingLeft + right - left - mTotalWidth;
                 break;
 
             case Gravity.LEFT:
             default:
-                childLeft = mPaddingLeft;
+                childLeft += mPaddingLeft;
                 break;
         }
 
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index f88db25..fb8b9f7 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -185,7 +185,6 @@
         "android/opengl/poly_clip.cpp", // TODO: .arm
         "android/opengl/util.cpp",
         "android_server_NetworkManagementSocketTagger.cpp",
-        "android_server_Watchdog.cpp",
         "android_ddm_DdmHandleNativeHeap.cpp",
         "android_backup_BackupDataInput.cpp",
         "android_backup_BackupDataOutput.cpp",
diff --git a/core/jni/android_os_HwBinder.cpp b/core/jni/android_os_HwBinder.cpp
index 08d9527..f6783e1 100644
--- a/core/jni/android_os_HwBinder.cpp
+++ b/core/jni/android_os_HwBinder.cpp
@@ -344,6 +344,17 @@
     IPCThreadState::self()->joinThreadPool();
 }
 
+void JHwBinder_native_startRpcThreadPool(JNIEnv *, jclass,
+        jlong maxThreads, jboolean callerWillJoin) {
+    CHECK(maxThreads > 0);
+    ProcessState::self()->setThreadPoolConfiguration(maxThreads,
+                                                     callerWillJoin /* callerJoinsPool */);
+    ssize_t threadsNeeded = maxThreads - (callerWillJoin ? 0 : 1);
+    for (ssize_t i = 0; i < threadsNeeded; ++i) {
+        ProcessState::self()->spawnPooledThread(false /* isMain */);
+    }
+}
+
 static void JHwBinder_report_sysprop_change(JNIEnv * /*env*/, jclass /*clazz*/)
 {
     report_sysprop_change();
@@ -369,6 +380,9 @@
     { "joinRpcThreadpool", "()V",
         (void *)JHwBinder_native_joinRpcThreadpool },
 
+    { "startRpcThreadPool", "(JZ)V",
+        (void *)JHwBinder_native_startRpcThreadPool },
+
     { "native_report_sysprop_change", "()V",
         (void *)JHwBinder_report_sysprop_change },
 };
diff --git a/core/jni/android_os_HwBlob.cpp b/core/jni/android_os_HwBlob.cpp
index 737ec47..bb916d2 100644
--- a/core/jni/android_os_HwBlob.cpp
+++ b/core/jni/android_os_HwBlob.cpp
@@ -26,6 +26,7 @@
 #include <android_runtime/AndroidRuntime.h>
 #include <hidl/Status.h>
 #include <nativehelper/ScopedLocalRef.h>
+#include <nativehelper/ScopedPrimitiveArray.h>
 
 #include "core_jni_helpers.h"
 
@@ -349,6 +350,13 @@
                 static_cast<const uint8_t *>(blob->data()) + offset));         \
 }
 
+DEFINE_BLOB_ARRAY_COPIER(Int8,jbyte,Byte)
+DEFINE_BLOB_ARRAY_COPIER(Int16,jshort,Short)
+DEFINE_BLOB_ARRAY_COPIER(Int32,jint,Int)
+DEFINE_BLOB_ARRAY_COPIER(Int64,jlong,Long)
+DEFINE_BLOB_ARRAY_COPIER(Float,jfloat,Float)
+DEFINE_BLOB_ARRAY_COPIER(Double,jdouble,Double)
+
 static void JHwBlob_native_copyToBoolArray(
         JNIEnv *env,
         jobject thiz,
@@ -386,13 +394,6 @@
     dst = nullptr;
 }
 
-DEFINE_BLOB_ARRAY_COPIER(Int8,jbyte,Byte)
-DEFINE_BLOB_ARRAY_COPIER(Int16,jshort,Short)
-DEFINE_BLOB_ARRAY_COPIER(Int32,jint,Int)
-DEFINE_BLOB_ARRAY_COPIER(Int64,jlong,Long)
-DEFINE_BLOB_ARRAY_COPIER(Float,jfloat,Float)
-DEFINE_BLOB_ARRAY_COPIER(Double,jdouble,Double)
-
 #define DEFINE_BLOB_PUTTER(Suffix,Type)                                        \
 static void JHwBlob_native_put ## Suffix(                                      \
         JNIEnv *env, jobject thiz, jlong offset, Type x) {                     \
@@ -458,23 +459,17 @@
 #define DEFINE_BLOB_ARRAY_PUTTER(Suffix,Type,NewType)                          \
 static void JHwBlob_native_put ## Suffix ## Array(                             \
         JNIEnv *env, jobject thiz, jlong offset, Type ## Array array) {        \
+    Scoped ## NewType ## ArrayRO autoArray(env, array);                        \
                                                                                \
     if (array == nullptr) {                                                    \
-        jniThrowException(env, "java/lang/NullPointerException", nullptr);     \
+        /* NullpointerException already pending */                             \
         return;                                                                \
     }                                                                          \
                                                                                \
     sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz);                   \
                                                                                \
-    jsize len = env->GetArrayLength(array);                                    \
-                                                                               \
-    Type *src =                                                                \
-        env->Get ## NewType ## ArrayElements(array, nullptr /* isCopy */);     \
-                                                                               \
-    status_t err = blob->write(offset, src, len * sizeof(Type));               \
-                                                                               \
-    env->Release ## NewType ## ArrayElements(array, src, 0 /* mode */);        \
-    src = nullptr;                                                             \
+    status_t err = blob->write(                                                \
+            offset, autoArray.get(), autoArray.size() * sizeof(Type));         \
                                                                                \
     if (err != OK) {                                                           \
         signalExceptionForError(env, err);                                     \
@@ -490,35 +485,28 @@
 
 static void JHwBlob_native_putBoolArray(
         JNIEnv *env, jobject thiz, jlong offset, jbooleanArray array) {
+    ScopedBooleanArrayRO autoArray(env, array);
 
     if (array == nullptr) {
-        jniThrowException(env, "java/lang/NullPointerException", nullptr);
+        /* NullpointerException already pending */
         return;
     }
 
     sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz);
 
-    jsize len = env->GetArrayLength(array);
-
-    if ((offset + len * sizeof(bool)) > blob->size()) {
+    if ((offset + autoArray.size() * sizeof(bool)) > blob->size()) {
         signalExceptionForError(env, -ERANGE);
         return;
     }
 
-    const jboolean *src =
-        env->GetBooleanArrayElements(array, nullptr /* isCopy */);
+    const jboolean *src = autoArray.get();
 
     bool *dst = reinterpret_cast<bool *>(
             static_cast<uint8_t *>(blob->data()) + offset);
 
-    for (jsize i = 0; i < len; ++i) {
+    for (size_t i = 0; i < autoArray.size(); ++i) {
         dst[i] = src[i];
     }
-
-    env->ReleaseBooleanArrayElements(
-            array, const_cast<jboolean *>(src), 0 /* mode */);
-
-    src = nullptr;
 }
 
 static void JHwBlob_native_putBlob(
diff --git a/core/jni/android_os_HwRemoteBinder.cpp b/core/jni/android_os_HwRemoteBinder.cpp
index cf59a56a..ca5e1e4 100644
--- a/core/jni/android_os_HwRemoteBinder.cpp
+++ b/core/jni/android_os_HwRemoteBinder.cpp
@@ -22,9 +22,13 @@
 
 #include "android_os_HwParcel.h"
 
-#include <nativehelper/JNIHelp.h>
+#include <android/hidl/base/1.0/IBase.h>
+#include <android/hidl/base/1.0/BpHwBase.h>
+#include <android/hidl/base/1.0/BnHwBase.h>
 #include <android_runtime/AndroidRuntime.h>
 #include <hidl/Status.h>
+#include <hidl/HidlTransportSupport.h>
+#include <nativehelper/JNIHelp.h>
 #include <nativehelper/ScopedUtfChars.h>
 #include <nativehelper/ScopedLocalRef.h>
 
@@ -413,6 +417,44 @@
     return res;
 }
 
+static sp<hidl::base::V1_0::IBase> toIBase(JNIEnv* env, jclass hwRemoteBinderClazz, jobject jbinder)
+{
+    if (jbinder == nullptr) {
+        return nullptr;
+    }
+    if (!env->IsInstanceOf(jbinder, hwRemoteBinderClazz)) {
+        return nullptr;
+    }
+    sp<JHwRemoteBinder> context = JHwRemoteBinder::GetNativeContext(env, jbinder);
+    sp<hardware::IBinder> cbinder = context->getBinder();
+    return hardware::fromBinder<hidl::base::V1_0::IBase, hidl::base::V1_0::BpHwBase,
+                                hidl::base::V1_0::BnHwBase>(cbinder);
+}
+
+// equals iff other is also a non-null android.os.HwRemoteBinder object
+// and getBinder() returns the same object.
+// In particular, if other is an android.os.HwBinder object (for stubs) then
+// it returns false.
+static jboolean JHwRemoteBinder_equals(JNIEnv* env, jobject thiz, jobject other)
+{
+    if (env->IsSameObject(thiz, other)) {
+        return true;
+    }
+    if (other == NULL) {
+        return false;
+    }
+
+    ScopedLocalRef<jclass> clazz(env, FindClassOrDie(env, CLASS_PATH));
+
+    return hardware::interfacesEqual(toIBase(env, clazz.get(), thiz), toIBase(env, clazz.get(), other));
+}
+
+static jint JHwRemoteBinder_hashCode(JNIEnv* env, jobject thiz) {
+    jlong longHash = reinterpret_cast<jlong>(
+            JHwRemoteBinder::GetNativeContext(env, thiz)->getBinder().get());
+    return static_cast<jint>(longHash ^ (longHash >> 32)); // See Long.hashCode()
+}
+
 static JNINativeMethod gMethods[] = {
     { "native_init", "()J", (void *)JHwRemoteBinder_native_init },
 
@@ -430,6 +472,11 @@
     {"unlinkToDeath",
         "(Landroid/os/IHwBinder$DeathRecipient;)Z",
         (void*)JHwRemoteBinder_unlinkToDeath},
+
+    {"equals", "(Ljava/lang/Object;)Z",
+        (void*)JHwRemoteBinder_equals},
+
+    {"hashCode", "()I", (void*)JHwRemoteBinder_hashCode},
 };
 
 namespace android {
diff --git a/core/jni/android_os_VintfObject.cpp b/core/jni/android_os_VintfObject.cpp
index 5ef2a9e..6243fad 100644
--- a/core/jni/android_os_VintfObject.cpp
+++ b/core/jni/android_os_VintfObject.cpp
@@ -102,8 +102,11 @@
         cPackageInfo[i] = cString;
         env->ReleaseStringUTFChars(element, cString);
     }
+    // If we can run this code, the device should already pass AVB.
+    // So, we don't need to check AVB here.
     std::string error;
-    int32_t status = VintfObject::CheckCompatibility(cPackageInfo, &error);
+    int32_t status = VintfObject::CheckCompatibility(
+        cPackageInfo, &error, ::android::vintf::DISABLE_AVB_CHECK);
     if (status)
         LOG(WARNING) << "VintfObject.verify() returns " << status << ": " << error;
     return status;
diff --git a/core/jni/android_server_Watchdog.cpp b/core/jni/android_server_Watchdog.cpp
deleted file mode 100644
index 01d565b..0000000
--- a/core/jni/android_server_Watchdog.cpp
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- ** Copyright 2010, 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 "Watchdog_N"
-#include <utils/Log.h>
-
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <dirent.h>
-#include <string.h>
-#include <errno.h>
-
-#include "jni.h"
-#include <nativehelper/JNIHelp.h>
-#include "core_jni_helpers.h"
-
-static void dumpOneStack(int tid, int outFd) {
-    char buf[64];
-
-    snprintf(buf, sizeof(buf), "/proc/%d/stack", tid);
-    int stackFd = open(buf, O_RDONLY);
-    if (stackFd >= 0) {
-        // header for readability
-        strncat(buf, ":\n", sizeof(buf) - strlen(buf) - 1);
-        write(outFd, buf, strlen(buf));
-
-        // copy the stack dump text
-        int nBytes;
-        while ((nBytes = read(stackFd, buf, sizeof(buf))) > 0) {
-            write(outFd, buf, nBytes);
-        }
-
-        // footer and done
-        write(outFd, "\n", 1);
-        close(stackFd);
-    } else {
-        ALOGE("Unable to open stack of tid %d : %d (%s)", tid, errno, strerror(errno));
-    }
-}
-
-static void dumpKernelStacks(JNIEnv* env, jobject clazz, jstring pathStr) {
-    char buf[128];
-    DIR* taskdir;
-
-    ALOGI("dumpKernelStacks");
-    if (!pathStr) {
-        jniThrowException(env, "java/lang/IllegalArgumentException", "Null path");
-        return;
-    }
-
-    const char *path = env->GetStringUTFChars(pathStr, NULL);
-
-    int outFd = open(path, O_WRONLY | O_APPEND | O_CREAT,
-        S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
-    if (outFd < 0) {
-        ALOGE("Unable to open stack dump file: %d (%s)", errno, strerror(errno));
-        goto done;
-    }
-
-    snprintf(buf, sizeof(buf), "\n----- begin pid %d kernel stacks -----\n", getpid());
-    write(outFd, buf, strlen(buf));
-
-    // look up the list of all threads in this process
-    snprintf(buf, sizeof(buf), "/proc/%d/task", getpid());
-    taskdir = opendir(buf);
-    if (taskdir != NULL) {
-        struct dirent * ent;
-        while ((ent = readdir(taskdir)) != NULL) {
-            int tid = atoi(ent->d_name);
-            if (tid > 0 && tid <= 65535) {
-                // dump each stack trace
-                dumpOneStack(tid, outFd);
-            }
-        }
-        closedir(taskdir);
-    }
-
-    snprintf(buf, sizeof(buf), "----- end pid %d kernel stacks -----\n", getpid());
-    write(outFd, buf, strlen(buf));
-
-    close(outFd);
-done:
-    env->ReleaseStringUTFChars(pathStr, path);
-}
-
-// ----------------------------------------
-
-namespace android {
-
-static const JNINativeMethod g_methods[] = {
-    { "native_dumpKernelStacks", "(Ljava/lang/String;)V", (void*)dumpKernelStacks },
-};
-
-int register_android_server_Watchdog(JNIEnv* env) {
-    return RegisterMethodsOrDie(env, "com/android/server/Watchdog", g_methods, NELEM(g_methods));
-}
-
-}
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index 50e811d..e998b09 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -27,6 +27,7 @@
 import "frameworks/base/core/proto/android/os/procrank.proto";
 import "frameworks/base/core/proto/android/server/activitymanagerservice.proto";
 import "frameworks/base/core/proto/android/server/alarmmanagerservice.proto";
+import "frameworks/base/core/proto/android/server/windowmanagerservice.proto";
 import "frameworks/base/core/proto/android/server/fingerprint.proto";
 import "frameworks/base/core/proto/android/server/powermanagerservice.proto";
 import "frameworks/base/core/proto/android/service/appwidget.proto";
@@ -135,4 +136,9 @@
         (section).type = SECTION_DUMPSYS,
         (section).args = "alarm --proto"
     ];
+
+    optional com.android.server.wm.proto.WindowManagerServiceProto window = 3017 [
+        (section).type = SECTION_DUMPSYS,
+        (section).args = "window --proto"
+    ];
 }
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index 064523a..4d48a42 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -15,6 +15,7 @@
  */
 
 syntax = "proto2";
+
 import "frameworks/base/core/proto/android/content/configuration.proto";
 import "frameworks/base/core/proto/android/graphics/rect.proto";
 import "frameworks/base/core/proto/android/view/displayinfo.proto";
diff --git a/core/res/res/drawable/dialog_background_material.xml b/core/res/res/drawable/dialog_background_material.xml
index 2f8d1fa..e017d3c 100644
--- a/core/res/res/drawable/dialog_background_material.xml
+++ b/core/res/res/drawable/dialog_background_material.xml
@@ -17,7 +17,7 @@
 <inset xmlns:android="http://schemas.android.com/apk/res/android"
     android:inset="16dp">
     <shape android:shape="rectangle">
-        <corners android:radius="2dp" />
+        <corners android:radius="?attr/dialogCornerRadius" />
         <solid android:color="?attr/colorBackground" />
     </shape>
 </inset>
diff --git a/core/res/res/layout/notification_template_header.xml b/core/res/res/layout/notification_template_header.xml
index f0c980c..3a28f4d 100644
--- a/core/res/res/layout/notification_template_header.xml
+++ b/core/res/res/layout/notification_template_header.xml
@@ -37,6 +37,7 @@
         android:textAppearance="?attr/notificationHeaderTextAppearance"
         android:layout_marginStart="@dimen/notification_header_app_name_margin_start"
         android:layout_marginEnd="@dimen/notification_header_separating_margin"
+        android:visibility="?attr/notificationHeaderAppNameVisibility"
         android:singleLine="true"
         />
     <TextView
diff --git a/core/res/res/layout/notification_template_material_ambient.xml b/core/res/res/layout/notification_template_material_ambient.xml
index ee5c758..865685f 100644
--- a/core/res/res/layout/notification_template_material_ambient.xml
+++ b/core/res/res/layout/notification_template_material_ambient.xml
@@ -23,8 +23,8 @@
     android:paddingStart="@dimen/notification_extra_margin_ambient"
     android:paddingEnd="@dimen/notification_extra_margin_ambient"
     >
-    <include layout="@layout/notification_template_header"
-        android:theme="@style/Theme.Material.Notification.Ambient" />
+    <include layout="@layout/notification_template_ambient_header"
+             android:theme="@style/Theme.Material.Notification.Ambient" />
 
     <LinearLayout
             android:id="@+id/notification_action_list_margin_target"
@@ -53,6 +53,7 @@
                 android:textAppearance="@style/TextAppearance.Material.Notification.Title"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
+                android:gravity="top|center_horizontal"
                 android:singleLine="true"
                 android:ellipsize="marquee"
                 android:fadingEdge="horizontal"
@@ -65,7 +66,7 @@
                 android:textAppearance="@style/TextAppearance.Material.Notification"
                 android:singleLine="false"
                 android:layout_weight="1"
-                android:gravity="top"
+                android:gravity="top|center_horizontal"
                 android:visibility="gone"
                 android:textSize="16sp"
                 android:textColor="#eeffffff"
@@ -75,5 +76,19 @@
             />
         </LinearLayout>
     </LinearLayout>
-    <include layout="@layout/notification_material_action_list" />
+    <FrameLayout android:id="@+id/actions_container"
+                 android:layout_width="match_parent"
+                 android:layout_height="wrap_content"
+                 android:layout_gravity="bottom">
+        <com.android.internal.widget.NotificationActionListLayout
+            android:id="@+id/actions"
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/notification_action_list_height"
+            android:paddingEnd="4dp"
+            android:orientation="horizontal"
+            android:gravity="center"
+            android:visibility="gone"
+            android:background="@color/notification_action_list"
+        />
+    </FrameLayout>
 </FrameLayout>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index db4dcd2..0eefec9 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -984,6 +984,8 @@
         <attr name="dialogTitleDecorLayout" format="reference" />
         <!-- Preferred padding for dialog content. -->
         <attr name="dialogPreferredPadding" format="dimension" />
+        <!-- Corner radius of dialogs. -->
+        <attr name="dialogCornerRadius" format="dimension" />
 
         <!-- Theme to use for alert dialogs spawned from this theme. -->
         <attr name="alertDialogTheme" format="reference" />
@@ -8713,6 +8715,14 @@
         <attr name="notificationHeaderStyle" format="reference" />
         <attr name="notificationHeaderTextAppearance" format="reference" />
         <attr name="notificationHeaderIconSize" format="dimension" />
+        <attr name="notificationHeaderAppNameVisibility" format="enum">
+            <!-- Visible on screen; the default value. -->
+            <enum name="visible" value="0" />
+            <!-- Not displayed, but taken into account during layout (space is left for it). -->
+            <enum name="invisible" value="1" />
+            <!-- Completely hidden, as if the view had not been added. -->
+            <enum name="gone" value="2" />
+        </attr>
     </declare-styleable>
 
     <attr name="lockPatternStyle" format="reference" />
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 4a8bc13..dc68341 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1698,6 +1698,11 @@
          a transaction, so it interacts poorly with SECURE_DELETE. -->
     <string name="db_default_journal_mode" translatable="false">TRUNCATE</string>
 
+    <!-- Enables compatibility WAL mode.
+         In this mode, only database journal mode will be changed, connection pool
+         size will still be limited to a single connection. -->
+    <bool name="db_compatibility_wal_supported">true</bool>
+
     <!-- Maximum size of the persistent journal file in bytes.
          If the journal file grows to be larger than this amount then SQLite will
          truncate it after committing the transaction. -->
@@ -3147,4 +3152,7 @@
 
     <!-- Component name of media projection permission dialog -->
     <string name="config_mediaProjectionPermissionDialogComponent" translateable="false">com.android.systemui/com.android.systemui.media.MediaProjectionPermissionActivity</string>
+
+    <!-- Corner radius of system dialogs -->
+    <dimen name="config_dialogCornerRadius">2dp</dimen>
 </resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index dc75ba6..947fcf1 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -624,4 +624,7 @@
     <dimen name="slice_icon_size">24dp</dimen>
     <!-- Standard padding used in a slice view -->
     <dimen name="slice_padding">16dp</dimen>
+
+    <!-- Default dialog corner radius -->
+    <dimen name="dialog_corner_radius">2dp</dimen>
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 083bf90..fdd56c4 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2847,6 +2847,7 @@
       <public name="cantSaveState" />
       <public name="ttcIndex" />
       <public name="fontVariationSettings" />
+      <public name="dialogCornerRadius" />
     </public-group>
 
     <public-group type="style" first-id="0x010302e0">
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index 470ac52..cddf99a 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -1296,6 +1296,11 @@
         <item name="layout_marginBottom">@dimen/notification_header_margin_bottom</item>
         <item name="paddingStart">@dimen/notification_content_margin_start</item>
         <item name="paddingEnd">16dp</item>
+        <item name="gravity">top</item>
+    </style>
+
+    <style name="Notification.Header.Ambient">
+        <item name="gravity">top|center_horizontal</item>
     </style>
 
 </resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index e513816..32758e8 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -667,6 +667,7 @@
   <java-symbol type="string" name="date_time" />
   <java-symbol type="string" name="date_time_set" />
   <java-symbol type="string" name="date_time_done" />
+  <java-symbol type="bool" name="db_compatibility_wal_supported" />
   <java-symbol type="string" name="db_default_journal_mode" />
   <java-symbol type="string" name="db_default_sync_mode" />
   <java-symbol type="string" name="db_wal_sync_mode" />
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index bf0c906..68d5523 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -88,6 +88,7 @@
 
         <!-- Dialog attributes -->
         <item name="dialogTheme">@style/Theme.DeviceDefault.Dialog</item>
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
 
         <!-- AlertDialog attributes -->
         <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
@@ -214,6 +215,10 @@
         <item name="colorPrimary">@color/primary_device_default_dark</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
         <item name="colorAccent">@color/accent_device_default_dark</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar.  This theme
@@ -223,6 +228,10 @@
         <item name="colorPrimary">@color/primary_device_default_dark</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
         <item name="colorAccent">@color/accent_device_default_dark</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar and
@@ -234,6 +243,10 @@
         <item name="colorPrimary">@color/primary_device_default_dark</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
         <item name="colorAccent">@color/accent_device_default_dark</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault} that has no title bar and translucent
@@ -244,6 +257,10 @@
         <item name="colorPrimary">@color/primary_device_default_dark</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
         <item name="colorAccent">@color/accent_device_default_dark</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
     </style>
 
     <!-- DeviceDefault theme for dialog windows and activities. This changes the window to be
@@ -263,6 +280,10 @@
         <item name="colorPrimary">@color/primary_device_default_dark</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
         <item name="colorAccent">@color/accent_device_default_dark</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Dialog} that has a nice minimum width for a
@@ -272,6 +293,10 @@
         <item name="colorPrimary">@color/primary_device_default_dark</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
         <item name="colorAccent">@color/accent_device_default_dark</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Dialog} without an action bar -->
@@ -280,6 +305,10 @@
         <item name="colorPrimary">@color/primary_device_default_dark</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
         <item name="colorAccent">@color/accent_device_default_dark</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Dialog_NoActionBar} that has a nice minimum width
@@ -289,6 +318,10 @@
         <item name="colorPrimary">@color/primary_device_default_dark</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
         <item name="colorAccent">@color/accent_device_default_dark</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
     </style>
 
     <!-- Variant of Theme.DeviceDefault.Dialog that has a fixed size. -->
@@ -314,6 +347,10 @@
         <item name="colorPrimary">@color/primary_device_default_dark</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
         <item name="colorAccent">@color/accent_device_default_dark</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
     </style>
 
     <!-- DeviceDefault theme for a window without an action bar that will be displayed either
@@ -324,6 +361,10 @@
         <item name="colorPrimary">@color/primary_device_default_dark</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
         <item name="colorAccent">@color/accent_device_default_dark</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
     </style>
 
     <!-- DeviceDefault theme for a presentation window on a secondary display. -->
@@ -332,6 +373,10 @@
         <item name="colorPrimary">@color/primary_device_default_dark</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
         <item name="colorAccent">@color/accent_device_default_dark</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
     </style>
 
     <!-- DeviceDefault theme for panel windows. This removes all extraneous window
@@ -342,6 +387,10 @@
         <item name="colorPrimary">@color/primary_device_default_dark</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
         <item name="colorAccent">@color/accent_device_default_dark</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
     </style>
 
     <!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear
@@ -351,6 +400,10 @@
         <item name="colorPrimary">@color/primary_device_default_dark</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
         <item name="colorAccent">@color/accent_device_default_dark</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
     </style>
 
     <!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear
@@ -360,6 +413,10 @@
         <item name="colorPrimary">@color/primary_device_default_dark</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
         <item name="colorAccent">@color/accent_device_default_dark</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
     </style>
 
     <!-- DeviceDefault style for input methods, which is used by the
@@ -369,6 +426,10 @@
         <item name="colorPrimary">@color/primary_device_default_light</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
     </style>
 
     <!-- DeviceDefault style for input methods, which is used by the
@@ -378,11 +439,19 @@
         <item name="colorPrimary">@color/primary_device_default_light</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
     </style>
 
     <style name="Theme.DeviceDefault.Dialog.Alert" parent="Theme.Material.Dialog.Alert">
         <item name="windowTitleStyle">@style/DialogWindowTitle.DeviceDefault</item>
 
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
+
         <!-- Color palette -->
         <item name="colorPrimary">@color/primary_device_default_dark</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
@@ -394,6 +463,10 @@
         <item name="colorPrimary">@color/primary_device_default_dark</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
         <item name="colorAccent">@color/accent_device_default_dark</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
     </style>
 
     <style name="Theme.DeviceDefault.Dialog.NoFrame" parent="Theme.Material.Dialog.NoFrame">
@@ -401,6 +474,10 @@
         <item name="colorPrimary">@color/primary_device_default_dark</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
         <item name="colorAccent">@color/accent_device_default_dark</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault} with a light-colored style -->
@@ -441,6 +518,7 @@
 
         <!-- Dialog attributes -->
         <item name="dialogTheme">@style/Theme.DeviceDefault.Light.Dialog</item>
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
 
         <!-- AlertDialog attributes -->
         <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
@@ -562,6 +640,10 @@
         <item name="colorPrimary">@color/primary_device_default_dark</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar -->
@@ -570,6 +652,10 @@
         <item name="colorPrimary">@color/primary_device_default_light</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar.
@@ -579,6 +665,10 @@
         <item name="colorPrimary">@color/primary_device_default_light</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar
@@ -590,6 +680,10 @@
         <item name="colorPrimary">@color/primary_device_default_light</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Light} that has no title bar and translucent
@@ -600,6 +694,10 @@
         <item name="colorPrimary">@color/primary_device_default_light</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
     </style>
 
     <!-- DeviceDefault light theme for dialog windows and activities. This changes the window to be
@@ -609,6 +707,10 @@
         <item name="windowTitleStyle">@style/DialogWindowTitle.DeviceDefault.Light</item>
         <item name="windowAnimationStyle">@style/Animation.DeviceDefault.Dialog</item>
 
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
+
         <item name="buttonBarStyle">@style/DeviceDefault.Light.ButtonBar.AlertDialog</item>
         <item name="borderlessButtonStyle">@style/Widget.DeviceDefault.Light.Button.Borderless.Small</item>
 
@@ -628,6 +730,10 @@
         <item name="colorPrimary">@color/primary_device_default_light</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
     </style>
 
      <!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog} without an action bar -->
@@ -636,6 +742,10 @@
         <item name="colorPrimary">@color/primary_device_default_light</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog_NoActionBar} that has a nice minimum
@@ -645,6 +755,10 @@
         <item name="colorPrimary">@color/primary_device_default_light</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
     </style>
 
     <!-- Variant of Theme.DeviceDefault.Dialog that has a fixed size. -->
@@ -680,6 +794,10 @@
         <item name="colorPrimary">@color/primary_device_default_light</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
     </style>
 
     <!-- DeviceDefault light theme for a window without an action bar that will be displayed either
@@ -690,6 +808,10 @@
         <item name="colorPrimary">@color/primary_device_default_light</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
     </style>
 
     <!-- DeviceDefault light theme for a presentation window on a secondary display. -->
@@ -698,6 +820,10 @@
         <item name="colorPrimary">@color/primary_device_default_light</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
     </style>
 
     <!-- DeviceDefault light theme for panel windows. This removes all extraneous window
@@ -708,6 +834,10 @@
         <item name="colorPrimary">@color/primary_device_default_light</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
     </style>
 
     <style name="Theme.DeviceDefault.Light.Dialog.Alert" parent="Theme.Material.Light.Dialog.Alert">
@@ -717,6 +847,10 @@
         <item name="colorPrimary">@color/primary_device_default_light</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
     </style>
 
     <style name="Theme.DeviceDefault.Light.SearchBar" parent="Theme.Material.Light.SearchBar">
@@ -724,6 +858,10 @@
         <item name="colorPrimary">@color/primary_device_default_light</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
     </style>
 
     <style name="Theme.DeviceDefault.Light.Voice" parent="Theme.Material.Light.Voice">
@@ -731,6 +869,10 @@
         <item name="colorPrimary">@color/primary_device_default_light</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
     </style>
 
     <!-- DeviceDefault theme for a window that should look like the Settings app.  -->
@@ -750,6 +892,10 @@
         <item name="navigationBarDividerColor">#1f000000</item>
         <item name="navigationBarColor">@android:color/white</item>
         <item name="windowLightNavigationBar">true</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
     </style>
 
     <!-- @hide DeviceDefault theme for a window that should use Settings theme colors
@@ -761,6 +907,7 @@
         <item name="colorSecondary">@color/secondary_device_default_settings_light</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
         <item name="colorControlNormal">?attr/textColorPrimary</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
     </style>
 
     <style name="Theme.DeviceDefault.QuickSettings.Dialog" parent="Theme.DeviceDefault.Light.Dialog">
@@ -769,6 +916,7 @@
         <item name="colorPrimaryDark">@color/primary_dark_device_default_settings_light</item>
         <item name="colorSecondary">@color/secondary_device_default_settings_light</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Settings_Dark} with no action bar -->
@@ -778,6 +926,10 @@
         <item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item>
         <item name="colorSecondary">@color/secondary_device_default_settings</item>
         <item name="colorAccent">@color/accent_device_default_dark</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
     </style>
 
     <style name="Theme.DeviceDefault.Settings.Dialog" parent="Theme.Material.Settings.Dialog">
@@ -786,6 +938,10 @@
         <item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item>
         <item name="colorSecondary">@color/secondary_device_default_settings</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
     </style>
 
     <style name="Theme.DeviceDefault.Settings.DialogWhenLarge" parent="Theme.Material.Settings.DialogWhenLarge">
@@ -794,6 +950,10 @@
         <item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item>
         <item name="colorSecondary">@color/secondary_device_default_settings</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
     </style>
 
     <style name="Theme.DeviceDefault.Settings.Dialog.Alert" parent="Theme.Material.Settings.Dialog.Alert">
@@ -802,9 +962,13 @@
         <item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item>
         <item name="colorSecondary">@color/secondary_device_default_settings</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
+
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
     </style>
 
-    <style name="Theme.DeviceDefault.Settings.Dialog.NoActionBar" parent="Theme.DeviceDefault.Light.Dialog.NoActionBar"/>
+    <style name="Theme.DeviceDefault.Settings.Dialog.NoActionBar" parent="Theme.DeviceDefault.Light.Dialog.NoActionBar" />
 
     <!-- Theme used for the intent picker activity. -->
     <style name="Theme.DeviceDefault.Resolver" parent="Theme.Material.Light">
@@ -820,6 +984,10 @@
         <item name="listPreferredItemPaddingStart">?attr/dialogPreferredPadding</item>
         <item name="listPreferredItemPaddingEnd">?attr/dialogPreferredPadding</item>
 
+        <!-- Dialog attributes -->
+        <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+        <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
+
         <!-- Color palette -->
         <item name="colorPrimary">@color/primary_device_default_light</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
@@ -831,7 +999,7 @@
 
     <style name="ThemeOverlay.DeviceDefault" />
 
-    <!-- @hide Theme overlay that inherits from material actionbar,  and use accent color for
+    <!-- @hide Theme overlay that inherits from material actionbar, and use accent color for
              primary text -->
     <style name="ThemeOverlay.DeviceDefault.ActionBar.Accent" parent="ThemeOverlay.Material.ActionBar">
         <item name="textColorPrimary">@color/btn_colored_borderless_text_material</item>
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index 9bea3ee..c317121 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -186,6 +186,7 @@
         <item name="dialogCustomTitleDecorLayout">@layout/dialog_custom_title_material</item>
         <item name="dialogTitleDecorLayout">@layout/dialog_title_material</item>
         <item name="dialogPreferredPadding">@dimen/dialog_padding_material</item>
+        <item name="dialogCornerRadius">@dimen/dialog_corner_radius</item>
 
         <!-- AlertDialog attributes -->
         <item name="alertDialogTheme">@style/ThemeOverlay.Material.Dialog.Alert</item>
@@ -554,6 +555,7 @@
         <item name="dialogCustomTitleDecorLayout">@layout/dialog_custom_title_material</item>
         <item name="dialogTitleDecorLayout">@layout/dialog_title_material</item>
         <item name="dialogPreferredPadding">@dimen/dialog_padding_material</item>
+        <item name="dialogCornerRadius">@dimen/dialog_corner_radius</item>
 
         <!-- AlertDialog attributes -->
         <item name="alertDialogTheme">@style/ThemeOverlay.Material.Dialog.Alert</item>
@@ -1325,12 +1327,15 @@
     <style name="Theme.Material.Notification" parent="">
         <item name="notificationHeaderStyle">@style/Notification.Header</item>
         <item name="notificationHeaderTextAppearance">@style/TextAppearance.Material.Notification.Info</item>
+        <item name="notificationHeaderAppNameVisibility">visible</item>
         <item name="notificationHeaderIconSize">@dimen/notification_header_icon_size</item>
     </style>
 
     <!-- Theme for inflating ambient notification -->
     <style name="Theme.Material.Notification.Ambient">
+        <item name="notificationHeaderStyle">@style/Notification.Header.Ambient</item>
         <item name="notificationHeaderTextAppearance">@style/TextAppearance.Material.Notification.Info.Ambient</item>
+        <item name="notificationHeaderAppNameVisibility">gone</item>
         <item name="notificationHeaderIconSize">@dimen/notification_header_icon_size_ambient</item>
     </style>
 
diff --git a/libs/hwui/tests/scripts/prep_taieye.sh b/libs/hwui/tests/scripts/prep_taieye.sh
new file mode 100755
index 0000000..503f6d5
--- /dev/null
+++ b/libs/hwui/tests/scripts/prep_taieye.sh
@@ -0,0 +1,50 @@
+nr=$(adb shell cat /proc/cpuinfo | grep processor | wc -l)
+cpubase=/sys/devices/system/cpu
+
+adb root
+adb wait-for-device
+adb shell stop vendor.perfd
+adb shell stop thermal-engine
+
+S=1036800
+cpu=0
+# Changing governor and frequency in one core will be automatically applied
+# to other cores in the cluster
+while [ $((cpu < 4)) -eq 1 ]; do
+    echo "Setting cpu ${cpu} to $S hz"
+    adb shell "echo userspace > $cpubase/cpu${cpu}/cpufreq/scaling_governor"
+    adb shell "echo 1 > $cpubase/cpu${cpu}/online"
+    adb shell "echo $S > $cpubase/cpu${cpu}/cpufreq/scaling_max_freq"
+    adb shell "echo $S > $cpubase/cpu${cpu}/cpufreq/scaling_min_freq"
+    cpu=$(($cpu + 1))
+done
+
+while [ $((cpu < $nr)) -eq 1 ]; do
+  echo "disable cpu $cpu"
+  adb shell "echo 0 > $cpubase/cpu${cpu}/online"
+  cpu=$(($cpu + 1))
+done
+
+echo "setting GPU bus and idle timer"
+adb shell "echo 0 > /sys/class/kgsl/kgsl-3d0/bus_split"
+adb shell "echo 1 > /sys/class/kgsl/kgsl-3d0/force_clk_on"
+adb shell "echo 10000 > /sys/class/kgsl/kgsl-3d0/idle_timer"
+
+#0 762 1144 1525 2288 3143 4173 5195 5859 7759 9887 11863 13763
+adb shell "echo 7759 > /sys/class/devfreq/soc\:qcom,gpubw/min_freq"
+adb shell "echo 7759 > /sys/class/devfreq/soc\:qcom,gpubw/max_freq"
+adb shell "echo 7759 > /sys/class/devfreq/soc\:qcom,cpubw/min_freq"
+adb shell "echo 7759 > /sys/class/devfreq/soc\:qcom,cpubw/max_freq"
+adb shell "echo 7759 > /sys/class/devfreq/soc\:qcom,mincpubw/min_freq"
+adb shell "echo 7759 > /sys/class/devfreq/soc\:qcom,mincpubw/max_freq"
+adb shell "echo 7759 > /sys/class/devfreq/soc\:qcom,memlat-cpu0/min_freq"
+adb shell "echo 7759 > /sys/class/devfreq/soc\:qcom,memlat-cpu0/max_freq"
+
+# 180000000 257000000 342000000 414000000 515000000 596000000 670000000 710000000
+echo "performance mode, 342 MHz"
+adb shell "echo performance > /sys/class/kgsl/kgsl-3d0/devfreq/governor"
+adb shell "echo 342000000 > /sys/class/kgsl/kgsl-3d0/devfreq/min_freq"
+adb shell "echo 342000000 > /sys/class/kgsl/kgsl-3d0/devfreq/max_freq"
+
+adb shell "echo 4 > /sys/class/kgsl/kgsl-3d0/min_pwrlevel"
+adb shell "echo 4 > /sys/class/kgsl/kgsl-3d0/max_pwrlevel"
diff --git a/libs/protoutil/include/android/util/ProtoOutputStream.h b/libs/protoutil/include/android/util/ProtoOutputStream.h
index 2155084..ce41849 100644
--- a/libs/protoutil/include/android/util/ProtoOutputStream.h
+++ b/libs/protoutil/include/android/util/ProtoOutputStream.h
@@ -35,6 +35,10 @@
  */
 const uint64_t FIELD_TYPE_MASK = 0x0ffULL << FIELD_TYPE_SHIFT;
 
+/**
+ * The types are copied from external/protobuf/src/google/protobuf/descriptor.h directly,
+ * so no extra mapping needs to be maintained in this case.
+ */
 const uint64_t FIELD_TYPE_UNKNOWN  = 0;
 const uint64_t FIELD_TYPE_DOUBLE   = 1ULL << FIELD_TYPE_SHIFT;   // double, exactly eight bytes on the wire.
 const uint64_t FIELD_TYPE_FLOAT    = 2ULL << FIELD_TYPE_SHIFT;   // float, exactly four bytes on the wire.
@@ -49,7 +53,7 @@
 const uint64_t FIELD_TYPE_FIXED32  = 7ULL << FIELD_TYPE_SHIFT;   // uint32, exactly four bytes on the wire.
 const uint64_t FIELD_TYPE_BOOL     = 8ULL << FIELD_TYPE_SHIFT;   // bool, varint on the wire.
 const uint64_t FIELD_TYPE_STRING   = 9ULL << FIELD_TYPE_SHIFT;   // UTF-8 text.
-const uint64_t FIELD_TYPE_GROUP    = 10ULL << FIELD_TYPE_SHIFT;  // Tag-delimited message.  Deprecated.
+// const uint64_t FIELD_TYPE_GROUP = 10ULL << FIELD_TYPE_SHIFT;  // Tag-delimited message.  Deprecated.
 const uint64_t FIELD_TYPE_MESSAGE  = 11ULL << FIELD_TYPE_SHIFT;  // Length-delimited message.
 
 const uint64_t FIELD_TYPE_BYTES    = 12ULL << FIELD_TYPE_SHIFT;  // Arbitrary byte array.
@@ -69,7 +73,7 @@
 const uint64_t FIELD_COUNT_UNKNOWN = 0;
 const uint64_t FIELD_COUNT_SINGLE = 1ULL << FIELD_COUNT_SHIFT;
 const uint64_t FIELD_COUNT_REPEATED = 2ULL << FIELD_COUNT_SHIFT;
-const uint64_t FIELD_COUNT_PACKED = 4ULL << FIELD_COUNT_SHIFT;
+const uint64_t FIELD_COUNT_PACKED = 5ULL << FIELD_COUNT_SHIFT;
 
 /**
  * Class to write to a protobuf stream.
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
index 32e6389..c3a36e9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
@@ -28,6 +28,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
 import android.graphics.drawable.Drawable;
 import android.os.RemoteException;
@@ -343,7 +344,8 @@
         }
         DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
                 Context.DEVICE_POLICY_SERVICE);
-        if (dpm == null) {
+        PackageManager pm = context.getPackageManager();
+        if (!pm.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN) || dpm == null) {
             return null;
         }
         boolean isAccountTypeDisabled = false;
diff --git a/packages/SettingsLib/src/com/android/settingslib/development/AbstractEnableAdbPreferenceController.java b/packages/SettingsLib/src/com/android/settingslib/development/AbstractEnableAdbPreferenceController.java
index 6aae226..3c02f6a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/development/AbstractEnableAdbPreferenceController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/development/AbstractEnableAdbPreferenceController.java
@@ -16,11 +16,13 @@
 
 package com.android.settingslib.development;
 
+import android.app.ActivityManager;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.os.UserManager;
 import android.provider.Settings;
+import android.support.annotation.VisibleForTesting;
 import android.support.v14.preference.SwitchPreference;
 import android.support.v4.content.LocalBroadcastManager;
 import android.support.v7.preference.Preference;
@@ -95,6 +97,10 @@
 
     @Override
     public boolean handlePreferenceTreeClick(Preference preference) {
+        if (isUserAMonkey()) {
+            return false;
+        }
+
         if (TextUtils.equals(KEY_ENABLE_ADB, preference.getKey())) {
             if (!isAdbEnabled()) {
                 showConfirmationDialog(preference);
@@ -117,4 +123,9 @@
         LocalBroadcastManager.getInstance(mContext)
                 .sendBroadcast(new Intent(ACTION_ENABLE_ADB_STATE_CHANGED));
     }
+
+    @VisibleForTesting
+    boolean isUserAMonkey() {
+        return ActivityManager.isUserAMonkey();
+    }
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java
index ca366ea..64de635 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java
@@ -33,6 +33,7 @@
 import android.app.admin.DevicePolicyManager;
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
 import android.os.UserManager;
 
@@ -56,6 +57,8 @@
     private DevicePolicyManager mDevicePolicyManager;
     @Mock
     private UserManager mUserManager;
+    @Mock
+    private PackageManager mPackageManager;
     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
     private RestrictedLockUtils.Proxy mProxy;
 
@@ -72,11 +75,32 @@
                 .thenReturn(mDevicePolicyManager);
         when(mContext.getSystemService(Context.USER_SERVICE))
                 .thenReturn(mUserManager);
+        when(mContext.getPackageManager())
+                .thenReturn(mPackageManager);
 
         RestrictedLockUtils.sProxy = mProxy;
     }
 
     @Test
+    public void checkIfDevicePolicyServiceDisabled_noEnforceAdminForManagedProfile() {
+        when(mContext.getSystemService(Context.DEVICE_POLICY_SERVICE)).thenReturn(null);
+        final EnforcedAdmin enforcedAdmin = RestrictedLockUtils.checkIfAccountManagementDisabled(
+                mContext, "account_type", mUserId);
+
+        assertThat(enforcedAdmin).isEqualTo(null);
+    }
+
+    @Test
+    public void checkIfDeviceAdminFeatureDisabled_noEnforceAdminForManagedProfile() {
+        when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN))
+                .thenReturn(false);
+        final EnforcedAdmin enforcedAdmin = RestrictedLockUtils.checkIfAccountManagementDisabled(
+                mContext, "account_type", mUserId);
+
+        assertThat(enforcedAdmin).isEqualTo(null);
+    }
+
+    @Test
     public void checkIfKeyguardFeaturesDisabled_noEnforcedAdminForManagedProfile() {
         setUpManagedProfile(mUserId, new ComponentName[] {mAdmin1, mAdmin2});
 
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/EnableAdbPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/EnableAdbPreferenceControllerTest.java
index bcabff3..32fa01c 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/EnableAdbPreferenceControllerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/EnableAdbPreferenceControllerTest.java
@@ -21,6 +21,7 @@
 import static org.mockito.Answers.RETURNS_DEEP_STUBS;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
@@ -119,6 +120,18 @@
     }
 
     @Test
+    public void handlePreferenceTreeClick_isMonkeyUser_shouldBeFalse() {
+        mController = spy(mController);
+        doReturn(true).when(mController).isUserAMonkey();
+        when(mUserManager.isAdminUser()).thenReturn(true);
+        mController.displayPreference(mScreen);
+
+        final boolean handled = mController.handlePreferenceTreeClick(mPreference);
+
+        assertThat(handled).isFalse();
+    }
+
+    @Test
     public void updateState_settingsOn_shouldCheck() {
         when(mUserManager.isAdminUser()).thenReturn(true);
         Settings.Secure.putInt(mContext.getContentResolver(),
@@ -161,6 +174,7 @@
         }
 
         @Override
-        public void dismissConfirmationDialog() {}
+        public void dismissConfirmationDialog() {
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 7bcef57..1596d12 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -439,7 +439,7 @@
         if (mMinimizedSnapAlgorithm == null) {
             mMinimizedSnapAlgorithm = new DividerSnapAlgorithm(getContext().getResources(),
                     mDisplayWidth, mDisplayHeight, mDividerSize, isHorizontalDivision(),
-                    mStableInsets, mDockedStackMinimized && mHomeStackResizable);
+                    mStableInsets, mDockSide, mDockedStackMinimized && mHomeStackResizable);
         }
     }
 
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 d8a9c12..fa34d4a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -5266,7 +5266,8 @@
     boolean isCameraAllowedByAdmin() {
         if (mDevicePolicyManager.getCameraDisabled(null, mCurrentUserId)) {
             return false;
-        } else if (isKeyguardShowing() && isKeyguardSecure()) {
+        } else if (mStatusBarKeyguardViewManager == null ||
+                (isKeyguardShowing() && isKeyguardSecure())) {
             // Check if the admin has disabled the camera specifically for the keyguard
             return (mDevicePolicyManager.getKeyguardDisabledFeatures(null, mCurrentUserId)
                     & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) == 0;
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 2e0f394..fad6bd1 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -4754,6 +4754,16 @@
     // OS: P
     DIALOG_OEM_LOCK_INFO = 1238;
 
+    // ACTION: Settings > Wi-Fi > Click one network > Auto sign in
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_WIFI_AUTO_SIGN_IN = 1239;
+
+    // Open: Settings > System > About phone > IMEI
+    // CATEGORY: SETTINGS
+    // OS: P
+    DIALOG_IMEI_INFO = 1240;
+
     // Add new aosp constants above this line.
     // END OF AOSP CONSTANTS
   }
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 8d46d1e..35f83e4 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -60,9 +60,6 @@
     // Set this to true to use debug default values.
     static final boolean DB = false;
 
-    // Set this to true to have the watchdog record kernel thread stacks when it fires
-    static final boolean RECORD_KERNEL_THREADS = true;
-
     // Note 1: Do not lower this value below thirty seconds without tightening the invoke-with
     //         timeout in com.android.internal.os.ZygoteConnection, or wrapped applications
     //         can trigger the watchdog.
@@ -509,11 +506,6 @@
             // The system's been hanging for a minute, another second or two won't hurt much.
             SystemClock.sleep(2000);
 
-            // Pull our own kernel thread stacks as well if we're configured for that
-            if (RECORD_KERNEL_THREADS) {
-                dumpKernelStackTraces();
-            }
-
             // Trigger the kernel to dump all blocked threads, and backtraces on all CPUs to the kernel log
             doSysRq('w');
             doSysRq('l');
@@ -591,18 +583,6 @@
         }
     }
 
-    private File dumpKernelStackTraces() {
-        String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
-        if (tracesPath == null || tracesPath.length() == 0) {
-            return null;
-        }
-
-        native_dumpKernelStacks(tracesPath);
-        return new File(tracesPath);
-    }
-
-    private native void native_dumpKernelStacks(String tracesPath);
-
     public static final class OpenFdMonitor {
         /**
          * Number of FDs below the soft limit that we trigger a runtime restart at. This was
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index e98bb1a..d2d9aab 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -4043,10 +4043,14 @@
         if (DEBUG_SWITCH) Slog.d(TAG_SWITCH,
                 "updateUsageStats: comp=" + component + "res=" + resumed);
         final BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
+        StatsLog.write(StatsLog.ACTIVITY_FOREGROUND_STATE_CHANGED,
+            component.userId, component.realActivity.getPackageName(),
+            component.realActivity.getShortClassName(), resumed ? 1 : 0);
         if (resumed) {
             if (mUsageStatsService != null) {
                 mUsageStatsService.reportEvent(component.realActivity, component.userId,
                         UsageEvents.Event.MOVE_TO_FOREGROUND);
+
             }
             synchronized (stats) {
                 stats.noteActivityResumedLocked(component.app.uid);
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index d6bd2b31..7eb922c 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -2476,7 +2476,10 @@
             pw.println("      -e <NAME> <VALUE>: set argument <NAME> to <VALUE>.  For test runners a");
             pw.println("          common form is [-e <testrunner_flag> <value>[,<value>...]].");
             pw.println("      -p <FILE>: write profiling data to <FILE>");
-            pw.println("      -m: Write output as protobuf (machine readable)");
+            pw.println("      -m: Write output as protobuf to stdout (machine readable)");
+            pw.println("      -f <Optional PATH/TO/FILE>: Write output as protobuf to a file (machine");
+            pw.println("          readable). If path is not specified, default directory and file name will");
+            pw.println("          be used: /sdcard/instrument-logs/log-yyyyMMdd-hhmmss-SSS.instrumentation_data_proto");
             pw.println("      -w: wait for instrumentation to finish before returning.  Required for");
             pw.println("          test runners.");
             pw.println("      --user <USER_ID> | current: Specify user instrumentation runs in;");
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index db12ae2..52f9702 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -23,6 +23,7 @@
 import android.net.wifi.WifiActivityEnergyInfo;
 import android.os.PowerSaveState;
 import android.os.BatteryStats;
+import android.os.BatteryStatsInternal;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
@@ -177,9 +178,22 @@
     }
 
     public void publish() {
+        LocalServices.addService(BatteryStatsInternal.class, new LocalService());
         ServiceManager.addService(BatteryStats.SERVICE_NAME, asBinder());
     }
 
+    private final class LocalService extends BatteryStatsInternal {
+        @Override
+        public String[] getWifiIfaces() {
+            return mStats.getWifiIfaces().clone();
+        }
+
+        @Override
+        public String[] getMobileIfaces() {
+            return mStats.getMobileIfaces().clone();
+        }
+    }
+
     private static void awaitUninterruptibly(Future<?> future) {
         while (true) {
             try {
diff --git a/services/core/java/com/android/server/am/RunningTasks.java b/services/core/java/com/android/server/am/RunningTasks.java
index 400b03a..c860df8 100644
--- a/services/core/java/com/android/server/am/RunningTasks.java
+++ b/services/core/java/com/android/server/am/RunningTasks.java
@@ -47,8 +47,10 @@
     void getTasks(int maxNum, List<RunningTaskInfo> list, @ActivityType int ignoreActivityType,
             @WindowingMode int ignoreWindowingMode, SparseArray<ActivityDisplay> activityDisplays,
             int callingUid, boolean allowed) {
-        // For each stack on each display, add the tasks into the sorted set and then pull the first
-        // {@param maxNum} from the set
+        // Return early if there are no tasks to fetch
+        if (maxNum <= 0) {
+            return;
+        }
 
         // Gather all of the tasks across all of the tasks, and add them to the sorted set
         mTmpSortedSet.clear();
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index 6e1c21e..c4e6ff6 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -163,10 +163,6 @@
     };
 
     private SyncManager getSyncManager() {
-        if (SystemProperties.getBoolean("config.disable_network", false)) {
-            return null;
-        }
-
         synchronized(mSyncManagerLock) {
             try {
                 // Try to create the SyncManager, return null if it fails (e.g. the disk is full).
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 4cf35bc..660659f 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -803,18 +803,6 @@
             }
         };
         mGnssMetrics = new GnssMetrics();
-
-        /*
-        * A cycle of native_init() and native_cleanup() is needed so that callbacks are registered
-        * after bootup even when location is disabled. This will allow Emergency SUPL to work even
-        * when location is disabled before device restart.
-        * */
-        boolean isInitialized = native_init();
-        if(!isInitialized) {
-            Log.d(TAG, "Failed to initialize at bootup");
-        } else {
-            native_cleanup();
-        }
     }
 
     /**
@@ -2272,6 +2260,19 @@
          * this handler.
          */
         private void handleInitialize() {
+            /*
+             * A cycle of native_init() and native_cleanup() is needed so that callbacks are
+             * registered after bootup even when location is disabled.
+             * This will allow Emergency SUPL to work even when location is disabled before device
+             * restart.
+             */
+            boolean isInitialized = native_init();
+            if(!isInitialized) {
+                Log.w(TAG, "Native initialization failed at bootup");
+            } else {
+                native_cleanup();
+            }
+
             // load default GPS configuration
             // (this configuration might change in the future based on SIM changes)
             reloadGpsProperties(mContext, mProperties);
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 86a1c03..50ac409 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -209,7 +209,7 @@
 
             // Get the dexopt flags after getRealCompilerFilter to make sure we get the correct
             // flags.
-            final int dexoptFlags = getDexFlags(pkg, compilerFilter, options.isBootComplete());
+            final int dexoptFlags = getDexFlags(pkg, compilerFilter, options);
 
             for (String dexCodeIsa : dexCodeInstructionSets) {
                 int newResult = dexOptPath(pkg, path, dexCodeIsa, compilerFilter,
@@ -349,8 +349,7 @@
                 dexUseInfo.isUsedByOtherApps());
         // Get the dexopt flags after getRealCompilerFilter to make sure we get the correct flags.
         // Secondary dex files are currently not compiled at boot.
-        int dexoptFlags = getDexFlags(info, compilerFilter, /* bootComplete */ true)
-                | DEXOPT_SECONDARY_DEX;
+        int dexoptFlags = getDexFlags(info, compilerFilter, options) | DEXOPT_SECONDARY_DEX;
         // Check the app storage and add the appropriate flags.
         if (info.deviceProtectedDataDir != null &&
                 FileUtils.contains(info.deviceProtectedDataDir, path)) {
@@ -486,11 +485,11 @@
      * filter.
      */
     private int getDexFlags(PackageParser.Package pkg, String compilerFilter,
-            boolean bootComplete) {
-        return getDexFlags(pkg.applicationInfo, compilerFilter, bootComplete);
+            DexoptOptions options) {
+        return getDexFlags(pkg.applicationInfo, compilerFilter, options);
     }
 
-    private int getDexFlags(ApplicationInfo info, String compilerFilter, boolean bootComplete) {
+    private int getDexFlags(ApplicationInfo info, String compilerFilter, DexoptOptions options) {
         int flags = info.flags;
         boolean debuggable = (flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
         // Profile guide compiled oat files should not be public.
@@ -501,7 +500,8 @@
                 (isPublic ? DEXOPT_PUBLIC : 0)
                 | (debuggable ? DEXOPT_DEBUGGABLE : 0)
                 | profileFlag
-                | (bootComplete ? DEXOPT_BOOTCOMPLETE : 0);
+                | (options.isBootComplete() ? DEXOPT_BOOTCOMPLETE : 0)
+                | (options.isDexoptIdleBackgroundJob() ? DEXOPT_IDLE_BACKGROUND_JOB : 0);
         return adjustDexoptFlags(dexFlags);
     }
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
index cf9e6f3..781216c 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
@@ -59,6 +59,8 @@
         // vendor.
         if ("pm.dexopt.inactive".equals(sysPropName)) {
             sysPropValue = "verify";
+        } else if ("pm.dexopt.shared".equals(sysPropName)) {
+            sysPropValue = "speed";
         } else {
             sysPropValue = SystemProperties.get(sysPropName);
         }
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 1c002aa..25e9239 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -2262,6 +2262,10 @@
 
             final ShortcutUser user = getUserShortcutsLocked(userId);
 
+            if (user.hasHostPackage(packageName)) {
+                return true;
+            }
+
             // Always trust the cached component.
             final ComponentName cached = user.getCachedLauncher();
             if (cached != null) {
@@ -2361,6 +2365,16 @@
         }
     }
 
+    public void setShortcutHostPackage(@NonNull String type, @Nullable String packageName,
+            int userId) {
+        synchronized (mLock) {
+            throwIfUserLockedL(userId);
+
+            final ShortcutUser user = getUserShortcutsLocked(userId);
+            user.setShortcutHostPackage(type, packageName);
+        }
+    }
+
     // === House keeping ===
 
     private void cleanUpPackageForAllLoadedUsers(String packageName, @UserIdInt int packageUserId,
@@ -2697,6 +2711,12 @@
         }
 
         @Override
+        public void setShortcutHostPackage(@NonNull String type, @Nullable String packageName,
+                int userId) {
+            ShortcutService.this.setShortcutHostPackage(type, packageName, userId);
+        }
+
+        @Override
         public boolean requestPinAppWidget(@NonNull String callingPackage,
                 @NonNull AppWidgetProviderInfo appWidget, @Nullable Bundle extras,
                 @Nullable IntentSender resultIntent, int userId) {
diff --git a/services/core/java/com/android/server/pm/ShortcutUser.java b/services/core/java/com/android/server/pm/ShortcutUser.java
index 48eccd0..1efd765 100644
--- a/services/core/java/com/android/server/pm/ShortcutUser.java
+++ b/services/core/java/com/android/server/pm/ShortcutUser.java
@@ -23,6 +23,7 @@
 import android.text.TextUtils;
 import android.text.format.Formatter;
 import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.Log;
 import android.util.Slog;
 
@@ -123,6 +124,20 @@
     /** In-memory-cached default launcher. */
     private ComponentName mCachedLauncher;
 
+    /**
+     * Keep track of additional packages that other parts of the system have said are
+     * allowed to access shortcuts.  The key is the part of the system it came from,
+     * the value is the package name that has access.  We don't persist these because
+     * at boot all relevant system services will push this data back to us they do their
+     * normal evaluation of the state of the world.
+     */
+    private final ArrayMap<String, String> mHostPackages = new ArrayMap<>();
+
+    /**
+     * Set of package name values from above.
+     */
+    private final ArraySet<String> mHostPackageSet = new ArraySet<>();
+
     private String mKnownLocales;
 
     private long mLastAppScanTime;
@@ -467,6 +482,23 @@
         return mCachedLauncher;
     }
 
+    public void setShortcutHostPackage(@NonNull String type, @Nullable String packageName) {
+        if (packageName != null) {
+            mHostPackages.put(type, packageName);
+        } else {
+            mHostPackages.remove(type);
+        }
+
+        mHostPackageSet.clear();
+        for (int i = 0; i < mHostPackages.size(); i++) {
+            mHostPackageSet.add(mHostPackages.valueAt(i));
+        }
+    }
+
+    public boolean hasHostPackage(@NonNull String packageName) {
+        return mHostPackageSet.contains(packageName);
+    }
+
     public void resetThrottling() {
         for (int i = mPackages.size() - 1; i >= 0; i--) {
             mPackages.valueAt(i).resetThrottling();
@@ -555,6 +587,18 @@
             pw.print("Last known launcher: ");
             pw.print(mLastKnownLauncher);
             pw.println();
+
+            if (mHostPackages.size() > 0) {
+                pw.print(prefix);
+                pw.println("Host packages:");
+                for (int i = 0; i < mHostPackages.size(); i++) {
+                    pw.print(prefix);
+                    pw.print("  ");
+                    pw.print(mHostPackages.keyAt(i));
+                    pw.print(": ");
+                    pw.println(mHostPackages.valueAt(i));
+                }
+            }
         }
 
         for (int i = 0; i < mLaunchers.size(); i++) {
diff --git a/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java b/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
index edd2fdb..c6ec287 100644
--- a/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
+++ b/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
@@ -52,6 +52,7 @@
 import android.widget.FrameLayout;
 
 import com.android.internal.R;
+import com.android.server.vr.VrManagerService;
 
 /**
  *  Helper to manage showing/hiding a confirmation prompt when the navigation bar is hidden
@@ -147,7 +148,6 @@
                     && userSetupComplete
                     && !mVrModeEnabled
                     && !navBarEmpty
-                    && !isLockTaskModeLocked()
                     && !UserManager.isDeviceInDemoMode(mContext)) {
                 mHandler.sendEmptyMessageDelayed(H.SHOW, mShowDelayMs);
             }
@@ -156,20 +156,6 @@
         }
     }
 
-    /**
-     * @return {@code true} if and only if the device is currently in LockTask mode managed by
-     * {@link android.app.admin.DevicePolicyManager}. Note that this differs from the screen pinning
-     * mode which is initiated by the user.
-     */
-    private boolean isLockTaskModeLocked() {
-        try {
-            return ActivityManager.getService().getLockTaskModeState()
-                    == ActivityManager.LOCK_TASK_MODE_LOCKED;
-        } catch (RemoteException e) {
-            return false;
-        }
-    }
-
     public boolean onPowerKeyDown(boolean isScreenOn, long time, boolean inImmersiveMode,
             boolean navBarEmpty) {
         if (!isScreenOn && (time - mPanicTime < mPanicThresholdMs)) {
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 2219de8d8..41534cb 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -24,7 +24,8 @@
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
-import android.content.IntentFilter;
+import android.net.NetworkStats;
+import android.os.BatteryStatsInternal;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.IBinder;
@@ -37,15 +38,17 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.util.Slog;
+import android.util.StatsLog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.net.NetworkStatsFactory;
+import com.android.internal.os.KernelWakelockReader;
+import com.android.internal.os.KernelWakelockStats;
+import com.android.server.LocalServices;
+import com.android.server.SystemService;
 
 import java.util.ArrayList;
 import java.util.List;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.os.KernelWakelockReader;
-import com.android.internal.os.KernelWakelockStats;
-import com.android.server.SystemService;
-
 import java.util.Map;
 
 /**
@@ -65,7 +68,7 @@
     private static final Object sStatsdLock = new Object();
 
     private final PendingIntent mAnomalyAlarmIntent;
-    private final PendingIntent mPollingAlarmIntent;
+    private final PendingIntent mPullingAlarmIntent;
     private final BroadcastReceiver mAppUpdateReceiver;
     private final BroadcastReceiver mUserUpdateReceiver;
 
@@ -76,8 +79,8 @@
 
         mAnomalyAlarmIntent = PendingIntent.getBroadcast(mContext, 0,
                 new Intent(mContext, AnomalyAlarmReceiver.class), 0);
-        mPollingAlarmIntent = PendingIntent.getBroadcast(mContext, 0,
-                new Intent(mContext, PollingAlarmReceiver.class), 0);
+        mPullingAlarmIntent = PendingIntent.getBroadcast(
+            mContext, 0, new Intent(mContext, PullingAlarmReceiver.class), 0);
         mAppUpdateReceiver = new AppUpdateReceiver();
         mUserUpdateReceiver = new BroadcastReceiver() {
             @Override
@@ -206,24 +209,25 @@
         }
     }
 
-    public final static class PollingAlarmReceiver extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            if (DEBUG) Slog.d(TAG, "Time to poll something.");
-            synchronized (sStatsdLock) {
-                if (sStatsd == null) {
-                    Slog.w(TAG, "Could not access statsd to inform it of polling alarm firing");
-                    return;
-                }
-                try {
-                    // Two-way call to statsd to retain AlarmManager wakelock
-                    sStatsd.informPollAlarmFired();
-                } catch (RemoteException e) {
-                    Slog.w(TAG, "Failed to inform statsd of polling alarm firing", e);
-                }
-            }
-            // AlarmManager releases its own wakelock here.
+    public final static class PullingAlarmReceiver extends BroadcastReceiver {
+      @Override
+      public void onReceive(Context context, Intent intent) {
+        if (DEBUG)
+          Slog.d(TAG, "Time to poll something.");
+        synchronized (sStatsdLock) {
+          if (sStatsd == null) {
+            Slog.w(TAG, "Could not access statsd to inform it of pulling alarm firing");
+            return;
+          }
+          try {
+            // Two-way call to statsd to retain AlarmManager wakelock
+            sStatsd.informPollAlarmFired();
+          } catch (RemoteException e) {
+            Slog.w(TAG, "Failed to inform statsd of pulling alarm firing", e);
+          }
         }
+        // AlarmManager releases its own wakelock here.
+      }
     }
 
     @Override // Binder call
@@ -254,32 +258,32 @@
     }
 
     @Override // Binder call
-    public void setPollingAlarms(long timestampMs, long intervalMs) {
-        enforceCallingPermission();
-        if (DEBUG) Slog.d(TAG, "Setting polling alarm for " + timestampMs
-                + " every " + intervalMs + "ms");
-        final long callingToken = Binder.clearCallingIdentity();
-        try {
-            // using RTC, not RTC_WAKEUP, so if device is asleep, will only fire when it awakens.
-            // This alarm is inexact, leaving its exactness completely up to the OS optimizations.
-            // TODO: totally inexact means that stats per bucket could be quite off. Is this okay?
-            mAlarmManager.setRepeating(AlarmManager.RTC, timestampMs, intervalMs,
-                    mPollingAlarmIntent);
-        } finally {
-            Binder.restoreCallingIdentity(callingToken);
-        }
+    public void setPullingAlarms(long timestampMs, long intervalMs) {
+      enforceCallingPermission();
+      if (DEBUG)
+        Slog.d(TAG, "Setting pulling alarm for " + timestampMs + " every " + intervalMs + "ms");
+      final long callingToken = Binder.clearCallingIdentity();
+      try {
+        // using RTC, not RTC_WAKEUP, so if device is asleep, will only fire when it awakens.
+        // This alarm is inexact, leaving its exactness completely up to the OS optimizations.
+        // TODO: totally inexact means that stats per bucket could be quite off. Is this okay?
+        mAlarmManager.setRepeating(AlarmManager.RTC, timestampMs, intervalMs, mPullingAlarmIntent);
+      } finally {
+        Binder.restoreCallingIdentity(callingToken);
+      }
     }
 
     @Override // Binder call
-    public void cancelPollingAlarms() {
-        enforceCallingPermission();
-        if (DEBUG) Slog.d(TAG, "Cancelling polling alarm");
-        final long callingToken = Binder.clearCallingIdentity();
-        try {
-            mAlarmManager.cancel(mPollingAlarmIntent);
-        } finally {
-            Binder.restoreCallingIdentity(callingToken);
-        }
+    public void cancelPullingAlarms() {
+      enforceCallingPermission();
+      if (DEBUG)
+        Slog.d(TAG, "Cancelling pulling alarm");
+      final long callingToken = Binder.clearCallingIdentity();
+      try {
+        mAlarmManager.cancel(mPullingAlarmIntent);
+      } finally {
+        Binder.restoreCallingIdentity(callingToken);
+      }
     }
 
     // These values must be kept in sync with cmd/statsd/StatsPullerManager.h.
@@ -289,35 +293,168 @@
     private final KernelWakelockReader mKernelWakelockReader = new KernelWakelockReader();
     private final KernelWakelockStats mTmpWakelockStats = new KernelWakelockStats();
 
+    private StatsLogEventWrapper[] addNetworkStats(int tag, NetworkStats stats, boolean withFGBG) {
+        List<StatsLogEventWrapper> ret = new ArrayList<>();
+        int size = stats.size();
+        NetworkStats.Entry entry = new NetworkStats.Entry(); // For recycling
+        for (int j = 0; j < size; j++) {
+            stats.getValues(j, entry);
+            StatsLogEventWrapper e = new StatsLogEventWrapper(tag, withFGBG ? 6 : 5);
+            e.writeInt(entry.uid);
+            if (withFGBG) {
+                e.writeInt(entry.set);
+            }
+            e.writeLong(entry.rxBytes);
+            e.writeLong(entry.rxPackets);
+            e.writeLong(entry.txBytes);
+            e.writeLong(entry.txPackets);
+            ret.add(e);
+        }
+        return ret.toArray(new StatsLogEventWrapper[ret.size()]);
+    }
+
+    /**
+     * Allows rollups per UID but keeping the set (foreground/background) slicing.
+     * Adapted from groupedByUid in frameworks/base/core/java/android/net/NetworkStats.java
+     */
+    private NetworkStats rollupNetworkStatsByFGBG(NetworkStats stats) {
+        final NetworkStats ret = new NetworkStats(stats.getElapsedRealtime(), 1);
+
+        final NetworkStats.Entry entry = new NetworkStats.Entry();
+        entry.iface = NetworkStats.IFACE_ALL;
+        entry.tag = NetworkStats.TAG_NONE;
+        entry.metered = NetworkStats.METERED_ALL;
+        entry.roaming = NetworkStats.ROAMING_ALL;
+
+        int size = stats.size();
+        NetworkStats.Entry recycle = new NetworkStats.Entry(); // Used for retrieving values
+        for (int i = 0; i < size; i++) {
+            stats.getValues(i, recycle);
+
+            // Skip specific tags, since already counted in TAG_NONE
+            if (recycle.tag != NetworkStats.TAG_NONE) continue;
+
+            entry.set = recycle.set; // Allows slicing by background/foreground
+            entry.uid = recycle.uid;
+            entry.rxBytes = recycle.rxBytes;
+            entry.rxPackets = recycle.rxPackets;
+            entry.txBytes = recycle.txBytes;
+            entry.txPackets = recycle.txPackets;
+            // Operations purposefully omitted since we don't use them for statsd.
+            ret.combineValues(entry);
+        }
+        return ret;
+    }
+
     @Override // Binder call
     public StatsLogEventWrapper[] pullData(int pullCode) {
         enforceCallingPermission();
-        if (DEBUG) {
+        if (DEBUG)
             Slog.d(TAG, "Pulling " + pullCode);
-        }
 
-        List<StatsLogEventWrapper> ret = new ArrayList<>();
         switch (pullCode) {
-            case PULL_CODE_KERNEL_WAKELOCKS: {
+            case StatsLog.WIFI_BYTES_TRANSFERRED: {
+                long token = Binder.clearCallingIdentity();
+                try {
+                    // TODO: Consider caching the following call to get BatteryStatsInternal.
+                    BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class);
+                    String[] ifaces = bs.getWifiIfaces();
+                    if (ifaces.length == 0) {
+                        return null;
+                    }
+                    NetworkStatsFactory nsf = new NetworkStatsFactory();
+                    // Combine all the metrics per Uid into one record.
+                    NetworkStats stats = nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces,
+                            NetworkStats.TAG_NONE, null).groupedByUid();
+                    return addNetworkStats(pullCode, stats, false);
+                } catch (java.io.IOException e) {
+                    Slog.e(TAG, "Pulling netstats for wifi bytes has error", e);
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+                break;
+            }
+            case StatsLog.MOBILE_BYTES_TRANSFERRED: {
+                long token = Binder.clearCallingIdentity();
+                try {
+                    BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class);
+                    String[] ifaces = bs.getMobileIfaces();
+                    if (ifaces.length == 0) {
+                        return null;
+                    }
+                    NetworkStatsFactory nsf = new NetworkStatsFactory();
+                    // Combine all the metrics per Uid into one record.
+                    NetworkStats stats = nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces,
+                        NetworkStats.TAG_NONE, null).groupedByUid();
+                    return addNetworkStats(pullCode, stats, false);
+                } catch (java.io.IOException e) {
+                    Slog.e(TAG, "Pulling netstats for mobile bytes has error", e);
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+                break;
+            }
+            case StatsLog.WIFI_BYTES_TRANSFERRED_BY_FG_BG: {
+                long token = Binder.clearCallingIdentity();
+                try {
+                    BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class);
+                    String[] ifaces = bs.getWifiIfaces();
+                    if (ifaces.length == 0) {
+                        return null;
+                    }
+                    NetworkStatsFactory nsf = new NetworkStatsFactory();
+                    NetworkStats stats = rollupNetworkStatsByFGBG(
+                            nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces,
+                            NetworkStats.TAG_NONE, null));
+                    return addNetworkStats(pullCode, stats, true);
+                } catch (java.io.IOException e) {
+                    Slog.e(TAG, "Pulling netstats for wifi bytes w/ fg/bg has error", e);
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+                break;
+            }
+            case StatsLog.MOBILE_BYTES_TRANSFERRED_BY_FG_BG: {
+                long token = Binder.clearCallingIdentity();
+                try {
+                    BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class);
+                    String[] ifaces = bs.getMobileIfaces();
+                    if (ifaces.length == 0) {
+                        return null;
+                    }
+                    NetworkStatsFactory nsf = new NetworkStatsFactory();
+                    NetworkStats stats = rollupNetworkStatsByFGBG(
+                            nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces,
+                            NetworkStats.TAG_NONE, null));
+                    return addNetworkStats(pullCode, stats, true);
+                } catch (java.io.IOException e) {
+                    Slog.e(TAG, "Pulling netstats for mobile bytes w/ fg/bg has error", e);
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+                break;
+            }
+            case StatsLog.KERNEL_WAKELOCKS_REPORTED: {
                 final KernelWakelockStats wakelockStats =
                         mKernelWakelockReader.readKernelWakelockStats(mTmpWakelockStats);
+                List<StatsLogEventWrapper> ret = new ArrayList();
                 for (Map.Entry<String, KernelWakelockStats.Entry> ent : wakelockStats.entrySet()) {
                     String name = ent.getKey();
                     KernelWakelockStats.Entry kws = ent.getValue();
-                    StatsLogEventWrapper e = new StatsLogEventWrapper(101, 4);
+                    StatsLogEventWrapper e = new StatsLogEventWrapper(pullCode, 4);
+                    e.writeString(name);
                     e.writeInt(kws.mCount);
                     e.writeInt(kws.mVersion);
                     e.writeLong(kws.mTotalTime);
-                    e.writeString(name);
                     ret.add(e);
                 }
-                break;
+                return ret.toArray(new StatsLogEventWrapper[ret.size()]);
             }
             default:
                 Slog.w(TAG, "No such pollable data as " + pullCode);
                 return null;
         }
-        return ret.toArray(new StatsLogEventWrapper[ret.size()]);
+        return null;
     }
 
     @Override // Binder call
@@ -441,7 +578,7 @@
             mContext.unregisterReceiver(mAppUpdateReceiver);
             mContext.unregisterReceiver(mUserUpdateReceiver);
             cancelAnomalyAlarm();
-            cancelPollingAlarms();
+            cancelPullingAlarms();
         }
     }
 
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index e7e4efc..e8ebbe4 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -166,6 +166,8 @@
     private boolean mUserUnlocked;
     private Vr2dDisplay mVr2dDisplay;
     private boolean mBootsToVr;
+    private boolean mStandby;
+    private boolean mUseStandbyToExitVrMode;
 
     // Handles events from the managed services (e.g. VrListenerService and any bound VR compositor
     // service).
@@ -203,7 +205,10 @@
      *
      */
     private void updateVrModeAllowedLocked() {
-        boolean allowed = mSystemSleepFlags == FLAG_ALL && mUserUnlocked;
+        boolean ignoreSleepFlags = mBootsToVr && mUseStandbyToExitVrMode;
+        boolean disallowedByStandby = mStandby && mUseStandbyToExitVrMode;
+        boolean allowed = (mSystemSleepFlags == FLAG_ALL || ignoreSleepFlags) && mUserUnlocked
+                && !disallowedByStandby;
         if (mVrModeAllowed != allowed) {
             mVrModeAllowed = allowed;
             if (DBG) Slog.d(TAG, "VR mode is " + ((allowed) ? "allowed" : "disallowed"));
@@ -273,6 +278,17 @@
         }
     }
 
+    private void setStandbyEnabled(boolean standby) {
+        synchronized(mLock) {
+            if (!mBootsToVr) {
+                Slog.e(TAG, "Attempting to set standby mode on a non-standalone device");
+                return;
+            }
+            mStandby = standby;
+            updateVrModeAllowedLocked();
+        }
+    }
+
     private final Handler mHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
@@ -587,6 +603,12 @@
         }
 
         @Override
+        public void setStandbyEnabled(boolean standby) {
+            enforceCallerPermissionAnyOf(Manifest.permission.ACCESS_VR_MANAGER);
+            VrManagerService.this.setStandbyEnabled(standby);
+        }
+
+        @Override
         protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
             if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
 
@@ -733,6 +755,8 @@
         }
 
         mBootsToVr = SystemProperties.getBoolean("ro.boot.vr", false);
+        mUseStandbyToExitVrMode = mBootsToVr
+                && SystemProperties.getBoolean("persist.vr.use_standby_to_exit_vr_mode", false);
         publishLocalService(VrManagerInternal.class, new LocalService());
         publishBinderService(Context.VR_SERVICE, mVrManager.asBinder());
     }
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index fd71d2f..98db80e 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -1100,52 +1100,54 @@
                     + " from " + fromToken + " to " + this);
 
             final long origId = Binder.clearCallingIdentity();
+            try {
+                // Transfer the starting window over to the new token.
+                startingData = fromToken.startingData;
+                startingSurface = fromToken.startingSurface;
+                startingDisplayed = fromToken.startingDisplayed;
+                fromToken.startingDisplayed = false;
+                startingWindow = tStartingWindow;
+                reportedVisible = fromToken.reportedVisible;
+                fromToken.startingData = null;
+                fromToken.startingSurface = null;
+                fromToken.startingWindow = null;
+                fromToken.startingMoved = true;
+                tStartingWindow.mToken = this;
+                tStartingWindow.mAppToken = this;
 
-            // Transfer the starting window over to the new token.
-            startingData = fromToken.startingData;
-            startingSurface = fromToken.startingSurface;
-            startingDisplayed = fromToken.startingDisplayed;
-            fromToken.startingDisplayed = false;
-            startingWindow = tStartingWindow;
-            reportedVisible = fromToken.reportedVisible;
-            fromToken.startingData = null;
-            fromToken.startingSurface = null;
-            fromToken.startingWindow = null;
-            fromToken.startingMoved = true;
-            tStartingWindow.mToken = this;
-            tStartingWindow.mAppToken = this;
+                if (DEBUG_ADD_REMOVE || DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
+                        "Removing starting " + tStartingWindow + " from " + fromToken);
+                fromToken.removeChild(tStartingWindow);
+                fromToken.postWindowRemoveStartingWindowCleanup(tStartingWindow);
+                fromToken.mHiddenSetFromTransferredStartingWindow = false;
+                addWindow(tStartingWindow);
 
-            if (DEBUG_ADD_REMOVE || DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
-                    "Removing starting " + tStartingWindow + " from " + fromToken);
-            fromToken.removeChild(tStartingWindow);
-            fromToken.postWindowRemoveStartingWindowCleanup(tStartingWindow);
-            fromToken.mHiddenSetFromTransferredStartingWindow = false;
-            addWindow(tStartingWindow);
+                // Propagate other interesting state between the tokens. If the old token is displayed,
+                // we should immediately force the new one to be displayed. If it is animating, we need
+                // to move that animation to the new one.
+                if (fromToken.allDrawn) {
+                    allDrawn = true;
+                    deferClearAllDrawn = fromToken.deferClearAllDrawn;
+                }
+                if (fromToken.firstWindowDrawn) {
+                    firstWindowDrawn = true;
+                }
+                if (!fromToken.hidden) {
+                    hidden = false;
+                    hiddenRequested = false;
+                    mHiddenSetFromTransferredStartingWindow = true;
+                }
+                setClientHidden(fromToken.mClientHidden);
+                fromToken.mAppAnimator.transferCurrentAnimation(
+                        mAppAnimator, tStartingWindow.mWinAnimator);
 
-            // Propagate other interesting state between the tokens. If the old token is displayed,
-            // we should immediately force the new one to be displayed. If it is animating, we need
-            // to move that animation to the new one.
-            if (fromToken.allDrawn) {
-                allDrawn = true;
-                deferClearAllDrawn = fromToken.deferClearAllDrawn;
+                mService.updateFocusedWindowLocked(
+                        UPDATE_FOCUS_WILL_PLACE_SURFACES, true /*updateInputWindows*/);
+                getDisplayContent().setLayoutNeeded();
+                mService.mWindowPlacerLocked.performSurfacePlacement();
+            } finally {
+                Binder.restoreCallingIdentity(origId);
             }
-            if (fromToken.firstWindowDrawn) {
-                firstWindowDrawn = true;
-            }
-            if (!fromToken.hidden) {
-                hidden = false;
-                hiddenRequested = false;
-                mHiddenSetFromTransferredStartingWindow = true;
-            }
-            setClientHidden(fromToken.mClientHidden);
-            fromToken.mAppAnimator.transferCurrentAnimation(
-                    mAppAnimator, tStartingWindow.mWinAnimator);
-
-            mService.updateFocusedWindowLocked(
-                    UPDATE_FOCUS_WILL_PLACE_SURFACES, true /*updateInputWindows*/);
-            getDisplayContent().setLayoutNeeded();
-            mService.mWindowPlacerLocked.performSurfacePlacement();
-            Binder.restoreCallingIdentity(origId);
             return true;
         } else if (fromToken.startingData != null) {
             // The previous app was getting ready to show a
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 0ac2cff..6e89e3e 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -523,7 +523,7 @@
         final DividerSnapAlgorithm algorithm = new DividerSnapAlgorithm(
                 mService.mContext.getResources(), displayWidth, displayHeight,
                 dividerSize, orientation == Configuration.ORIENTATION_PORTRAIT, outBounds,
-                isMinimizedDockAndHomeStackResizable());
+                getDockSide(), isMinimizedDockAndHomeStackResizable());
         final SnapTarget target = algorithm.calculateNonDismissingSnapTarget(dividerPosition);
 
         // Recalculate the bounds based on the position of the target.
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 6bed30c..6b1932d 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1849,110 +1849,109 @@
 
         final long origId = Binder.clearCallingIdentity();
 
-        disposeInputChannel();
+        try {
+            disposeInputChannel();
 
-        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "Remove " + this
-                + ": mSurfaceController=" + mWinAnimator.mSurfaceController
-                + " mAnimatingExit=" + mAnimatingExit
-                + " mRemoveOnExit=" + mRemoveOnExit
-                + " mHasSurface=" + mHasSurface
-                + " surfaceShowing=" + mWinAnimator.getShown()
-                + " isAnimationSet=" + mWinAnimator.isAnimationSet()
-                + " app-animation="
-                + (mAppToken != null ? mAppToken.mAppAnimator.animation : null)
-                + " mWillReplaceWindow=" + mWillReplaceWindow
-                + " inPendingTransaction="
-                + (mAppToken != null ? mAppToken.inPendingTransaction : false)
-                + " mDisplayFrozen=" + mService.mDisplayFrozen
-                + " callers=" + Debug.getCallers(6));
+            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "Remove " + this
+                    + ": mSurfaceController=" + mWinAnimator.mSurfaceController
+                    + " mAnimatingExit=" + mAnimatingExit
+                    + " mRemoveOnExit=" + mRemoveOnExit
+                    + " mHasSurface=" + mHasSurface
+                    + " surfaceShowing=" + mWinAnimator.getShown()
+                    + " isAnimationSet=" + mWinAnimator.isAnimationSet()
+                    + " app-animation="
+                    + (mAppToken != null ? mAppToken.mAppAnimator.animation : null)
+                    + " mWillReplaceWindow=" + mWillReplaceWindow
+                    + " inPendingTransaction="
+                    + (mAppToken != null ? mAppToken.inPendingTransaction : false)
+                    + " mDisplayFrozen=" + mService.mDisplayFrozen
+                    + " callers=" + Debug.getCallers(6));
 
-        // Visibility of the removed window. Will be used later to update orientation later on.
-        boolean wasVisible = false;
+            // Visibility of the removed window. Will be used later to update orientation later on.
+            boolean wasVisible = false;
 
-        final int displayId = getDisplayId();
+            final int displayId = getDisplayId();
 
-        // First, see if we need to run an animation. If we do, we have to hold off on removing the
-        // window until the animation is done. If the display is frozen, just remove immediately,
-        // since the animation wouldn't be seen.
-        if (mHasSurface && mToken.okToAnimate()) {
-            if (mWillReplaceWindow) {
-                // This window is going to be replaced. We need to keep it around until the new one
-                // gets added, then we will get rid of this one.
-                if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
-                        "Preserving " + this + " until the new one is " + "added");
-                // TODO: We are overloading mAnimatingExit flag to prevent the window state from
-                // been removed. We probably need another flag to indicate that window removal
-                // should be deffered vs. overloading the flag that says we are playing an exit
-                // animation.
-                mAnimatingExit = true;
-                mReplacingRemoveRequested = true;
-                Binder.restoreCallingIdentity(origId);
-                return;
-            }
-
-            // If we are not currently running the exit animation, we need to see about starting one
-            wasVisible = isWinVisibleLw();
-
-            if (keepVisibleDeadWindow) {
-                if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
-                        "Not removing " + this + " because app died while it's visible");
-
-                mAppDied = true;
-                setDisplayLayoutNeeded();
-                mService.mWindowPlacerLocked.performSurfacePlacement();
-
-                // Set up a replacement input channel since the app is now dead.
-                // We need to catch tapping on the dead window to restart the app.
-                openInputChannel(null);
-                mService.mInputMonitor.updateInputWindowsLw(true /*force*/);
-
-                Binder.restoreCallingIdentity(origId);
-                return;
-            }
-
-            if (wasVisible) {
-                final int transit = (!startingWindow) ? TRANSIT_EXIT : TRANSIT_PREVIEW_DONE;
-
-                // Try starting an animation.
-                if (mWinAnimator.applyAnimationLocked(transit, false)) {
+            // First, see if we need to run an animation. If we do, we have to hold off on removing the
+            // window until the animation is done. If the display is frozen, just remove immediately,
+            // since the animation wouldn't be seen.
+            if (mHasSurface && mToken.okToAnimate()) {
+                if (mWillReplaceWindow) {
+                    // This window is going to be replaced. We need to keep it around until the new one
+                    // gets added, then we will get rid of this one.
+                    if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
+                            "Preserving " + this + " until the new one is " + "added");
+                    // TODO: We are overloading mAnimatingExit flag to prevent the window state from
+                    // been removed. We probably need another flag to indicate that window removal
+                    // should be deffered vs. overloading the flag that says we are playing an exit
+                    // animation.
                     mAnimatingExit = true;
+                    mReplacingRemoveRequested = true;
+                    return;
                 }
-                //TODO (multidisplay): Magnification is supported only for the default display.
-                if (mService.mAccessibilityController != null && displayId == DEFAULT_DISPLAY) {
-                    mService.mAccessibilityController.onWindowTransitionLocked(this, transit);
-                }
-            }
-            final boolean isAnimating =
-                    mWinAnimator.isAnimationSet() && !mWinAnimator.isDummyAnimation();
-            final boolean lastWindowIsStartingWindow = startingWindow && mAppToken != null
-                    && mAppToken.isLastWindow(this);
-            // We delay the removal of a window if it has a showing surface that can be used to run
-            // exit animation and it is marked as exiting.
-            // Also, If isn't the an animating starting window that is the last window in the app.
-            // We allow the removal of the non-animating starting window now as there is no
-            // additional window or animation that will trigger its removal.
-            if (mWinAnimator.getShown() && mAnimatingExit
-                    && (!lastWindowIsStartingWindow || isAnimating)) {
-                // The exit animation is running or should run... wait for it!
-                if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
-                        "Not removing " + this + " due to exit animation ");
-                setupWindowForRemoveOnExit();
-                if (mAppToken != null) {
-                    mAppToken.updateReportedVisibilityLocked();
-                }
-                Binder.restoreCallingIdentity(origId);
-                return;
-            }
-        }
 
-        removeImmediately();
-        // Removing a visible window will effect the computed orientation
-        // So just update orientation if needed.
-        if (wasVisible && mService.updateOrientationFromAppTokensLocked(false, displayId)) {
-            mService.mH.obtainMessage(SEND_NEW_CONFIGURATION, displayId).sendToTarget();
+                // If we are not currently running the exit animation, we need to see about starting one
+                wasVisible = isWinVisibleLw();
+
+                if (keepVisibleDeadWindow) {
+                    if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
+                            "Not removing " + this + " because app died while it's visible");
+
+                    mAppDied = true;
+                    setDisplayLayoutNeeded();
+                    mService.mWindowPlacerLocked.performSurfacePlacement();
+
+                    // Set up a replacement input channel since the app is now dead.
+                    // We need to catch tapping on the dead window to restart the app.
+                    openInputChannel(null);
+                    mService.mInputMonitor.updateInputWindowsLw(true /*force*/);
+                    return;
+                }
+
+                if (wasVisible) {
+                    final int transit = (!startingWindow) ? TRANSIT_EXIT : TRANSIT_PREVIEW_DONE;
+
+                    // Try starting an animation.
+                    if (mWinAnimator.applyAnimationLocked(transit, false)) {
+                        mAnimatingExit = true;
+                    }
+                    //TODO (multidisplay): Magnification is supported only for the default display.
+                    if (mService.mAccessibilityController != null && displayId == DEFAULT_DISPLAY) {
+                        mService.mAccessibilityController.onWindowTransitionLocked(this, transit);
+                    }
+                }
+                final boolean isAnimating =
+                        mWinAnimator.isAnimationSet() && !mWinAnimator.isDummyAnimation();
+                final boolean lastWindowIsStartingWindow = startingWindow && mAppToken != null
+                        && mAppToken.isLastWindow(this);
+                // We delay the removal of a window if it has a showing surface that can be used to run
+                // exit animation and it is marked as exiting.
+                // Also, If isn't the an animating starting window that is the last window in the app.
+                // We allow the removal of the non-animating starting window now as there is no
+                // additional window or animation that will trigger its removal.
+                if (mWinAnimator.getShown() && mAnimatingExit
+                        && (!lastWindowIsStartingWindow || isAnimating)) {
+                    // The exit animation is running or should run... wait for it!
+                    if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
+                            "Not removing " + this + " due to exit animation ");
+                    setupWindowForRemoveOnExit();
+                    if (mAppToken != null) {
+                        mAppToken.updateReportedVisibilityLocked();
+                    }
+                    return;
+                }
+            }
+
+            removeImmediately();
+            // Removing a visible window will effect the computed orientation
+            // So just update orientation if needed.
+            if (wasVisible && mService.updateOrientationFromAppTokensLocked(false, displayId)) {
+                mService.mH.obtainMessage(SEND_NEW_CONFIGURATION, displayId).sendToTarget();
+            }
+            mService.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/);
+        } finally {
+            Binder.restoreCallingIdentity(origId);
         }
-        mService.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/);
-        Binder.restoreCallingIdentity(origId);
     }
 
     private void setupWindowForRemoveOnExit() {
diff --git a/services/core/jni/com_android_server_SystemServer.cpp b/services/core/jni/com_android_server_SystemServer.cpp
index 3901ceb..d4ffa70 100644
--- a/services/core/jni/com_android_server_SystemServer.cpp
+++ b/services/core/jni/com_android_server_SystemServer.cpp
@@ -48,8 +48,6 @@
 
     status_t err;
 
-    configureRpcThreadpool(5, false /* callerWillJoin */);
-
     JavaVM *vm;
     LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&vm) != JNI_OK, "Cannot get Java VM");
 
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index e8ef168..2f45181 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -92,7 +92,6 @@
     register_android_server_tv_TvUinputBridge(env);
     register_android_server_tv_TvInputHal(env);
     register_android_server_PersistentDataBlockService(env);
-    register_android_server_Watchdog(env);
     register_android_server_HardwarePropertiesManagerService(env);
     register_android_server_storage_AppFuse(env);
     register_android_server_SyntheticPasswordManager(env);
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index de5d879..a2c2aeb 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -545,11 +545,9 @@
         traceEnd();
 
         // Bring up recovery system in case a rescue party needs a reboot
-        if (!SystemProperties.getBoolean("config.disable_noncore", false)) {
-            traceBeginAndSlog("StartRecoverySystemService");
-            mSystemServiceManager.startService(RecoverySystemService.class);
-            traceEnd();
-        }
+        traceBeginAndSlog("StartRecoverySystemService");
+        mSystemServiceManager.startService(RecoverySystemService.class);
+        traceEnd();
 
         // Now that we have the bare essentials of the OS up and running, take
         // note that we just booted, which might send out a rescue party if
@@ -660,6 +658,9 @@
         mSystemServiceManager.startService(DropBoxManagerService.class);
         traceEnd();
 
+        // First hwbinder call is in BatteryService.
+        android.os.HwBinder.startRpcThreadPool(5, false /* callerWillJoin */);
+
         traceBeginAndSlog("StartBatteryService");
         // Tracks the battery level.  Requires LightService.
         mSystemServiceManager.startService(BatteryService.class);
@@ -705,13 +706,7 @@
         MmsServiceBroker mmsService = null;
         HardwarePropertiesManagerService hardwarePropertiesService = null;
 
-        boolean disableStorage = SystemProperties.getBoolean("config.disable_storage", false);
-        boolean disableBluetooth = SystemProperties.getBoolean("config.disable_bluetooth", false);
-        boolean disableLocation = SystemProperties.getBoolean("config.disable_location", false);
         boolean disableSystemUI = SystemProperties.getBoolean("config.disable_systemui", false);
-        boolean disableNonCoreServices = SystemProperties.getBoolean("config.disable_noncore", false);
-        boolean disableNetwork = SystemProperties.getBoolean("config.disable_network", false);
-        boolean disableNetworkTime = SystemProperties.getBoolean("config.disable_networktime", false);
         boolean disableRtt = SystemProperties.getBoolean("config.disable_rtt", false);
         boolean disableMediaProjection = SystemProperties.getBoolean("config.disable_mediaproj",
                 false);
@@ -875,8 +870,6 @@
             } else if (!context.getPackageManager().hasSystemFeature
                        (PackageManager.FEATURE_BLUETOOTH)) {
                 Slog.i(TAG, "No Bluetooth Service (Bluetooth Hardware Not Present)");
-            } else if (disableBluetooth) {
-                Slog.i(TAG, "Bluetooth Service disabled by config");
             } else {
                 traceBeginAndSlog("StartBluetoothService");
                 mSystemServiceManager.startService(BluetoothService.class);
@@ -927,8 +920,7 @@
         traceEnd();
 
         if (mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
-            if (!disableStorage &&
-                    !"0".equals(SystemProperties.get("system_init.startmountservice"))) {
+            if (!"0".equals(SystemProperties.get("system_init.startmountservice"))) {
                 traceBeginAndSlog("StartStorageManagerService");
                 try {
                     /*
@@ -978,42 +970,40 @@
         traceEnd();
 
         if (mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
-            if (!disableNonCoreServices) {
-                traceBeginAndSlog("StartLockSettingsService");
-                try {
-                    mSystemServiceManager.startService(LOCK_SETTINGS_SERVICE_CLASS);
-                    lockSettings = ILockSettings.Stub.asInterface(
-                            ServiceManager.getService("lock_settings"));
-                } catch (Throwable e) {
-                    reportWtf("starting LockSettingsService service", e);
-                }
-                traceEnd();
+            traceBeginAndSlog("StartLockSettingsService");
+            try {
+                mSystemServiceManager.startService(LOCK_SETTINGS_SERVICE_CLASS);
+                lockSettings = ILockSettings.Stub.asInterface(
+                    ServiceManager.getService("lock_settings"));
+            } catch (Throwable e) {
+                reportWtf("starting LockSettingsService service", e);
+            }
+            traceEnd();
 
-                final boolean hasPdb = !SystemProperties.get(PERSISTENT_DATA_BLOCK_PROP).equals("");
-                if (hasPdb) {
-                    traceBeginAndSlog("StartPersistentDataBlock");
-                    mSystemServiceManager.startService(PersistentDataBlockService.class);
-                    traceEnd();
-                }
-
-                if (hasPdb || OemLockService.isHalPresent()) {
-                    // Implementation depends on pdb or the OemLock HAL
-                    traceBeginAndSlog("StartOemLockService");
-                    mSystemServiceManager.startService(OemLockService.class);
-                    traceEnd();
-                }
-
-                traceBeginAndSlog("StartDeviceIdleController");
-                mSystemServiceManager.startService(DeviceIdleController.class);
-                traceEnd();
-
-                // Always start the Device Policy Manager, so that the API is compatible with
-                // API8.
-                traceBeginAndSlog("StartDevicePolicyManager");
-                mSystemServiceManager.startService(DevicePolicyManagerService.Lifecycle.class);
+            final boolean hasPdb = !SystemProperties.get(PERSISTENT_DATA_BLOCK_PROP).equals("");
+            if (hasPdb) {
+                traceBeginAndSlog("StartPersistentDataBlock");
+                mSystemServiceManager.startService(PersistentDataBlockService.class);
                 traceEnd();
             }
 
+            if (hasPdb || OemLockService.isHalPresent()) {
+                // Implementation depends on pdb or the OemLock HAL
+                traceBeginAndSlog("StartOemLockService");
+                mSystemServiceManager.startService(OemLockService.class);
+                traceEnd();
+            }
+
+            traceBeginAndSlog("StartDeviceIdleController");
+            mSystemServiceManager.startService(DeviceIdleController.class);
+            traceEnd();
+
+            // Always start the Device Policy Manager, so that the API is compatible with
+            // API8.
+            traceBeginAndSlog("StartDevicePolicyManager");
+            mSystemServiceManager.startService(DevicePolicyManagerService.Lifecycle.class);
+            traceEnd();
+
             if (!disableSystemUI) {
                 traceBeginAndSlog("StartStatusBarManagerService");
                 try {
@@ -1025,153 +1015,145 @@
                 traceEnd();
             }
 
-            if (!disableNonCoreServices) {
-                traceBeginAndSlog("StartClipboardService");
-                mSystemServiceManager.startService(ClipboardService.class);
-                traceEnd();
+            traceBeginAndSlog("StartClipboardService");
+            mSystemServiceManager.startService(ClipboardService.class);
+            traceEnd();
+
+            traceBeginAndSlog("StartNetworkManagementService");
+            try {
+                networkManagement = NetworkManagementService.create(context);
+                ServiceManager.addService(Context.NETWORKMANAGEMENT_SERVICE, networkManagement);
+            } catch (Throwable e) {
+                reportWtf("starting NetworkManagement Service", e);
             }
+            traceEnd();
 
-            if (!disableNetwork) {
-                traceBeginAndSlog("StartNetworkManagementService");
-                try {
-                    networkManagement = NetworkManagementService.create(context);
-                    ServiceManager.addService(Context.NETWORKMANAGEMENT_SERVICE, networkManagement);
-                } catch (Throwable e) {
-                    reportWtf("starting NetworkManagement Service", e);
-                }
-                traceEnd();
-
-                traceBeginAndSlog("StartIpSecService");
-                try {
-                    ipSecService = IpSecService.create(context);
-                    ServiceManager.addService(Context.IPSEC_SERVICE, ipSecService);
-                } catch (Throwable e) {
-                    reportWtf("starting IpSec Service", e);
-                }
-                traceEnd();
+            traceBeginAndSlog("StartIpSecService");
+            try {
+                ipSecService = IpSecService.create(context);
+                ServiceManager.addService(Context.IPSEC_SERVICE, ipSecService);
+            } catch (Throwable e) {
+                reportWtf("starting IpSec Service", e);
             }
+            traceEnd();
 
-            if (!disableNonCoreServices && !disableTextServices) {
+            if (!disableTextServices) {
                 traceBeginAndSlog("StartTextServicesManager");
                 mSystemServiceManager.startService(TextServicesManagerService.Lifecycle.class);
                 traceEnd();
             }
 
-            if (!disableNetwork) {
-                traceBeginAndSlog("StartNetworkScoreService");
-                try {
-                    networkScore = new NetworkScoreService(context);
-                    ServiceManager.addService(Context.NETWORK_SCORE_SERVICE, networkScore);
-                } catch (Throwable e) {
-                    reportWtf("starting Network Score Service", e);
-                }
-                traceEnd();
+            traceBeginAndSlog("StartNetworkScoreService");
+            try {
+                networkScore = new NetworkScoreService(context);
+                ServiceManager.addService(Context.NETWORK_SCORE_SERVICE, networkScore);
+            } catch (Throwable e) {
+                reportWtf("starting Network Score Service", e);
+            }
+            traceEnd();
 
-                traceBeginAndSlog("StartNetworkStatsService");
-                try {
-                    networkStats = NetworkStatsService.create(context, networkManagement);
-                    ServiceManager.addService(Context.NETWORK_STATS_SERVICE, networkStats);
-                } catch (Throwable e) {
-                    reportWtf("starting NetworkStats Service", e);
-                }
-                traceEnd();
+            traceBeginAndSlog("StartNetworkStatsService");
+            try {
+                networkStats = NetworkStatsService.create(context, networkManagement);
+                ServiceManager.addService(Context.NETWORK_STATS_SERVICE, networkStats);
+            } catch (Throwable e) {
+                reportWtf("starting NetworkStats Service", e);
+            }
+            traceEnd();
 
-                traceBeginAndSlog("StartNetworkPolicyManagerService");
-                try {
-                    networkPolicy = new NetworkPolicyManagerService(context,
-                            mActivityManagerService, networkStats, networkManagement);
-                    ServiceManager.addService(Context.NETWORK_POLICY_SERVICE, networkPolicy);
-                } catch (Throwable e) {
-                    reportWtf("starting NetworkPolicy Service", e);
-                }
-                traceEnd();
+            traceBeginAndSlog("StartNetworkPolicyManagerService");
+            try {
+                networkPolicy = new NetworkPolicyManagerService(context,
+                    mActivityManagerService, networkStats, networkManagement);
+                ServiceManager.addService(Context.NETWORK_POLICY_SERVICE, networkPolicy);
+            } catch (Throwable e) {
+                reportWtf("starting NetworkPolicy Service", e);
+            }
+            traceEnd();
 
-                // Wifi Service must be started first for wifi-related services.
-                traceBeginAndSlog("StartWifi");
-                mSystemServiceManager.startService(WIFI_SERVICE_CLASS);
-                traceEnd();
-                traceBeginAndSlog("StartWifiScanning");
-                mSystemServiceManager.startService(
-                        "com.android.server.wifi.scanner.WifiScanningService");
-                traceEnd();
+            // Wifi Service must be started first for wifi-related services.
+            traceBeginAndSlog("StartWifi");
+            mSystemServiceManager.startService(WIFI_SERVICE_CLASS);
+            traceEnd();
+            traceBeginAndSlog("StartWifiScanning");
+            mSystemServiceManager.startService(
+                "com.android.server.wifi.scanner.WifiScanningService");
+            traceEnd();
 
-                if (!disableRtt) {
-                    traceBeginAndSlog("StartWifiRtt");
-                    mSystemServiceManager.startService("com.android.server.wifi.RttService");
-                    traceEnd();
-
-                    if (context.getPackageManager().hasSystemFeature(
-                            PackageManager.FEATURE_WIFI_RTT)) {
-                        traceBeginAndSlog("StartRttService");
-                        mSystemServiceManager.startService(
-                                "com.android.server.wifi.rtt.RttService");
-                        traceEnd();
-                    }
-                }
+            if (!disableRtt) {
+                traceBeginAndSlog("StartWifiRtt");
+                mSystemServiceManager.startService("com.android.server.wifi.RttService");
+                traceEnd();
 
                 if (context.getPackageManager().hasSystemFeature(
-                        PackageManager.FEATURE_WIFI_AWARE)) {
-                    traceBeginAndSlog("StartWifiAware");
-                    mSystemServiceManager.startService(WIFI_AWARE_SERVICE_CLASS);
+                    PackageManager.FEATURE_WIFI_RTT)) {
+                    traceBeginAndSlog("StartRttService");
+                    mSystemServiceManager.startService(
+                        "com.android.server.wifi.rtt.RttService");
                     traceEnd();
                 }
+            }
 
-                if (context.getPackageManager().hasSystemFeature(
-                        PackageManager.FEATURE_WIFI_DIRECT)) {
-                    traceBeginAndSlog("StartWifiP2P");
-                    mSystemServiceManager.startService(WIFI_P2P_SERVICE_CLASS);
-                    traceEnd();
-                }
+            if (context.getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_WIFI_AWARE)) {
+                traceBeginAndSlog("StartWifiAware");
+                mSystemServiceManager.startService(WIFI_AWARE_SERVICE_CLASS);
+                traceEnd();
+            }
 
-                if (context.getPackageManager().hasSystemFeature(
-                        PackageManager.FEATURE_LOWPAN)) {
-                    traceBeginAndSlog("StartLowpan");
-                    mSystemServiceManager.startService(LOWPAN_SERVICE_CLASS);
-                    traceEnd();
-                }
+            if (context.getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_WIFI_DIRECT)) {
+                traceBeginAndSlog("StartWifiP2P");
+                mSystemServiceManager.startService(WIFI_P2P_SERVICE_CLASS);
+                traceEnd();
+            }
 
-                if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_ETHERNET) ||
-                    mPackageManager.hasSystemFeature(PackageManager.FEATURE_USB_HOST)) {
-                    traceBeginAndSlog("StartEthernet");
-                    mSystemServiceManager.startService(ETHERNET_SERVICE_CLASS);
-                    traceEnd();
-                }
+            if (context.getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_LOWPAN)) {
+                traceBeginAndSlog("StartLowpan");
+                mSystemServiceManager.startService(LOWPAN_SERVICE_CLASS);
+                traceEnd();
+            }
 
-                traceBeginAndSlog("StartConnectivityService");
-                try {
-                    connectivity = new ConnectivityService(
-                            context, networkManagement, networkStats, networkPolicy);
-                    ServiceManager.addService(Context.CONNECTIVITY_SERVICE, connectivity,
+            if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_ETHERNET) ||
+                mPackageManager.hasSystemFeature(PackageManager.FEATURE_USB_HOST)) {
+                traceBeginAndSlog("StartEthernet");
+                mSystemServiceManager.startService(ETHERNET_SERVICE_CLASS);
+                traceEnd();
+            }
+
+            traceBeginAndSlog("StartConnectivityService");
+            try {
+                connectivity = new ConnectivityService(
+                    context, networkManagement, networkStats, networkPolicy);
+                ServiceManager.addService(Context.CONNECTIVITY_SERVICE, connectivity,
                             /* allowIsolated= */ false,
-                            DUMP_FLAG_PRIORITY_HIGH | DUMP_FLAG_PRIORITY_NORMAL);
-                    networkStats.bindConnectivityManager(connectivity);
-                    networkPolicy.bindConnectivityManager(connectivity);
-                } catch (Throwable e) {
-                    reportWtf("starting Connectivity Service", e);
-                }
-                traceEnd();
-
-                traceBeginAndSlog("StartNsdService");
-                try {
-                    serviceDiscovery = NsdService.create(context);
-                    ServiceManager.addService(
-                            Context.NSD_SERVICE, serviceDiscovery);
-                } catch (Throwable e) {
-                    reportWtf("starting Service Discovery Service", e);
-                }
-                traceEnd();
+                    DUMP_FLAG_PRIORITY_HIGH | DUMP_FLAG_PRIORITY_NORMAL);
+                networkStats.bindConnectivityManager(connectivity);
+                networkPolicy.bindConnectivityManager(connectivity);
+            } catch (Throwable e) {
+                reportWtf("starting Connectivity Service", e);
             }
+            traceEnd();
 
-            if (!disableNonCoreServices) {
-                traceBeginAndSlog("StartUpdateLockService");
-                try {
-                    ServiceManager.addService(Context.UPDATE_LOCK_SERVICE,
-                            new UpdateLockService(context));
-                } catch (Throwable e) {
-                    reportWtf("starting UpdateLockService", e);
-                }
-                traceEnd();
+            traceBeginAndSlog("StartNsdService");
+            try {
+                serviceDiscovery = NsdService.create(context);
+                ServiceManager.addService(
+                    Context.NSD_SERVICE, serviceDiscovery);
+            } catch (Throwable e) {
+                reportWtf("starting Service Discovery Service", e);
             }
+            traceEnd();
+
+            traceBeginAndSlog("StartUpdateLockService");
+            try {
+                ServiceManager.addService(Context.UPDATE_LOCK_SERVICE,
+                    new UpdateLockService(context));
+            } catch (Throwable e) {
+                reportWtf("starting UpdateLockService", e);
+            }
+            traceEnd();
 
             traceBeginAndSlog("StartNotificationManager");
             mSystemServiceManager.startService(NotificationManagerService.class);
@@ -1185,27 +1167,25 @@
             mSystemServiceManager.startService(DeviceStorageMonitorService.class);
             traceEnd();
 
-            if (!disableLocation) {
-                traceBeginAndSlog("StartLocationManagerService");
-                try {
-                    location = new LocationManagerService(context);
-                    ServiceManager.addService(Context.LOCATION_SERVICE, location);
-                } catch (Throwable e) {
-                    reportWtf("starting Location Manager", e);
-                }
-                traceEnd();
-
-                traceBeginAndSlog("StartCountryDetectorService");
-                try {
-                    countryDetector = new CountryDetectorService(context);
-                    ServiceManager.addService(Context.COUNTRY_DETECTOR, countryDetector);
-                } catch (Throwable e) {
-                    reportWtf("starting Country Detector", e);
-                }
-                traceEnd();
+            traceBeginAndSlog("StartLocationManagerService");
+            try {
+                location = new LocationManagerService(context);
+                ServiceManager.addService(Context.LOCATION_SERVICE, location);
+            } catch (Throwable e) {
+                reportWtf("starting Location Manager", e);
             }
+            traceEnd();
 
-            if (!disableNonCoreServices && !disableSearchManager) {
+            traceBeginAndSlog("StartCountryDetectorService");
+            try {
+                countryDetector = new CountryDetectorService(context);
+                ServiceManager.addService(Context.COUNTRY_DETECTOR, countryDetector);
+            } catch (Throwable e) {
+                reportWtf("starting Country Detector", e);
+            }
+            traceEnd();
+
+            if (!disableSearchManager) {
                 traceBeginAndSlog("StartSearchManagerService");
                 try {
                     mSystemServiceManager.startService(SEARCH_MANAGER_SERVICE_CLASS);
@@ -1215,8 +1195,7 @@
                 traceEnd();
             }
 
-            if (!disableNonCoreServices && context.getResources().getBoolean(
-                        R.bool.config_enableWallpaperService)) {
+            if (context.getResources().getBoolean(R.bool.config_enableWallpaperService)) {
                 traceBeginAndSlog("StartWallpaperManagerService");
                 mSystemServiceManager.startService(WALLPAPER_SERVICE_CLASS);
                 traceEnd();
@@ -1232,16 +1211,14 @@
                 traceEnd();
             }
 
-            if (!disableNonCoreServices) {
-                traceBeginAndSlog("StartDockObserver");
-                mSystemServiceManager.startService(DockObserver.class);
-                traceEnd();
+            traceBeginAndSlog("StartDockObserver");
+            mSystemServiceManager.startService(DockObserver.class);
+            traceEnd();
 
-                if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
-                    traceBeginAndSlog("StartThermalObserver");
-                    mSystemServiceManager.startService(THERMAL_OBSERVER_CLASS);
-                    traceEnd();
-                }
+            if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+                traceBeginAndSlog("StartThermalObserver");
+                mSystemServiceManager.startService(THERMAL_OBSERVER_CLASS);
+                traceEnd();
             }
 
             traceBeginAndSlog("StartWiredAccessoryManager");
@@ -1254,46 +1231,44 @@
             }
             traceEnd();
 
-            if (!disableNonCoreServices) {
-                if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_MIDI)) {
-                    // Start MIDI Manager service
-                    traceBeginAndSlog("StartMidiManager");
-                    mSystemServiceManager.startService(MIDI_SERVICE_CLASS);
-                    traceEnd();
-                }
+            if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_MIDI)) {
+                // Start MIDI Manager service
+                traceBeginAndSlog("StartMidiManager");
+                mSystemServiceManager.startService(MIDI_SERVICE_CLASS);
+                traceEnd();
+            }
 
-                if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_USB_HOST)
-                        || mPackageManager.hasSystemFeature(
-                                PackageManager.FEATURE_USB_ACCESSORY)) {
-                    // Manage USB host and device support
-                    traceBeginAndSlog("StartUsbService");
-                    mSystemServiceManager.startService(USB_SERVICE_CLASS);
-                    traceEnd();
-                }
+            if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_USB_HOST)
+                || mPackageManager.hasSystemFeature(
+                PackageManager.FEATURE_USB_ACCESSORY)) {
+                // Manage USB host and device support
+                traceBeginAndSlog("StartUsbService");
+                mSystemServiceManager.startService(USB_SERVICE_CLASS);
+                traceEnd();
+            }
 
-                if (!disableSerial) {
-                    traceBeginAndSlog("StartSerialService");
-                    try {
-                        // Serial port support
-                        serial = new SerialService(context);
-                        ServiceManager.addService(Context.SERIAL_SERVICE, serial);
-                    } catch (Throwable e) {
-                        Slog.e(TAG, "Failure starting SerialService", e);
-                    }
-                    traceEnd();
-                }
-
-                traceBeginAndSlog("StartHardwarePropertiesManagerService");
+            if (!disableSerial) {
+                traceBeginAndSlog("StartSerialService");
                 try {
-                    hardwarePropertiesService = new HardwarePropertiesManagerService(context);
-                    ServiceManager.addService(Context.HARDWARE_PROPERTIES_SERVICE,
-                            hardwarePropertiesService);
+                    // Serial port support
+                    serial = new SerialService(context);
+                    ServiceManager.addService(Context.SERIAL_SERVICE, serial);
                 } catch (Throwable e) {
-                    Slog.e(TAG, "Failure starting HardwarePropertiesManagerService", e);
+                    Slog.e(TAG, "Failure starting SerialService", e);
                 }
                 traceEnd();
             }
 
+            traceBeginAndSlog("StartHardwarePropertiesManagerService");
+            try {
+                hardwarePropertiesService = new HardwarePropertiesManagerService(context);
+                ServiceManager.addService(Context.HARDWARE_PROPERTIES_SERVICE,
+                    hardwarePropertiesService);
+            } catch (Throwable e) {
+                Slog.e(TAG, "Failure starting HardwarePropertiesManagerService", e);
+            }
+            traceEnd();
+
             traceBeginAndSlog("StartTwilightService");
             mSystemServiceManager.startService(TwilightService.class);
             traceEnd();
@@ -1312,48 +1287,46 @@
             mSystemServiceManager.startService(SoundTriggerService.class);
             traceEnd();
 
-            if (!disableNonCoreServices) {
-                if (!disableTrustManager) {
-                    traceBeginAndSlog("StartTrustManager");
-                    mSystemServiceManager.startService(TrustManagerService.class);
-                    traceEnd();
-                }
-
-                if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_BACKUP)) {
-                    traceBeginAndSlog("StartBackupManager");
-                    mSystemServiceManager.startService(BACKUP_MANAGER_SERVICE_CLASS);
-                    traceEnd();
-                }
-
-                if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_APP_WIDGETS)
-                    || context.getResources().getBoolean(R.bool.config_enableAppWidgetService)) {
-                    traceBeginAndSlog("StartAppWidgerService");
-                    mSystemServiceManager.startService(APPWIDGET_SERVICE_CLASS);
-                    traceEnd();
-                }
-
-                // We need to always start this service, regardless of whether the
-                // FEATURE_VOICE_RECOGNIZERS feature is set, because it needs to take care
-                // of initializing various settings.  It will internally modify its behavior
-                // based on that feature.
-                traceBeginAndSlog("StartVoiceRecognitionManager");
-                mSystemServiceManager.startService(VOICE_RECOGNITION_MANAGER_SERVICE_CLASS);
-                traceEnd();
-
-                if (GestureLauncherService.isGestureLauncherEnabled(context.getResources())) {
-                    traceBeginAndSlog("StartGestureLauncher");
-                    mSystemServiceManager.startService(GestureLauncherService.class);
-                    traceEnd();
-                }
-                traceBeginAndSlog("StartSensorNotification");
-                mSystemServiceManager.startService(SensorNotificationService.class);
-                traceEnd();
-
-                traceBeginAndSlog("StartContextHubSystemService");
-                mSystemServiceManager.startService(ContextHubSystemService.class);
+            if (!disableTrustManager) {
+                traceBeginAndSlog("StartTrustManager");
+                mSystemServiceManager.startService(TrustManagerService.class);
                 traceEnd();
             }
 
+            if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_BACKUP)) {
+                traceBeginAndSlog("StartBackupManager");
+                mSystemServiceManager.startService(BACKUP_MANAGER_SERVICE_CLASS);
+                traceEnd();
+            }
+
+            if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_APP_WIDGETS)
+                || context.getResources().getBoolean(R.bool.config_enableAppWidgetService)) {
+                traceBeginAndSlog("StartAppWidgerService");
+                mSystemServiceManager.startService(APPWIDGET_SERVICE_CLASS);
+                traceEnd();
+            }
+
+            // We need to always start this service, regardless of whether the
+            // FEATURE_VOICE_RECOGNIZERS feature is set, because it needs to take care
+            // of initializing various settings.  It will internally modify its behavior
+            // based on that feature.
+            traceBeginAndSlog("StartVoiceRecognitionManager");
+            mSystemServiceManager.startService(VOICE_RECOGNITION_MANAGER_SERVICE_CLASS);
+            traceEnd();
+
+            if (GestureLauncherService.isGestureLauncherEnabled(context.getResources())) {
+                traceBeginAndSlog("StartGestureLauncher");
+                mSystemServiceManager.startService(GestureLauncherService.class);
+                traceEnd();
+            }
+            traceBeginAndSlog("StartSensorNotification");
+            mSystemServiceManager.startService(SensorNotificationService.class);
+            traceEnd();
+
+            traceBeginAndSlog("StartContextHubSystemService");
+            mSystemServiceManager.startService(ContextHubSystemService.class);
+            traceEnd();
+
             traceBeginAndSlog("StartDiskStatsService");
             try {
                 ServiceManager.addService("diskstats", new DiskStatsService(context));
@@ -1375,16 +1348,14 @@
                 traceEnd();
             }
 
-            if (!disableNetwork && !disableNetworkTime) {
-                traceBeginAndSlog("StartNetworkTimeUpdateService");
-                try {
-                    networkTimeUpdater = new NetworkTimeUpdateService(context);
-                    ServiceManager.addService("network_time_update_service", networkTimeUpdater);
-                } catch (Throwable e) {
-                    reportWtf("starting NetworkTimeUpdate service", e);
-                }
-                traceEnd();
+            traceBeginAndSlog("StartNetworkTimeUpdateService");
+            try {
+                networkTimeUpdater = new NetworkTimeUpdateService(context);
+                ServiceManager.addService("network_time_update_service", networkTimeUpdater);
+            } catch (Throwable e) {
+                reportWtf("starting NetworkTimeUpdate service", e);
             }
+            traceEnd();
 
             traceBeginAndSlog("StartCommonTimeManagementService");
             try {
@@ -1395,38 +1366,32 @@
             }
             traceEnd();
 
-            if (!disableNetwork) {
-                traceBeginAndSlog("CertBlacklister");
-                try {
-                    CertBlacklister blacklister = new CertBlacklister(context);
-                } catch (Throwable e) {
-                    reportWtf("starting CertBlacklister", e);
-                }
-                traceEnd();
+            traceBeginAndSlog("CertBlacklister");
+            try {
+                CertBlacklister blacklister = new CertBlacklister(context);
+            } catch (Throwable e) {
+                reportWtf("starting CertBlacklister", e);
             }
+            traceEnd();
 
-            if (!disableNetwork && !disableNonCoreServices && EmergencyAffordanceManager.ENABLED) {
+            if (EmergencyAffordanceManager.ENABLED) {
                 // EmergencyMode service
                 traceBeginAndSlog("StartEmergencyAffordanceService");
                 mSystemServiceManager.startService(EmergencyAffordanceService.class);
                 traceEnd();
             }
 
-            if (!disableNonCoreServices) {
-                // Dreams (interactive idle-time views, a/k/a screen savers, and doze mode)
-                traceBeginAndSlog("StartDreamManager");
-                mSystemServiceManager.startService(DreamManagerService.class);
-                traceEnd();
-            }
+            // Dreams (interactive idle-time views, a/k/a screen savers, and doze mode)
+            traceBeginAndSlog("StartDreamManager");
+            mSystemServiceManager.startService(DreamManagerService.class);
+            traceEnd();
 
-            if (!disableNonCoreServices) {
-                traceBeginAndSlog("AddGraphicsStatsService");
-                ServiceManager.addService(GraphicsStatsService.GRAPHICS_STATS_SERVICE,
-                        new GraphicsStatsService(context));
-                traceEnd();
-            }
+            traceBeginAndSlog("AddGraphicsStatsService");
+            ServiceManager.addService(GraphicsStatsService.GRAPHICS_STATS_SERVICE,
+                new GraphicsStatsService(context));
+            traceEnd();
 
-            if (!disableNonCoreServices && CoverageService.ENABLED) {
+            if (CoverageService.ENABLED) {
                 traceBeginAndSlog("AddCoverageService");
                 ServiceManager.addService(CoverageService.COVERAGE_SERVICE, new CoverageService());
                 traceEnd();
@@ -1477,38 +1442,37 @@
                 traceEnd();
             }
 
-            if (!disableNonCoreServices) {
-                traceBeginAndSlog("StartMediaRouterService");
-                try {
-                    mediaRouter = new MediaRouterService(context);
-                    ServiceManager.addService(Context.MEDIA_ROUTER_SERVICE, mediaRouter);
-                } catch (Throwable e) {
-                    reportWtf("starting MediaRouterService", e);
-                }
-                traceEnd();
+            traceBeginAndSlog("StartMediaRouterService");
+            try {
+                mediaRouter = new MediaRouterService(context);
+                ServiceManager.addService(Context.MEDIA_ROUTER_SERVICE, mediaRouter);
+            } catch (Throwable e) {
+                reportWtf("starting MediaRouterService", e);
+            }
+            traceEnd();
 
-                if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
-                    traceBeginAndSlog("StartFingerprintSensor");
-                    mSystemServiceManager.startService(FingerprintService.class);
-                    traceEnd();
-                }
-
-                traceBeginAndSlog("StartBackgroundDexOptService");
-                try {
-                    BackgroundDexOptService.schedule(context);
-                } catch (Throwable e) {
-                    reportWtf("starting StartBackgroundDexOptService", e);
-                }
-                traceEnd();
-
-                traceBeginAndSlog("StartPruneInstantAppsJobService");
-                try {
-                    PruneInstantAppsJobService.schedule(context);
-                } catch (Throwable e) {
-                    reportWtf("StartPruneInstantAppsJobService", e);
-                }
+            if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
+                traceBeginAndSlog("StartFingerprintSensor");
+                mSystemServiceManager.startService(FingerprintService.class);
                 traceEnd();
             }
+
+            traceBeginAndSlog("StartBackgroundDexOptService");
+            try {
+                BackgroundDexOptService.schedule(context);
+            } catch (Throwable e) {
+                reportWtf("starting StartBackgroundDexOptService", e);
+            }
+            traceEnd();
+
+            traceBeginAndSlog("StartPruneInstantAppsJobService");
+            try {
+                PruneInstantAppsJobService.schedule(context);
+            } catch (Throwable e) {
+                reportWtf("StartPruneInstantAppsJobService", e);
+            }
+            traceEnd();
+
             // LauncherAppsService uses ShortcutService.
             traceBeginAndSlog("StartShortcutServiceLifecycle");
             mSystemServiceManager.startService(ShortcutService.Lifecycle.class);
@@ -1519,7 +1483,7 @@
             traceEnd();
         }
 
-        if (!disableNonCoreServices && !disableMediaProjection) {
+        if (!disableMediaProjection) {
             traceBeginAndSlog("StartMediaProjectionManager");
             mSystemServiceManager.startService(MediaProjectionManagerService.class);
             traceEnd();
@@ -1530,17 +1494,15 @@
             mSystemServiceManager.startService(WEAR_CONNECTIVITY_SERVICE_CLASS);
             traceEnd();
 
-            if (!disableNonCoreServices) {
-                traceBeginAndSlog("StartWearTimeService");
-                mSystemServiceManager.startService(WEAR_DISPLAY_SERVICE_CLASS);
-                mSystemServiceManager.startService(WEAR_TIME_SERVICE_CLASS);
-                traceEnd();
+            traceBeginAndSlog("StartWearTimeService");
+            mSystemServiceManager.startService(WEAR_DISPLAY_SERVICE_CLASS);
+            mSystemServiceManager.startService(WEAR_TIME_SERVICE_CLASS);
+            traceEnd();
 
-                if (enableLeftyService) {
-                    traceBeginAndSlog("StartWearLeftyService");
-                    mSystemServiceManager.startService(WEAR_LEFTY_SERVICE_CLASS);
-                    traceEnd();
-                }
+            if (enableLeftyService) {
+                traceBeginAndSlog("StartWearLeftyService");
+                mSystemServiceManager.startService(WEAR_LEFTY_SERVICE_CLASS);
+                traceEnd();
             }
         }
 
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 1569ac3..44e5314 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -30,6 +30,7 @@
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
+import android.content.pm.ShortcutServiceInternal;
 import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.hardware.soundtrigger.IRecognitionStatusCallback;
@@ -44,6 +45,7 @@
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.provider.Settings;
 import android.service.voice.IVoiceInteractionService;
 import android.service.voice.IVoiceInteractionSession;
@@ -53,6 +55,7 @@
 import android.service.voice.VoiceInteractionSession;
 import android.speech.RecognitionService;
 import android.text.TextUtils;
+import android.util.ArraySet;
 import android.util.Log;
 import android.util.Slog;
 
@@ -63,6 +66,7 @@
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.DumpUtils;
+import com.android.internal.util.Preconditions;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
 import com.android.server.UiThread;
@@ -84,7 +88,9 @@
     final ContentResolver mResolver;
     final DatabaseHelper mDbHelper;
     final ActivityManagerInternal mAmInternal;
-    final TreeSet<Integer> mLoadedKeyphraseIds;
+    final UserManager mUserManager;
+    final ArraySet<Integer> mLoadedKeyphraseIds = new ArraySet<>();
+    ShortcutServiceInternal mShortcutServiceInternal;
     SoundTriggerInternal mSoundTriggerInternal;
 
     private final RemoteCallbackList<IVoiceInteractionSessionListener>
@@ -96,8 +102,10 @@
         mResolver = context.getContentResolver();
         mDbHelper = new DatabaseHelper(context);
         mServiceStub = new VoiceInteractionManagerServiceStub();
-        mAmInternal = LocalServices.getService(ActivityManagerInternal.class);
-        mLoadedKeyphraseIds = new TreeSet<Integer>();
+        mAmInternal = Preconditions.checkNotNull(
+                LocalServices.getService(ActivityManagerInternal.class));
+        mUserManager = Preconditions.checkNotNull(
+                context.getSystemService(UserManager.class));
 
         PackageManagerInternal packageManagerInternal = LocalServices.getService(
                 PackageManagerInternal.class);
@@ -124,6 +132,8 @@
     @Override
     public void onBootPhase(int phase) {
         if (PHASE_SYSTEM_SERVICES_READY == phase) {
+            mShortcutServiceInternal = Preconditions.checkNotNull(
+                    LocalServices.getService(ShortcutServiceInternal.class));
             mSoundTriggerInternal = LocalServices.getService(SoundTriggerInternal.class);
         } else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
             mServiceStub.systemRunning(isSafeMode());
@@ -180,6 +190,7 @@
 
         private boolean mSafeMode;
         private int mCurUser;
+        private boolean mCurUserUnlocked;
         private final boolean mEnableService;
 
         VoiceInteractionManagerServiceStub() {
@@ -381,6 +392,7 @@
         public void switchUser(int userHandle) {
             synchronized (this) {
                 mCurUser = userHandle;
+                mCurUserUnlocked = false;
                 switchImplementationIfNeededLocked(false);
             }
         }
@@ -409,13 +421,24 @@
                     }
                 }
 
+                final boolean hasComponent = serviceComponent != null && serviceInfo != null;
+
+                if (mUserManager.isUserUnlockingOrUnlocked(mCurUser)) {
+                    if (hasComponent) {
+                        mShortcutServiceInternal.setShortcutHostPackage(TAG,
+                                serviceComponent.getPackageName(), mCurUser);
+                    } else {
+                        mShortcutServiceInternal.setShortcutHostPackage(TAG, null, mCurUser);
+                    }
+                }
+
                 if (force || mImpl == null || mImpl.mUser != mCurUser
                         || !mImpl.mComponent.equals(serviceComponent)) {
                     unloadAllKeyphraseModels();
                     if (mImpl != null) {
                         mImpl.shutdownLocked();
                     }
-                    if (serviceComponent != null && serviceInfo != null) {
+                    if (hasComponent) {
                         mImpl = new VoiceInteractionManagerServiceImpl(mContext,
                                 UiThread.getHandler(), this, mCurUser, serviceComponent);
                         mImpl.startLocked();
@@ -953,12 +976,14 @@
         }
 
         private synchronized void unloadAllKeyphraseModels() {
-            for (int keyphraseId : mLoadedKeyphraseIds) {
+            for (int i = 0; i < mLoadedKeyphraseIds.size(); i++) {
                 final long caller = Binder.clearCallingIdentity();
                 try {
-                    int status = mSoundTriggerInternal.unloadKeyphraseModel(keyphraseId);
+                    int status = mSoundTriggerInternal.unloadKeyphraseModel(
+                            mLoadedKeyphraseIds.valueAt(i));
                     if (status != SoundTriggerInternal.STATUS_OK) {
-                        Slog.w(TAG, "Failed to unload keyphrase " + keyphraseId + ":" + status);
+                        Slog.w(TAG, "Failed to unload keyphrase " + mLoadedKeyphraseIds.valueAt(i)
+                                + ":" + status);
                     }
                 } finally {
                     Binder.restoreCallingIdentity(caller);
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 67f6849..42c3de5 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -2166,13 +2166,16 @@
      * @hide
      */
     public String getSimOperatorNumeric() {
-        int subId = SubscriptionManager.getDefaultDataSubscriptionId();
+        int subId = mSubId;
         if (!SubscriptionManager.isUsableSubIdValue(subId)) {
-            subId = SubscriptionManager.getDefaultSmsSubscriptionId();
+            subId = SubscriptionManager.getDefaultDataSubscriptionId();
             if (!SubscriptionManager.isUsableSubIdValue(subId)) {
-                subId = SubscriptionManager.getDefaultVoiceSubscriptionId();
+                subId = SubscriptionManager.getDefaultSmsSubscriptionId();
                 if (!SubscriptionManager.isUsableSubIdValue(subId)) {
-                    subId = SubscriptionManager.getDefaultSubscriptionId();
+                    subId = SubscriptionManager.getDefaultVoiceSubscriptionId();
+                    if (!SubscriptionManager.isUsableSubIdValue(subId)) {
+                        subId = SubscriptionManager.getDefaultSubscriptionId();
+                    }
                 }
             }
         }
diff --git a/telephony/java/android/telephony/mbms/FileServiceInfo.java b/telephony/java/android/telephony/mbms/FileServiceInfo.java
index d8d7f48..b30a3af 100644
--- a/telephony/java/android/telephony/mbms/FileServiceInfo.java
+++ b/telephony/java/android/telephony/mbms/FileServiceInfo.java
@@ -17,6 +17,7 @@
 package android.telephony.mbms;
 
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -35,6 +36,7 @@
 
     /** @hide */
     @SystemApi
+    @TestApi
     public FileServiceInfo(Map<Locale, String> newNames, String newClassName,
             List<Locale> newLocales, String newServiceId, Date start, Date end,
             List<FileInfo> newFiles) {
diff --git a/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java b/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java
index 9ccdd56..4fee3df 100644
--- a/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java
+++ b/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.content.Intent;
 import android.os.Binder;
 import android.os.IBinder;
@@ -42,6 +43,7 @@
  * @hide
  */
 @SystemApi
+@TestApi
 public class MbmsDownloadServiceBase extends IMbmsDownloadService.Stub {
     private final Map<IBinder, DownloadStateCallback> mDownloadCallbackBinderMap = new HashMap<>();
     private final Map<IBinder, DeathRecipient> mDownloadCallbackDeathRecipients = new HashMap<>();
diff --git a/telephony/java/com/android/internal/telephony/uicc/IccUtils.java b/telephony/java/com/android/internal/telephony/uicc/IccUtils.java
index 62d570c..99a82ad 100644
--- a/telephony/java/com/android/internal/telephony/uicc/IccUtils.java
+++ b/telephony/java/com/android/internal/telephony/uicc/IccUtils.java
@@ -567,4 +567,12 @@
         } while (valueIndex < endIndex);
         return result;
     }
+
+    public static String getDecimalSubstring(String iccId) {
+        int position;
+        for (position = 0; position < iccId.length(); position ++) {
+            if (!Character.isDigit(iccId.charAt(position))) break;
+        }
+        return iccId.substring( 0, position );
+    }
 }
diff --git a/tools/incident_section_gen/main.cpp b/tools/incident_section_gen/main.cpp
index 135df40..674bee1 100644
--- a/tools/incident_section_gen/main.cpp
+++ b/tools/incident_section_gen/main.cpp
@@ -18,6 +18,7 @@
 #include <frameworks/base/core/proto/android/os/incident.pb.h>
 
 #include <map>
+#include <set>
 #include <string>
 
 using namespace android;
@@ -27,6 +28,60 @@
 using namespace google::protobuf::internal;
 using namespace std;
 
+/**
+ * Implementation details:
+ * This binary auto generates .cpp files for incident and incidentd.
+ *
+ * When argument "incident" is specified, it generates incident_section.cpp file.
+ *
+ * When argument "incidentd" is specified, it generates section_list.cpp file.
+ *
+ * In section_list.cpp file, it generates a SECTION_LIST array and a PRIVACY_POLICY_LIST array.
+ * For SECTION_LIST, it generates Section.h classes only for proto fields with section option enabled.
+ * For PRIVACY_POLICY_LIST, it generates Privacy.h classes only for proto fields with privacy option enabled.
+ *
+ * For Privacy struct, it is possible to have self recursion definitions since protobuf is defining "classes"
+ * So the logic to handle it becomes very complicated when Privacy tag of a message contains a list of Privacies
+ * of its sub-messages. The code also handles multiple depth of self recursion fields.
+ *
+ * For example here is a one level self recursion message WindowManager:
+ * message WindowState {
+ *     string state = 1 [(privacy).dest = LOCAL];
+ *     int32  display_id = 2;
+ *     repeated WindowState child_windows = 3;
+ * }
+ *
+ * message WindowManager {
+ *     WindowState my_window = 1;
+ * }
+ *
+ * When generating Privacy options for WindowManager, this tool will generate cpp syntax source code:
+ *
+ * #include "section_list.h"
+ * ...
+ * Privacy WindowState_state { 1, 9, NULL, LOCAL, NULL }; // first two integers are values for field id and proto type.
+ * Privacy WindowState_child_windows { 3, 11, NULL, DEFAULT, NULL }; // reserved for WindowState_LIST
+ * Privacy* WindowState_MSG_[] = {
+ *     &WindowState_state,
+ *     // display id is default, nothing is generated.
+ *     &WindowState_child_windows,
+ *     NULL  // terminator of the array
+ * };
+ * Privacy WindowState_my_window { 1, 11, WindowState_my_window_LIST, DEFAULT, NULL };
+ *
+ * createList() {
+ *    ...
+ *    WindowState_child_windows.children = WindowState_my_window_LIST; // point to its own definition after the list is defined.
+ *    ...
+ * }
+ *
+ * const Privacy** PRIVACY_POLICY_LIST = createList();
+ * const int PRIVACY_POLICY_COUNT = 1;
+ */
+
+// The assignments will be called when constructs PRIVACY_POLICY_LIST, has to be global variable
+vector<string> gSelfRecursionAssignments;
+
 static inline void emptyline() {
     printf("\n");
 }
@@ -38,7 +93,7 @@
     emptyline();
 }
 
-// ================================================================================
+// ======================== incident_sections =============================
 static bool generateIncidentSectionsCpp(Descriptor const* descriptor)
 {
     generateHead("incident_sections");
@@ -73,7 +128,7 @@
     return true;
 }
 
-// ================================================================================
+// ========================= section_list ===================================
 static void splitAndPrint(const string& args) {
     size_t base = 0;
     size_t found;
@@ -88,12 +143,12 @@
     }
 }
 
-static const std::string replaceAll(const string& field_name, const char oldC, const string& newS) {
-    if (field_name.find_first_of(oldC) == field_name.npos) return field_name.c_str();
+static string replaceAll(const string& fieldName, const char oldC, const string& newS) {
+    if (fieldName.find_first_of(oldC) == fieldName.npos) return fieldName.c_str();
     size_t pos = 0, idx = 0;
-    char* res = new char[field_name.size() * newS.size() + 1]; // assign a larger buffer
-    while (pos != field_name.size()) {
-        char cur = field_name[pos++];
+    char* res = new char[fieldName.size() * newS.size() + 1]; // assign a larger buffer
+    while (pos != fieldName.size()) {
+        char cur = fieldName[pos++];
         if (cur != oldC) {
             res[idx++] = cur;
             continue;
@@ -104,92 +159,162 @@
         }
     }
     res[idx] = '\0';
-    std::string result(res);
+    string result(res);
     delete [] res;
     return result;
 }
 
-static inline bool isDefaultDest(const FieldDescriptor* field) {
-    return field->options().GetExtension(privacy).dest() == PrivacyFlags::default_instance().dest();
+static string getFieldName(const FieldDescriptor* field) {
+    return replaceAll(field->full_name(), '.', "__");
 }
 
+static string getMessageTypeName(const Descriptor* descriptor) {
+    return replaceAll(descriptor->full_name(), '.', "_") + "_MSG_";
+}
+
+static inline SectionFlags getSectionFlags(const FieldDescriptor* field) {
+    return field->options().GetExtension(section);
+}
+
+static inline PrivacyFlags getPrivacyFlags(const FieldDescriptor* field) {
+    return field->options().GetExtension(privacy);
+}
+
+static inline bool isDefaultField(const FieldDescriptor* field) {
+    return getPrivacyFlags(field).dest() == PrivacyFlags::default_instance().dest();
+}
+
+static bool isDefaultMessageImpl(const Descriptor* descriptor, set<string>* parents) {
+    int N = descriptor->field_count();
+    parents->insert(descriptor->full_name());
+    for (int i=0; i<N; ++i) {
+        const FieldDescriptor* field = descriptor->field(i);
+        // look at if the current field is default or not, return false immediately
+        if (!isDefaultField(field)) return false;
+
+        switch (field->type()) {
+            case FieldDescriptor::TYPE_MESSAGE:
+                // if self recursion, don't go deep.
+                if (parents->find(field->message_type()->full_name()) != parents->end()) break;
+                // if is a default message, just continue
+                if (isDefaultMessageImpl(field->message_type(), parents)) break;
+                // sub message is not default, so this message is always not default
+                return false;
+            case FieldDescriptor::TYPE_STRING:
+                if (getPrivacyFlags(field).patterns_size() != 0) return false;
+            default:
+                continue;
+        }
+    }
+    parents->erase(descriptor->full_name());
+    return true;
+}
+
+static bool isDefaultMessage(const Descriptor* descriptor) {
+    set<string> parents;
+    return isDefaultMessageImpl(descriptor, &parents);
+}
+
+// This function is called for looking at privacy tags for a message type and recursively its sub-messages
+// It prints out each fields's privacy tags and a List of Privacy of the message itself (don't print default values)
 // Returns false if the descriptor doesn't have any non default privacy flags set, including its submessages
-static bool generatePrivacyFlags(const Descriptor* descriptor, const char* alias, map<string, bool> &msgNames) {
+static bool generatePrivacyFlags(const Descriptor* descriptor, map<string, bool> &msgNames, set<string>* parents) {
     bool hasDefaultFlags[descriptor->field_count()];
+
+    string messageTypeName = getMessageTypeName(descriptor);
+    // if the message is already defined, skip it.
+    if (msgNames.find(messageTypeName) != msgNames.end()) {
+        bool hasDefault = msgNames[messageTypeName];
+        return !hasDefault; // don't generate if it has default privacy.
+    }
+    // insert the message type name so sub-message will figure out if self-recursion occurs
+    parents->insert(messageTypeName);
+
     // iterate though its field and generate sub flags first
     for (int i=0; i<descriptor->field_count(); i++) {
         hasDefaultFlags[i] = true; // set default to true
+
         const FieldDescriptor* field = descriptor->field(i);
-        const std::string field_name_str = replaceAll(field->full_name(), '.', "__");
-        const char* field_name = field_name_str.c_str();
-        // check if the same name is already defined
-        if (msgNames.find(field_name) != msgNames.end()) {
-            hasDefaultFlags[i] = msgNames[field_name];
+        const string fieldName = getFieldName(field);
+        // check if the same field name is already defined.
+        if (msgNames.find(fieldName) != msgNames.end()) {
+            hasDefaultFlags[i] = msgNames[fieldName];
             continue;
         };
 
-        PrivacyFlags p = field->options().GetExtension(privacy);
+        PrivacyFlags p = getPrivacyFlags(field);
+        string fieldMessageName;
         switch (field->type()) {
             case FieldDescriptor::TYPE_MESSAGE:
-                if (generatePrivacyFlags(field->message_type(), field_name, msgNames)) {
-                    printf("Privacy %s { %d, %d, %s_LIST, %d, NULL };\n", field_name, field->number(),
-                            field->type(), field_name, p.dest());
-                } else if (isDefaultDest(field)) {
+                fieldMessageName = getMessageTypeName(field->message_type());
+                if (parents->find(fieldMessageName) != parents->end()) { // Self-Recursion proto definition
+                    if (isDefaultField(field)) {
+                        hasDefaultFlags[i] = isDefaultMessage(field->message_type());
+                    } else {
+                        hasDefaultFlags[i] = false;
+                    }
+                    if (!hasDefaultFlags[i]) {
+                        printf("Privacy %s = { %d, %d, NULL, %d, NULL }; // self recursion field of %s\n",
+                                fieldName.c_str(), field->number(), field->type(), p.dest(), fieldMessageName.c_str());
+                        // generate the assignment and used to construct createList function later on.
+                        gSelfRecursionAssignments.push_back(fieldName + ".children = " + fieldMessageName);
+                    }
+                    break;
+                } else if (generatePrivacyFlags(field->message_type(), msgNames, parents)) {
+                    printf("Privacy %s = { %d, %d, %s, %d, NULL };\n", fieldName.c_str(), field->number(),
+                            field->type(), fieldMessageName.c_str(), p.dest());
+                } else if (isDefaultField(field)) {
                     // don't create a new privacy if the value is default.
                     break;
-                } else{
-                    printf("Privacy %s { %d, %d, NULL, %d, NULL };\n", field_name, field->number(),
+                } else {
+                    printf("Privacy %s = { %d, %d, NULL, %d, NULL };\n", fieldName.c_str(), field->number(),
                             field->type(), p.dest());
                 }
                 hasDefaultFlags[i] = false;
                 break;
             case FieldDescriptor::TYPE_STRING:
-                if (isDefaultDest(field) && p.patterns_size() == 0) break;
+                if (isDefaultField(field) && p.patterns_size() == 0) break;
 
-                printf("const char* %s_patterns[] = {\n", field_name);
+                printf("const char* %s_patterns[] = {\n", fieldName.c_str());
                 for (int i=0; i<p.patterns_size(); i++) {
                     // the generated string need to escape backslash as well, need to dup it here
                     printf("    \"%s\",\n", replaceAll(p.patterns(i), '\\', "\\\\").c_str());
                 }
                 printf("    NULL };\n");
-                printf("Privacy %s { %d, %d, NULL, %d, %s_patterns };\n", field_name, field->number(),
-                        field->type(), p.dest(), field_name);
+                printf("Privacy %s = { %d, %d, NULL, %d, %s_patterns };\n", fieldName.c_str(), field->number(),
+                        field->type(), p.dest(), fieldName.c_str());
                 hasDefaultFlags[i] = false;
                 break;
             default:
-                if (isDefaultDest(field)) break;
-                printf("Privacy %s { %d, %d, NULL, %d, NULL };\n", field_name, field->number(),
+                if (isDefaultField(field)) break;
+                printf("Privacy %s = { %d, %d, NULL, %d, NULL };\n", fieldName.c_str(), field->number(),
                         field->type(), p.dest());
                 hasDefaultFlags[i] = false;
         }
         // add the field name to message map, true means it has default flags
-        msgNames[field_name] = hasDefaultFlags[i];
+        msgNames[fieldName] = hasDefaultFlags[i];
     }
 
     bool allDefaults = true;
     for (int i=0; i<descriptor->field_count(); i++) {
         allDefaults &= hasDefaultFlags[i];
     }
+
+    parents->erase(messageTypeName); // erase the message type name when exit the message.
+    msgNames[messageTypeName] = allDefaults; // store the privacy tags of the message here to avoid overhead.
+
     if (allDefaults) return false;
 
     emptyline();
-
-    bool needConst = strcmp(alias, "PRIVACY_POLICY") == 0;
     int policyCount = 0;
-
-    printf("%sPrivacy* %s_LIST[] = {\n", needConst ? "const " : "", alias);
+    printf("Privacy* %s[] = {\n", messageTypeName.c_str());
     for (int i=0; i<descriptor->field_count(); i++) {
         const FieldDescriptor* field = descriptor->field(i);
         if (hasDefaultFlags[i]) continue;
-        printf("    &%s,\n", replaceAll(field->full_name(), '.', "__").c_str());
+        printf("    &%s,\n", getFieldName(field).c_str());
         policyCount++;
     }
-    if (needConst) {
-        printf("};\n\n");
-        printf("const int PRIVACY_POLICY_COUNT = %d;\n", policyCount);
-    } else {
-        printf("    NULL };\n");
-    }
+    printf("    NULL };\n");
     emptyline();
     return true;
 }
@@ -198,6 +323,8 @@
     generateHead("section_list");
 
     // generates SECTION_LIST
+    printf("// Generate SECTION_LIST.\n\n");
+
     printf("const Section* SECTION_LIST[] = {\n");
     for (int i=0; i<descriptor->field_count(); i++) {
         const FieldDescriptor* field = descriptor->field(i);
@@ -205,7 +332,7 @@
         if (field->type() != FieldDescriptor::TYPE_MESSAGE) {
             continue;
         }
-        const SectionFlags s = field->options().GetExtension(section);
+        const SectionFlags s = getSectionFlags(field);
         switch (s.type()) {
             case SECTION_NONE:
                 continue;
@@ -225,16 +352,73 @@
         }
     }
     printf("    NULL };\n");
+
+    emptyline();
+    printf("// =============================================================================\n");
     emptyline();
 
-    // generates PRIVACY_POLICY
+    // generates PRIVACY_POLICY_LIST
+    printf("// Generate PRIVACY_POLICY_LIST.\n\n");
     map<string, bool> messageNames;
-    if (!generatePrivacyFlags(descriptor, "PRIVACY_POLICY", messageNames)) {
-        // if no privacy options set at all, define an empty list
-        printf("const Privacy* PRIVACY_POLICY_LIST[] = {};\n");
-        printf("const int PRIVACY_POLICY_COUNT = 0;\n");
+    set<string> parents;
+    bool skip[descriptor->field_count()];
+
+    for (int i=0; i<descriptor->field_count(); i++) {
+        const FieldDescriptor* field = descriptor->field(i);
+        const string fieldName = getFieldName(field);
+        PrivacyFlags p = getPrivacyFlags(field);
+
+        skip[i] = true;
+
+        if (field->type() != FieldDescriptor::TYPE_MESSAGE) {
+            continue;
+        }
+        // generate privacy flags for each field.
+        if (generatePrivacyFlags(field->message_type(), messageNames, &parents)) {
+            printf("Privacy %s { %d, %d, %s, %d, NULL };\n", fieldName.c_str(), field->number(),
+                    field->type(), getMessageTypeName(field->message_type()).c_str(), p.dest());
+        } else if (isDefaultField(field)) {
+            continue; // don't create a new privacy if the value is default.
+        } else {
+            printf("Privacy %s { %d, %d, NULL, %d, NULL };\n", fieldName.c_str(), field->number(),
+                    field->type(), p.dest());
+        }
+        skip[i] = false;
     }
 
+    // generate final PRIVACY_POLICY_LIST
+    emptyline();
+    int policyCount = 0;
+    if (gSelfRecursionAssignments.empty()) {
+        printf("Privacy* privacyArray[] = {\n");
+        for (int i=0; i<descriptor->field_count(); i++) {
+            if (skip[i]) continue;
+            printf("    &%s,\n", getFieldName(descriptor->field(i)).c_str());
+            policyCount++;
+        }
+        printf("};\n\n");
+        printf("const Privacy** PRIVACY_POLICY_LIST = const_cast<const Privacy**>(privacyArray);\n\n");
+        printf("const int PRIVACY_POLICY_COUNT = %d;\n", policyCount);
+    } else {
+        for (int i=0; i<descriptor->field_count(); i++) {
+            if (!skip[i]) policyCount++;
+        }
+
+        printf("static const Privacy** createList() {\n");
+        for (size_t i=0; i<gSelfRecursionAssignments.size(); ++i) {
+            printf("    %s;\n", gSelfRecursionAssignments[i].c_str());
+        }
+        printf("    Privacy** privacyArray = (Privacy**)malloc(%d * sizeof(Privacy**));\n", policyCount);
+        policyCount = 0; // reset
+        for (int i=0; i<descriptor->field_count(); i++) {
+            if (skip[i]) continue;
+            printf("    privacyArray[%d] = &%s;\n", policyCount++, getFieldName(descriptor->field(i)).c_str());
+        }
+        printf("    return const_cast<const Privacy**>(privacyArray);\n");
+        printf("}\n\n");
+        printf("const Privacy** PRIVACY_POLICY_LIST = createList();\n\n");
+        printf("const int PRIVACY_POLICY_COUNT = %d;\n", policyCount);
+    }
     return true;
 }
 
diff --git a/tools/streaming_proto/Android.bp b/tools/streaming_proto/Android.bp
index 96e060d..dc5c14e 100644
--- a/tools/streaming_proto/Android.bp
+++ b/tools/streaming_proto/Android.bp
@@ -21,8 +21,11 @@
     name: "protoc-gen-stream-defaults",
     srcs: [
         "Errors.cpp",
+        "stream_proto_utils.cpp",
         "string_utils.cpp",
     ],
+
+    shared_libs: ["libprotoc"],
 }
 
 cc_library {
@@ -52,7 +55,6 @@
     ],
 
     defaults: ["protoc-gen-stream-defaults"],
-    shared_libs: ["libprotoc"],
 }
 
 cc_binary_host {
@@ -62,6 +64,5 @@
     ],
 
     defaults: ["protoc-gen-stream-defaults"],
-    shared_libs: ["libprotoc"],
     static_libs: ["streamingflags"],
 }
diff --git a/tools/streaming_proto/cpp/main.cpp b/tools/streaming_proto/cpp/main.cpp
index dc96d5c..4816984 100644
--- a/tools/streaming_proto/cpp/main.cpp
+++ b/tools/streaming_proto/cpp/main.cpp
@@ -1,108 +1,23 @@
 #include "Errors.h"
+#include "stream_proto_utils.h"
 #include "string_utils.h"
 
 #include <frameworks/base/tools/streaming_proto/stream.pb.h>
 
-#include "google/protobuf/compiler/plugin.pb.h"
-#include "google/protobuf/io/zero_copy_stream_impl.h"
-#include "google/protobuf/text_format.h"
-
 #include <iomanip>
 #include <iostream>
 #include <sstream>
 
 using namespace android::stream_proto;
-using namespace google::protobuf;
-using namespace google::protobuf::compiler;
 using namespace google::protobuf::io;
 using namespace std;
 
-/**
- * Position of the field type in a (long long) fieldId.
- */
-const uint64_t FIELD_TYPE_SHIFT = 32;
-
-//
-// FieldId flags for whether the field is single, repeated or packed.
-// TODO: packed is not supported yet.
-//
-const uint64_t FIELD_COUNT_SHIFT = 40;
-const uint64_t FIELD_COUNT_MASK = 0x0fULL << FIELD_COUNT_SHIFT;
-const uint64_t FIELD_COUNT_UNKNOWN = 0;
-const uint64_t FIELD_COUNT_SINGLE = 1ULL << FIELD_COUNT_SHIFT;
-const uint64_t FIELD_COUNT_REPEATED = 2ULL << FIELD_COUNT_SHIFT;
-const uint64_t FIELD_COUNT_PACKED = 4ULL << FIELD_COUNT_SHIFT;
-
-// Indent
-const string INDENT = "    ";
-
-/**
- * See if this is the file for this request, and not one of the imported ones.
- */
-static bool
-should_generate_for_file(const CodeGeneratorRequest& request, const string& file)
-{
-    const int N = request.file_to_generate_size();
-    for (int i=0; i<N; i++) {
-        if (request.file_to_generate(i) == file) {
-            return true;
-        }
-    }
-    return false;
-}
-
 static string
 make_filename(const FileDescriptorProto& file_descriptor)
 {
     return file_descriptor.name() + ".h";
 }
 
-static string
-get_proto_type(const FieldDescriptorProto& field)
-{
-    switch (field.type()) {
-        case FieldDescriptorProto::TYPE_DOUBLE:
-            return "double";
-        case FieldDescriptorProto::TYPE_FLOAT:
-            return "float";
-        case FieldDescriptorProto::TYPE_INT64:
-            return "int64";
-        case FieldDescriptorProto::TYPE_UINT64:
-            return "uint64";
-        case FieldDescriptorProto::TYPE_INT32:
-            return "int32";
-        case FieldDescriptorProto::TYPE_FIXED64:
-            return "fixed64";
-        case FieldDescriptorProto::TYPE_FIXED32:
-            return "fixed32";
-        case FieldDescriptorProto::TYPE_BOOL:
-            return "bool";
-        case FieldDescriptorProto::TYPE_STRING:
-            return "string";
-        case FieldDescriptorProto::TYPE_GROUP:
-            return "group<unsupported!>";
-        case FieldDescriptorProto::TYPE_MESSAGE:
-            return field.type_name();
-        case FieldDescriptorProto::TYPE_BYTES:
-            return "bytes";
-        case FieldDescriptorProto::TYPE_UINT32:
-            return "uint32";
-        case FieldDescriptorProto::TYPE_ENUM:
-            return field.type_name();
-        case FieldDescriptorProto::TYPE_SFIXED32:
-            return "sfixed32";
-        case FieldDescriptorProto::TYPE_SFIXED64:
-            return "sfixed64";
-        case FieldDescriptorProto::TYPE_SINT32:
-            return "sint32";
-        case FieldDescriptorProto::TYPE_SINT64:
-            return "sint64";
-        default:
-            // won't happen
-            return "void";
-    }
-}
-
 static void
 write_enum(stringstream& text, const EnumDescriptorProto& enu, const string& indent)
 {
@@ -117,27 +32,6 @@
     text << endl;
 }
 
-static uint64_t
-get_field_id(const FieldDescriptorProto& field)
-{
-    // Number
-    uint64_t result = (uint64_t)field.number();
-
-    // Type
-    result |= (uint64_t)field.type() << FIELD_TYPE_SHIFT;
-
-    // Count
-    if (field.options().packed()) {
-        result |= FIELD_COUNT_PACKED;
-    } else if (field.label() == FieldDescriptorProto::LABEL_REPEATED) {
-        result |= FIELD_COUNT_REPEATED;
-    } else {
-        result |= FIELD_COUNT_SINGLE;
-    }
-
-    return result;
-}
-
 static void
 write_field(stringstream& text, const FieldDescriptorProto& field, const string& indent)
 {
diff --git a/tools/streaming_proto/java/main.cpp b/tools/streaming_proto/java/main.cpp
index b7d594b..c9c50a5 100644
--- a/tools/streaming_proto/java/main.cpp
+++ b/tools/streaming_proto/java/main.cpp
@@ -1,11 +1,7 @@
 #include "Errors.h"
-
+#include "stream_proto_utils.h"
 #include "string_utils.h"
 
-#include "google/protobuf/compiler/plugin.pb.h"
-#include "google/protobuf/io/zero_copy_stream_impl.h"
-#include "google/protobuf/text_format.h"
-
 #include <stdio.h>
 #include <iomanip>
 #include <iostream>
@@ -13,51 +9,9 @@
 #include <map>
 
 using namespace android::stream_proto;
-using namespace google::protobuf;
-using namespace google::protobuf::compiler;
 using namespace google::protobuf::io;
 using namespace std;
 
-const int FIELD_TYPE_SHIFT = 32;
-const uint64_t FIELD_TYPE_DOUBLE = 1L << FIELD_TYPE_SHIFT;
-const uint64_t FIELD_TYPE_FLOAT = 2L << FIELD_TYPE_SHIFT;
-const uint64_t FIELD_TYPE_INT32 = 3L << FIELD_TYPE_SHIFT;
-const uint64_t FIELD_TYPE_INT64 = 4L << FIELD_TYPE_SHIFT;
-const uint64_t FIELD_TYPE_UINT32 = 5L << FIELD_TYPE_SHIFT;
-const uint64_t FIELD_TYPE_UINT64 = 6L << FIELD_TYPE_SHIFT;
-const uint64_t FIELD_TYPE_SINT32 = 7L << FIELD_TYPE_SHIFT;
-const uint64_t FIELD_TYPE_SINT64 = 8L << FIELD_TYPE_SHIFT;
-const uint64_t FIELD_TYPE_FIXED32 = 9L << FIELD_TYPE_SHIFT;
-const uint64_t FIELD_TYPE_FIXED64 = 10L << FIELD_TYPE_SHIFT;
-const uint64_t FIELD_TYPE_SFIXED32 = 11L << FIELD_TYPE_SHIFT;
-const uint64_t FIELD_TYPE_SFIXED64 = 12L << FIELD_TYPE_SHIFT;
-const uint64_t FIELD_TYPE_BOOL = 13L << FIELD_TYPE_SHIFT;
-const uint64_t FIELD_TYPE_STRING = 14L << FIELD_TYPE_SHIFT;
-const uint64_t FIELD_TYPE_BYTES = 15L << FIELD_TYPE_SHIFT;
-const uint64_t FIELD_TYPE_ENUM = 16L << FIELD_TYPE_SHIFT;
-const uint64_t FIELD_TYPE_OBJECT = 17L << FIELD_TYPE_SHIFT;
-
-const int FIELD_COUNT_SHIFT = 40;
-const uint64_t FIELD_COUNT_SINGLE = 1L << FIELD_COUNT_SHIFT;
-const uint64_t FIELD_COUNT_REPEATED = 2L << FIELD_COUNT_SHIFT;
-const uint64_t FIELD_COUNT_PACKED = 5L << FIELD_COUNT_SHIFT;
-
-
-/**
- * See if this is the file for this request, and not one of the imported ones.
- */
-static bool
-should_generate_for_file(const CodeGeneratorRequest& request, const string& file)
-{
-    const int N = request.file_to_generate_size();
-    for (int i=0; i<N; i++) {
-        if (request.file_to_generate(i) == file) {
-            return true;
-        }
-    }
-    return false;
-}
-
 /**
  * If the descriptor gives us a class name, use that. Otherwise make one up from
  * the filename of the .proto file.
@@ -112,7 +66,7 @@
 static string
 indent_more(const string& indent)
 {
-    return indent + "    ";
+    return indent + INDENT;
 }
 
 /**
@@ -133,130 +87,6 @@
 }
 
 /**
- * Get the string name for a field.
- */
-static string
-get_proto_type(const FieldDescriptorProto& field)
-{
-    switch (field.type()) {
-        case FieldDescriptorProto::TYPE_DOUBLE:
-            return "double";
-        case FieldDescriptorProto::TYPE_FLOAT:
-            return "float";
-        case FieldDescriptorProto::TYPE_INT64:
-            return "int64";
-        case FieldDescriptorProto::TYPE_UINT64:
-            return "uint64";
-        case FieldDescriptorProto::TYPE_INT32:
-            return "int32";
-        case FieldDescriptorProto::TYPE_FIXED64:
-            return "fixed64";
-        case FieldDescriptorProto::TYPE_FIXED32:
-            return "fixed32";
-        case FieldDescriptorProto::TYPE_BOOL:
-            return "bool";
-        case FieldDescriptorProto::TYPE_STRING:
-            return "string";
-        case FieldDescriptorProto::TYPE_GROUP:
-            return "group<unsupported!>";
-        case FieldDescriptorProto::TYPE_MESSAGE:
-            return field.type_name();
-        case FieldDescriptorProto::TYPE_BYTES:
-            return "bytes";
-        case FieldDescriptorProto::TYPE_UINT32:
-            return "uint32";
-        case FieldDescriptorProto::TYPE_ENUM:
-            return field.type_name();
-        case FieldDescriptorProto::TYPE_SFIXED32:
-            return "sfixed32";
-        case FieldDescriptorProto::TYPE_SFIXED64:
-            return "sfixed64";
-        case FieldDescriptorProto::TYPE_SINT32:
-            return "sint32";
-        case FieldDescriptorProto::TYPE_SINT64:
-            return "sint64";
-        default:
-            // won't happen
-            return "void";
-    }
-}
-
-static uint64_t
-get_field_id(const FieldDescriptorProto& field)
-{
-    // Number
-    uint64_t result = (uint32_t)field.number();
-
-    // Type
-    switch (field.type()) {
-        case FieldDescriptorProto::TYPE_DOUBLE:
-            result |= FIELD_TYPE_DOUBLE;
-            break;
-        case FieldDescriptorProto::TYPE_FLOAT:
-            result |= FIELD_TYPE_FLOAT;
-            break;
-        case FieldDescriptorProto::TYPE_INT64:
-            result |= FIELD_TYPE_INT64;
-            break;
-        case FieldDescriptorProto::TYPE_UINT64:
-            result |= FIELD_TYPE_UINT64;
-            break;
-        case FieldDescriptorProto::TYPE_INT32:
-            result |= FIELD_TYPE_INT32;
-            break;
-        case FieldDescriptorProto::TYPE_FIXED64:
-            result |= FIELD_TYPE_FIXED64;
-            break;
-        case FieldDescriptorProto::TYPE_FIXED32:
-            result |= FIELD_TYPE_FIXED32;
-            break;
-        case FieldDescriptorProto::TYPE_BOOL:
-            result |= FIELD_TYPE_BOOL;
-            break;
-        case FieldDescriptorProto::TYPE_STRING:
-            result |= FIELD_TYPE_STRING;
-            break;
-        case FieldDescriptorProto::TYPE_MESSAGE:
-            result |= FIELD_TYPE_OBJECT;
-            break;
-        case FieldDescriptorProto::TYPE_BYTES:
-            result |= FIELD_TYPE_BYTES;
-            break;
-        case FieldDescriptorProto::TYPE_UINT32:
-            result |= FIELD_TYPE_UINT32;
-            break;
-        case FieldDescriptorProto::TYPE_ENUM:
-            result |= FIELD_TYPE_ENUM;
-            break;
-        case FieldDescriptorProto::TYPE_SFIXED32:
-            result |= FIELD_TYPE_SFIXED32;
-            break;
-        case FieldDescriptorProto::TYPE_SFIXED64:
-            result |= FIELD_TYPE_SFIXED64;
-            break;
-        case FieldDescriptorProto::TYPE_SINT32:
-            result |= FIELD_TYPE_SINT32;
-            break;
-        case FieldDescriptorProto::TYPE_SINT64:
-            result |= FIELD_TYPE_SINT64;
-            break;
-        default:
-            ;
-    }
-
-    // Count
-    if (field.options().packed()) {
-        result |= FIELD_COUNT_PACKED;
-    } else if (field.label() == FieldDescriptorProto::LABEL_REPEATED) {
-        result |= FIELD_COUNT_REPEATED;
-    } else {
-        result |= FIELD_COUNT_SINGLE;
-    }
-
-    return result;
-}
-
-/**
  * Write a field.
  */
 static void
diff --git a/tools/streaming_proto/stream_proto_utils.cpp b/tools/streaming_proto/stream_proto_utils.cpp
new file mode 100644
index 0000000..e8f86bc
--- /dev/null
+++ b/tools/streaming_proto/stream_proto_utils.cpp
@@ -0,0 +1,102 @@
+#include "stream_proto_utils.h"
+
+namespace android {
+namespace stream_proto {
+
+/**
+ * Position of the field type in a (long long) fieldId.
+ */
+const uint64_t FIELD_TYPE_SHIFT = 32;
+
+//
+// FieldId flags for whether the field is single, repeated or packed.
+// TODO: packed is not supported yet.
+//
+const uint64_t FIELD_COUNT_SHIFT = 40;
+const uint64_t FIELD_COUNT_MASK = 0x0fULL << FIELD_COUNT_SHIFT;
+const uint64_t FIELD_COUNT_UNKNOWN = 0;
+const uint64_t FIELD_COUNT_SINGLE = 1ULL << FIELD_COUNT_SHIFT;
+const uint64_t FIELD_COUNT_REPEATED = 2ULL << FIELD_COUNT_SHIFT;
+const uint64_t FIELD_COUNT_PACKED = 5ULL << FIELD_COUNT_SHIFT;
+
+uint64_t
+get_field_id(const FieldDescriptorProto& field)
+{
+    // Number
+    uint64_t result = (uint32_t)field.number();
+
+    // Type
+    result |= (uint64_t)field.type() << FIELD_TYPE_SHIFT;
+
+    // Count
+    if (field.options().packed()) {
+        result |= FIELD_COUNT_PACKED;
+    } else if (field.label() == FieldDescriptorProto::LABEL_REPEATED) {
+        result |= FIELD_COUNT_REPEATED;
+    } else {
+        result |= FIELD_COUNT_SINGLE;
+    }
+
+    return result;
+}
+
+string
+get_proto_type(const FieldDescriptorProto& field)
+{
+    switch (field.type()) {
+        case FieldDescriptorProto::TYPE_DOUBLE:
+            return "double";
+        case FieldDescriptorProto::TYPE_FLOAT:
+            return "float";
+        case FieldDescriptorProto::TYPE_INT64:
+            return "int64";
+        case FieldDescriptorProto::TYPE_UINT64:
+            return "uint64";
+        case FieldDescriptorProto::TYPE_INT32:
+            return "int32";
+        case FieldDescriptorProto::TYPE_FIXED64:
+            return "fixed64";
+        case FieldDescriptorProto::TYPE_FIXED32:
+            return "fixed32";
+        case FieldDescriptorProto::TYPE_BOOL:
+            return "bool";
+        case FieldDescriptorProto::TYPE_STRING:
+            return "string";
+        case FieldDescriptorProto::TYPE_GROUP:
+            return "group<unsupported!>";
+        case FieldDescriptorProto::TYPE_MESSAGE:
+            return field.type_name();
+        case FieldDescriptorProto::TYPE_BYTES:
+            return "bytes";
+        case FieldDescriptorProto::TYPE_UINT32:
+            return "uint32";
+        case FieldDescriptorProto::TYPE_ENUM:
+            return field.type_name();
+        case FieldDescriptorProto::TYPE_SFIXED32:
+            return "sfixed32";
+        case FieldDescriptorProto::TYPE_SFIXED64:
+            return "sfixed64";
+        case FieldDescriptorProto::TYPE_SINT32:
+            return "sint32";
+        case FieldDescriptorProto::TYPE_SINT64:
+            return "sint64";
+        default:
+            // won't happen
+            return "void";
+    }
+}
+
+bool
+should_generate_for_file(const CodeGeneratorRequest& request, const string& file)
+{
+    const int N = request.file_to_generate_size();
+    for (int i=0; i<N; i++) {
+        if (request.file_to_generate(i) == file) {
+            return true;
+        }
+    }
+    return false;
+}
+
+} // stream_proto
+} // android
diff --git a/tools/streaming_proto/stream_proto_utils.h b/tools/streaming_proto/stream_proto_utils.h
new file mode 100644
index 0000000..5297ecc
--- /dev/null
+++ b/tools/streaming_proto/stream_proto_utils.h
@@ -0,0 +1,29 @@
+#include <stdint.h>
+
+#include "google/protobuf/compiler/plugin.pb.h"
+#include "google/protobuf/io/zero_copy_stream_impl.h"
+
+namespace android {
+namespace stream_proto {
+
+using namespace google::protobuf;
+using namespace google::protobuf::compiler;
+using namespace std;
+
+/**
+ * Get encoded field id from a field.
+ */
+uint64_t get_field_id(const FieldDescriptorProto& field);
+
+/**
+ * Get the string name for a field.
+ */
+string get_proto_type(const FieldDescriptorProto& field);
+
+/**
+ * See if this is the file for this request, and not one of the imported ones.
+ */
+bool should_generate_for_file(const CodeGeneratorRequest& request, const string& file);
+
+} // stream_proto
+} // android
diff --git a/tools/streaming_proto/string_utils.h b/tools/streaming_proto/string_utils.h
index 03284d1..d6f195f 100644
--- a/tools/streaming_proto/string_utils.h
+++ b/tools/streaming_proto/string_utils.h
@@ -6,6 +6,9 @@
 
 using namespace std;
 
+// Indent
+const string INDENT = "    ";
+
 /**
  * Capitalizes the string, removes underscores and makes the next letter
  * capitalized, and makes the letter following numbers capitalized.