Merge "Fixed scenario where an authentication response has no dataset." into oc-dev
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index deb5b31..588a1bf 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -1441,10 +1441,10 @@
             System.err.println("Error: no size specified");
             return showUsage();
         }
-        int len = size.length();
         long multiplier = 1;
-        if (len > 1) {
-            char c = size.charAt(len-1);
+        int len = size.length();
+        char c = size.charAt(len - 1);
+        if (c < '0' || c > '9') {
             if (c == 'K' || c == 'k') {
                 multiplier = 1024L;
             } else if (c == 'M' || c == 'm') {
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index dd9db8a..928ef7e 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -4275,9 +4275,19 @@
             View.mDebugViewAttributes = debugViewAttributes;
 
             // request all activities to relaunch for the changes to take place
-            for (Map.Entry<IBinder, ActivityClientRecord> entry : mActivities.entrySet()) {
-                requestRelaunchActivity(entry.getKey(), null, null, 0, false, null, null, false,
-                        false /* preserveWindow */);
+            requestRelaunchAllActivities();
+        }
+    }
+
+    private void requestRelaunchAllActivities() {
+        for (Map.Entry<IBinder, ActivityClientRecord> entry : mActivities.entrySet()) {
+            final Activity activity = entry.getValue().activity;
+            if (!activity.mFinished) {
+                try {
+                    ActivityManager.getService().requestActivityRelaunch(entry.getKey());
+                } catch (RemoteException e) {
+                    throw e.rethrowFromSystemServer();
+                }
             }
         }
     }
@@ -5084,24 +5094,26 @@
         // caused by other sources, such as overlays. That means we want to be as conservative
         // about code changes as possible. Take the diff of the old ApplicationInfo and the new
         // to see if anything needs to change.
+        LoadedApk apk;
+        LoadedApk resApk;
+        // Update all affected loaded packages with new package information
         synchronized (mResourcesManager) {
-            // Update all affected loaded packages with new package information
             WeakReference<LoadedApk> ref = mPackages.get(ai.packageName);
-            LoadedApk apk = ref != null ? ref.get() : null;
-            if (apk != null) {
-                final ArrayList<String> oldPaths = new ArrayList<>();
-                LoadedApk.makePaths(this, apk.getApplicationInfo(), oldPaths);
-                apk.updateApplicationInfo(ai, oldPaths);
-            }
-
-            ref = mResourcePackages.get(ai.packageName);
             apk = ref != null ? ref.get() : null;
-            if (apk != null) {
-                final ArrayList<String> oldPaths = new ArrayList<>();
-                LoadedApk.makePaths(this, apk.getApplicationInfo(), oldPaths);
-                apk.updateApplicationInfo(ai, oldPaths);
-            }
-
+            ref = mResourcePackages.get(ai.packageName);
+            resApk = ref != null ? ref.get() : null;
+        }
+        if (apk != null) {
+            final ArrayList<String> oldPaths = new ArrayList<>();
+            LoadedApk.makePaths(this, apk.getApplicationInfo(), oldPaths);
+            apk.updateApplicationInfo(ai, oldPaths);
+        }
+        if (resApk != null) {
+            final ArrayList<String> oldPaths = new ArrayList<>();
+            LoadedApk.makePaths(this, resApk.getApplicationInfo(), oldPaths);
+            resApk.updateApplicationInfo(ai, oldPaths);
+        }
+        synchronized (mResourcesManager) {
             // Update all affected Resources objects to use new ResourcesImpl
             mResourcesManager.applyNewResourceDirsLocked(ai.sourceDir, ai.resourceDirs);
         }
@@ -5116,14 +5128,7 @@
         newConfig.assetsSeq = (mConfiguration != null ? mConfiguration.assetsSeq : 0) + 1;
         handleConfigurationChanged(newConfig, null);
 
-        // Schedule all activities to reload
-        for (final Map.Entry<IBinder, ActivityClientRecord> entry : mActivities.entrySet()) {
-            final Activity activity = entry.getValue().activity;
-            if (!activity.mFinished) {
-                requestRelaunchActivity(entry.getKey(), null, null, 0, false, null, null, false,
-                        false);
-            }
-        }
+        requestRelaunchAllActivities();
     }
 
     static void freeTextLayoutCachesIfNeeded(int configDiff) {
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 63c0ef3..1b2543c 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -2497,7 +2497,6 @@
             mBackStack = new ArrayList<BackStackRecord>();
         }
         mBackStack.add(state);
-        reportBackStackChanged();
     }
 
     boolean popBackStackState(ArrayList<BackStackRecord> records, ArrayList<Boolean> isRecordPop,
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index aeccf56..68fce75 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -200,7 +200,7 @@
     void setRequestedOrientation(in IBinder token, int requestedOrientation);
     int getRequestedOrientation(in IBinder token);
     void unbindFinished(in IBinder token, in Intent service, boolean doRebind);
-    void setProcessForeground(in IBinder token, int pid, boolean isForeground);
+    void setProcessImportant(in IBinder token, int pid, boolean isForeground, String reason);
     void setServiceForeground(in ComponentName className, in IBinder token,
             int id, in Notification notification, int flags);
     boolean moveActivityTaskToBack(in IBinder token, boolean nonRoot);
diff --git a/core/java/android/app/VrManager.java b/core/java/android/app/VrManager.java
index 040b330..8014eca 100644
--- a/core/java/android/app/VrManager.java
+++ b/core/java/android/app/VrManager.java
@@ -6,8 +6,6 @@
 import android.os.RemoteException;
 import android.service.vr.IVrManager;
 
-import java.io.FileDescriptor;
-
 /**
  * Used to control aspects of a devices Virtual Reality (VR) capabilities.
  * <p>
@@ -63,32 +61,4 @@
             e.rethrowFromSystemServer();
         }
     }
-
-    /**
-     * Initiate connection for system controller data.
-     *
-     * @param fd Controller data file descriptor.
-     *
-     * {@hide}
-     */
-    public void connectController(FileDescriptor fd) {
-        try {
-            mService.connectController(fd);
-        } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Sever connection for system controller data.
-     *
-     * {@hide}
-     */
-    public void disconnectController() {
-        try {
-            mService.disconnectController();
-        } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
-        }
-    }
 }
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index 7261dfa..1994206 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -18,6 +18,7 @@
 import android.os.PooledStringWriter;
 import android.os.RemoteException;
 import android.os.SystemClock;
+import android.service.autofill.FillContext;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.Pair;
@@ -1103,6 +1104,9 @@
          * Returns the transformation that has been applied to this view, such as a translation
          * or scaling.  The returned Matrix object is owned by ViewNode; do not modify it.
          * Returns null if there is no transformation applied to the view.
+         *
+         * <p>It's only relevant when the {@link AssistStructure} is used for Assist purposes,
+         * not for Autofill purposes.
          */
         public Matrix getTransformation() {
             return mMatrix;
@@ -1112,6 +1116,9 @@
          * Returns the visual elevation of the view, used for shadowing and other visual
          * characterstics, as set by {@link ViewStructure#setElevation
          * ViewStructure.setElevation(float)}.
+         *
+         * <p>It's only relevant when the {@link AssistStructure} is used for Assist purposes,
+         * not for Autofill purposes.
          */
         public float getElevation() {
             return mElevation;
@@ -1121,6 +1128,9 @@
          * Returns the alpha transformation of the view, used to reduce the overall opacity
          * of the view's contents, as set by {@link ViewStructure#setAlpha
          * ViewStructure.setAlpha(float)}.
+         *
+         * <p>It's only relevant when the {@link AssistStructure} is used for Assist purposes,
+         * not for Autofill purposes.
          */
         public float getAlpha() {
             return mAlpha;
@@ -1289,6 +1299,9 @@
 
         /**
          * If {@link #getText()} is non-null, this is where the current selection starts.
+         *
+         * <p>It's only relevant when the {@link AssistStructure} is used for Assist purposes,
+         * not for Autofill purposes.
          */
         public int getTextSelectionStart() {
             return mText != null ? mText.mTextSelectionStart : -1;
@@ -1298,6 +1311,9 @@
          * If {@link #getText()} is non-null, this is where the current selection starts.
          * If there is no selection, returns the same value as {@link #getTextSelectionStart()},
          * indicating the cursor position.
+         *
+         * <p>It's only relevant when the {@link AssistStructure} is used for Assist purposes,
+         * not for Autofill purposes.
          */
         public int getTextSelectionEnd() {
             return mText != null ? mText.mTextSelectionEnd : -1;
@@ -1319,6 +1335,9 @@
          * If there is no text background color, {@link #TEXT_COLOR_UNDEFINED} is returned.
          * Note that the text may also contain style spans that modify the color of specific
          * parts of the text.
+         *
+         * <p>It's only relevant when the {@link AssistStructure} is used for Assist purposes,
+         * not for Autofill purposes.
          */
         public int getTextBackgroundColor() {
             return mText != null ? mText.mTextBackgroundColor : TEXT_COLOR_UNDEFINED;
@@ -1329,6 +1348,9 @@
          * with it.
          * Note that the text may also contain style spans that modify the size of specific
          * parts of the text.
+         *
+         * <p>It's only relevant when the {@link AssistStructure} is used for Assist purposes,
+         * not for Autofill purposes.
          */
         public float getTextSize() {
             return mText != null ? mText.mTextSize : 0;
@@ -1341,6 +1363,9 @@
          * {@link #TEXT_STYLE_UNDERLINE}.
          * Note that the text may also contain style spans that modify the style of specific
          * parts of the text.
+         *
+         * <p>It's only relevant when the {@link AssistStructure} is used for Assist purposes,
+         * not for Autofill purposes.
          */
         public int getTextStyle() {
             return mText != null ? mText.mTextStyle : 0;
@@ -1351,6 +1376,9 @@
          * in the array is a formatted line of text, and the value it contains is the offset
          * into the text string where that line starts.  May return null if there is no line
          * information.
+         *
+         * <p>It's only relevant when the {@link AssistStructure} is used for Assist purposes,
+         * not for Autofill purposes.
          */
         public int[] getTextLineCharOffsets() {
             return mText != null ? mText.mLineCharOffsets : null;
@@ -1361,6 +1389,9 @@
          * in the array is a formatted line of text, and the value it contains is the baseline
          * where that text appears in the view.  May return null if there is no line
          * information.
+         *
+         * <p>It's only relevant when the {@link AssistStructure} is used for Assist purposes,
+         * not for Autofill purposes.
          */
         public int[] getTextLineBaselines() {
             return mText != null ? mText.mLineBaselines : null;
diff --git a/core/java/android/app/usage/ExternalStorageStats.java b/core/java/android/app/usage/ExternalStorageStats.java
index 83ac779e..d7e570f 100644
--- a/core/java/android/app/usage/ExternalStorageStats.java
+++ b/core/java/android/app/usage/ExternalStorageStats.java
@@ -37,30 +37,46 @@
     /**
      * Return the total bytes used by all files in the shared/external storage
      * hosted on this volume.
+     * <p>
+     * This value only includes data which is isolated for each user on a
+     * multiuser device. Any OBB data shared between users is not accounted in
+     * this value.
      */
     public @BytesLong long getTotalBytes() {
         return totalBytes;
     }
 
     /**
-     * Return the total bytes used by audio files in the shared/external storage
-     * hosted on this volume.
+     * Return the total bytes used by all audio files in the shared/external
+     * storage hosted on this volume.
+     * <p>
+     * This value only includes data which is isolated for each user on a
+     * multiuser device. This value does not include any app files which are all
+     * accounted under {@link #getAppBytes()}.
      */
     public @BytesLong long getAudioBytes() {
         return audioBytes;
     }
 
     /**
-     * Return the total bytes used by video files in the shared/external storage
-     * hosted on this volume.
+     * Return the total bytes used by all video files in the shared/external
+     * storage hosted on this volume.
+     * <p>
+     * This value only includes data which is isolated for each user on a
+     * multiuser device. This value does not include any app files which are all
+     * accounted under {@link #getAppBytes()}.
      */
     public @BytesLong long getVideoBytes() {
         return videoBytes;
     }
 
     /**
-     * Return the total bytes used by image files in the shared/external storage
-     * hosted on this volume.
+     * Return the total bytes used by all image files in the shared/external
+     * storage hosted on this volume.
+     * <p>
+     * This value only includes data which is isolated for each user on a
+     * multiuser device. This value does not include any app files which are all
+     * accounted under {@link #getAppBytes()}.
      */
     public @BytesLong long getImageBytes() {
         return imageBytes;
@@ -72,6 +88,9 @@
      * <p>
      * This data is already accounted against individual apps as returned
      * through {@link StorageStats}.
+     * <p>
+     * This value only includes data which is isolated for each user on a
+     * multiuser device.
      */
     public @BytesLong long getAppBytes() {
         return appBytes;
diff --git a/core/java/android/content/pm/InstantAppResolveInfo.java b/core/java/android/content/pm/InstantAppResolveInfo.java
index 603192a..dcaf66e 100644
--- a/core/java/android/content/pm/InstantAppResolveInfo.java
+++ b/core/java/android/content/pm/InstantAppResolveInfo.java
@@ -47,7 +47,7 @@
     private final int mVersionCode;
 
     public InstantAppResolveInfo(@NonNull InstantAppDigest digest, @Nullable String packageName,
-            @Nullable List<InstantAppIntentFilter> filters, int versionConde) {
+            @Nullable List<InstantAppIntentFilter> filters, int versionCode) {
         // validate arguments
         if ((packageName == null && (filters != null && filters.size() != 0))
                 || (packageName != null && (filters == null || filters.size() == 0))) {
@@ -61,7 +61,7 @@
             mFilters = null;
         }
         mPackageName = packageName;
-        mVersionCode = versionConde;
+        mVersionCode = versionCode;
     }
 
     public InstantAppResolveInfo(@NonNull String hostName, @Nullable String packageName,
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index 2b76ae2..d0c6397 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -23,7 +23,6 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.pm.LauncherApps.ShortcutQuery;
 import android.content.res.Resources;
 import android.content.res.Resources.NotFoundException;
@@ -96,6 +95,9 @@
     public static final int FLAG_ADAPTIVE_BITMAP = 1 << 9;
 
     /** @hide */
+    public static final int FLAG_RETURNED_BY_SERVICE = 1 << 10;
+
+    /** @hide */
     @IntDef(flag = true,
             value = {
             FLAG_DYNAMIC,
@@ -108,6 +110,7 @@
             FLAG_STRINGS_RESOLVED,
             FLAG_IMMUTABLE,
             FLAG_ADAPTIVE_BITMAP,
+            FLAG_RETURNED_BY_SERVICE
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ShortcutFlags {}
@@ -1343,6 +1346,16 @@
         return (mFlags & flags) == flags;
     }
 
+    /** @hide */
+    public boolean isReturnedByServer() {
+        return hasFlags(FLAG_RETURNED_BY_SERVICE);
+    }
+
+    /** @hide */
+    public void setReturnedByServer() {
+        addFlags(FLAG_RETURNED_BY_SERVICE);
+    }
+
     /** Return whether a shortcut is dynamic. */
     public boolean isDynamic() {
         return hasFlags(FLAG_DYNAMIC);
@@ -1450,7 +1463,7 @@
 
     /**
      * Return whether a shortcut's icon is adaptive bitmap following design guideline
-     * defined in {@link AdaptiveIconDrawable}.
+     * defined in {@link android.graphics.drawable.AdaptiveIconDrawable}.
      *
      * @hide internal/unit tests only
      */
@@ -1776,6 +1789,9 @@
         if (hasStringResourcesResolved()) {
             sb.append("Sr");
         }
+        if (isReturnedByServer()) {
+            sb.append("V");
+        }
         sb.append("]");
 
         sb.append(", packageName=");
diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java
index a7c09b5..e3e0cc5 100644
--- a/core/java/android/content/pm/ShortcutManager.java
+++ b/core/java/android/content/pm/ShortcutManager.java
@@ -618,6 +618,10 @@
     /**
      * Return all dynamic shortcuts from the caller app.
      *
+     * <p>This API is intended to be used for examining what shortcuts are currently published.
+     * Re-publishing returned {@link ShortcutInfo}s via APIs such as
+     * {@link #setDynamicShortcuts(List)} may cause loss of information such as icons.
+     *
      * @throws IllegalStateException when the user is locked.
      */
     @NonNull
@@ -633,6 +637,10 @@
     /**
      * Return all static (manifest) shortcuts from the caller app.
      *
+     * <p>This API is intended to be used for examining what shortcuts are currently published.
+     * Re-publishing returned {@link ShortcutInfo}s via APIs such as
+     * {@link #setDynamicShortcuts(List)} may cause loss of information such as icons.
+     *
      * @throws IllegalStateException when the user is locked.
      */
     @NonNull
@@ -697,6 +705,10 @@
     /**
      * Return all pinned shortcuts from the caller app.
      *
+     * <p>This API is intended to be used for examining what shortcuts are currently published.
+     * Re-publishing returned {@link ShortcutInfo}s via APIs such as
+     * {@link #setDynamicShortcuts(List)} may cause loss of information such as icons.
+     *
      * @throws IllegalStateException when the user is locked.
      */
     @NonNull
diff --git a/core/java/android/content/res/FontResourcesParser.java b/core/java/android/content/res/FontResourcesParser.java
index b21ccf1..042eb87 100644
--- a/core/java/android/content/res/FontResourcesParser.java
+++ b/core/java/android/content/res/FontResourcesParser.java
@@ -18,6 +18,7 @@
 import com.android.internal.R;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.graphics.Typeface;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.Xml;
@@ -36,8 +37,6 @@
  */
 public class FontResourcesParser {
     private static final String TAG = "FontResourcesParser";
-    private static final int NORMAL_WEIGHT = 400;
-    private static final int ITALIC = 1;
 
     // A class represents single entry of font-family in xml file.
     public interface FamilyResourceEntry {}
@@ -78,10 +77,10 @@
     public static final class FontFileResourceEntry {
         private final @NonNull String mFileName;
         private int mWeight;
-        private boolean mItalic;
+        private int mItalic;
         private int mResourceId;
 
-        public FontFileResourceEntry(@NonNull String fileName, int weight, boolean italic) {
+        public FontFileResourceEntry(@NonNull String fileName, int weight, int italic) {
             mFileName = fileName;
             mWeight = weight;
             mItalic = italic;
@@ -95,7 +94,7 @@
             return mWeight;
         }
 
-        public boolean isItalic() {
+        public int getItalic() {
             return mItalic;
         }
     }
@@ -200,8 +199,10 @@
             throws XmlPullParserException, IOException {
         AttributeSet attrs = Xml.asAttributeSet(parser);
         TypedArray array = resources.obtainAttributes(attrs, R.styleable.FontFamilyFont);
-        int weight = array.getInt(R.styleable.FontFamilyFont_fontWeight, NORMAL_WEIGHT);
-        boolean isItalic = ITALIC == array.getInt(R.styleable.FontFamilyFont_fontStyle, 0);
+        int weight = array.getInt(R.styleable.FontFamilyFont_fontWeight,
+                Typeface.RESOLVE_BY_FONT_TABLE);
+        int italic = array.getInt(R.styleable.FontFamilyFont_fontStyle,
+                Typeface.RESOLVE_BY_FONT_TABLE);
         String filename = array.getString(R.styleable.FontFamilyFont_font);
         array.recycle();
         while (parser.next() != XmlPullParser.END_TAG) {
@@ -210,7 +211,7 @@
         if (filename == null) {
             return null;
         }
-        return new FontFileResourceEntry(filename, weight, isItalic);
+        return new FontFileResourceEntry(filename, weight, italic);
     }
 
     private static void skip(XmlPullParser parser) throws XmlPullParserException, IOException {
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 235f24c..37c153f 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -183,8 +183,10 @@
      *   - Wakelock data (wl) gets current and max times.
      * New in version 20:
      *   - Background timers and counters for: Sensor, BluetoothScan, WifiScan, Jobs, Syncs.
+     * New in version 21:
+     *   - Actual (not just apportioned) Wakelock time is also recorded.
      */
-    static final String CHECKIN_VERSION = "20";
+    static final String CHECKIN_VERSION = "21";
 
     /**
      * Old version, we hit 9 and ran out of room, need to remove.
@@ -194,7 +196,7 @@
     private static final long BYTES_PER_KB = 1024;
     private static final long BYTES_PER_MB = 1048576; // 1024^2
     private static final long BYTES_PER_GB = 1073741824; //1024^3
-    
+
     private static final String VERSION_DATA = "vers";
     private static final String UID_DATA = "uid";
     private static final String WAKEUP_ALARM_DATA = "wua";
@@ -205,6 +207,12 @@
     private static final String VIBRATOR_DATA = "vib";
     private static final String FOREGROUND_DATA = "fg";
     private static final String STATE_TIME_DATA = "st";
+    // wl line is:
+    // BATTERY_STATS_CHECKIN_VERSION, uid, which, "wl", name,
+    // full totalTime,    'f', count, current duration, max duration, total duration,
+    // partial totalTime, 'p', count, current duration, max duration, total duration,
+    // window totalTime,  'w', count, current duration, max duration, total duration
+    // [Currently, full and window wakelocks have durations current = max = total = -1]
     private static final String WAKELOCK_DATA = "wl";
     private static final String SYNC_DATA = "sy";
     private static final String JOB_DATA = "jb";
@@ -2659,6 +2667,12 @@
                     sb.append(" max=");
                     sb.append(maxDurationMs);
                 }
+                // Put actual time if it is available and different from totalTimeMillis.
+                final long totalDurMs = timer.getTotalDurationMsLocked(elapsedRealtimeUs/1000);
+                if (totalDurMs > totalTimeMillis) {
+                    sb.append(" actual=");
+                    sb.append(totalDurMs);
+                }
                 if (timer.isRunningLocked()) {
                     final long currentMs = timer.getCurrentDurationMsLocked(elapsedRealtimeUs/1000);
                     if (currentMs >= 0) {
@@ -2742,13 +2756,15 @@
             long elapsedRealtimeUs, String name, int which, String linePrefix) {
         long totalTimeMicros = 0;
         int count = 0;
-        long max = -1;
-        long current = -1;
+        long max = 0;
+        long current = 0;
+        long totalDuration = 0;
         if (timer != null) {
             totalTimeMicros = timer.getTotalTimeLocked(elapsedRealtimeUs, which);
-            count = timer.getCountLocked(which); 
+            count = timer.getCountLocked(which);
             current = timer.getCurrentDurationMsLocked(elapsedRealtimeUs/1000);
             max = timer.getMaxDurationMsLocked(elapsedRealtimeUs/1000);
+            totalDuration = timer.getTotalDurationMsLocked(elapsedRealtimeUs/1000);
         }
         sb.append(linePrefix);
         sb.append((totalTimeMicros + 500) / 1000); // microseconds to milliseconds with rounding
@@ -2759,9 +2775,16 @@
         sb.append(current);
         sb.append(',');
         sb.append(max);
+        // Partial, full, and window wakelocks are pooled, so totalDuration is meaningful (albeit
+        // not always tracked). Kernel wakelocks (which have name == null) have no notion of
+        // totalDuration independent of totalTimeMicros (since they are not pooled).
+        if (name != null) {
+            sb.append(',');
+            sb.append(totalDuration);
+        }
         return ",";
     }
-    
+
     private static final void dumpLineHeader(PrintWriter pw, int uid, String category,
                                              String type) {
         pw.print(BATTERY_STATS_CHECKIN_VERSION);
diff --git a/core/java/android/os/VibrationEffect.java b/core/java/android/os/VibrationEffect.java
index eceaa31..6aa601a 100644
--- a/core/java/android/os/VibrationEffect.java
+++ b/core/java/android/os/VibrationEffect.java
@@ -189,10 +189,11 @@
             if (mAmplitude < -1 || mAmplitude == 0 || mAmplitude > 255) {
                 throw new IllegalArgumentException(
                         "amplitude must either be DEFAULT_AMPLITUDE, " +
-                        "or between 1 and 255 inclusive");
+                        "or between 1 and 255 inclusive (amplitude=" + mAmplitude + ")");
             }
             if (mTiming <= 0) {
-                throw new IllegalArgumentException("timing must be positive");
+                throw new IllegalArgumentException(
+                        "timing must be positive (timing=" + mTiming + ")");
             }
         }
 
@@ -274,24 +275,31 @@
         public void validate() {
             if (mTimings.length != mAmplitudes.length) {
                 throw new IllegalArgumentException(
-                        "timing and amplitude arrays must be of equal length");
+                        "timing and amplitude arrays must be of equal length" +
+                        " (timings.length=" + mTimings.length +
+                        ", amplitudes.length=" + mAmplitudes.length + ")");
             }
             if (!hasNonZeroEntry(mTimings)) {
-                throw new IllegalArgumentException("at least one timing must be non-zero");
+                throw new IllegalArgumentException("at least one timing must be non-zero" +
+                        " (timings=" + Arrays.toString(mTimings) + ")");
             }
             for (long timing : mTimings) {
                 if (timing < 0) {
-                    throw new IllegalArgumentException("timings must all be >= 0");
+                    throw new IllegalArgumentException("timings must all be >= 0" +
+                            " (timings=" + Arrays.toString(mTimings) + ")");
                 }
             }
             for (int amplitude : mAmplitudes) {
                 if (amplitude < -1 || amplitude > 255) {
                     throw new IllegalArgumentException(
-                            "amplitudes must all be DEFAULT_AMPLITUDE or between 0 and 255");
+                            "amplitudes must all be DEFAULT_AMPLITUDE or between 0 and 255" +
+                            " (amplitudes=" + Arrays.toString(mAmplitudes) + ")");
                 }
             }
             if (mRepeat < -1 || mRepeat >= mTimings.length) {
-                throw new IllegalArgumentException("repeat index must be >= -1");
+                throw new IllegalArgumentException(
+                        "repeat index must be within the bounds of the timings array" +
+                        " (timings.length=" + mTimings.length + ", index=" + mRepeat +")");
             }
         }
 
@@ -375,7 +383,8 @@
         @Override
         public void validate() {
             if (mEffectId != EFFECT_CLICK) {
-                throw new IllegalArgumentException("Unknown prebaked effect type");
+                throw new IllegalArgumentException(
+                        "Unknown prebaked effect type (value=" + mEffectId + ")");
             }
         }
 
diff --git a/core/java/android/os/Vibrator.java b/core/java/android/os/Vibrator.java
index 1e55c78..2f0eeca 100644
--- a/core/java/android/os/Vibrator.java
+++ b/core/java/android/os/Vibrator.java
@@ -157,6 +157,8 @@
         // This call needs to continue throwing ArrayIndexOutOfBoundsException but ignore all other
         // exceptions for compatibility purposes
         if (repeat < -1 || repeat >= pattern.length) {
+            Log.e(TAG, "vibrate called with repeat index out of bounds" +
+                    " (pattern.length=" + pattern.length + ", index=" + repeat + ")");
             throw new ArrayIndexOutOfBoundsException();
         }
 
diff --git a/core/java/android/os/VintfObject.java b/core/java/android/os/VintfObject.java
index 8302ece..65b33e5 100644
--- a/core/java/android/os/VintfObject.java
+++ b/core/java/android/os/VintfObject.java
@@ -16,14 +16,17 @@
 
 package android.os;
 
-import java.util.ArrayList;
+import java.util.Map;
 
 import android.util.Log;
 
-/** @hide */
+/**
+ * Java API for libvintf.
+ * @hide
+ */
 public class VintfObject {
 
-    private static final String LOG_TAG = "VintfObject";
+    /// ---------- OTA
 
     /**
      * Slurps all device information (both manifests and both matrices)
@@ -45,4 +48,26 @@
      */
     public static native int verify(String[] packageInfo);
 
+    /// ---------- CTS Device Info
+
+    /**
+     * @return a list of HAL names and versions that is supported by this
+     * device as stated in device and framework manifests. For example,
+     * ["android.hidl.manager@1.0", "android.hardware.camera.device@1.0",
+     *  "android.hardware.camera.device@3.2"]. There are no duplicates.
+     */
+    public static native String[] getHalNamesAndVersions();
+
+    /**
+     * @return the BOARD_SEPOLICY_VERS build flag available in device manifest.
+     */
+    public static native String getSepolicyVersion();
+
+    /**
+     * @return a list of VNDK snapshots supported by the framework, as
+     * specified in framework manifest. For example,
+     * [("25.0.5", ["libjpeg.so", "libbase.so"]),
+     *  ("25.1.3", ["libjpeg.so", "libbase.so"])]
+     */
+    public static native Map<String, String[]> getVndkSnapshots();
 }
diff --git a/core/java/android/service/autofill/AutofillService.java b/core/java/android/service/autofill/AutofillService.java
index 88d17ef..5fd9458 100644
--- a/core/java/android/service/autofill/AutofillService.java
+++ b/core/java/android/service/autofill/AutofillService.java
@@ -15,6 +15,7 @@
  */
 package android.service.autofill;
 
+import android.annotation.CallSuper;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.os.RemoteException;
@@ -156,6 +157,7 @@
      *
      * <strong>NOTE: </strong>if overridden, it must call {@code super.onCreate()}.
      */
+    @CallSuper
     @Override
     public void onCreate() {
         super.onCreate();
diff --git a/core/java/android/service/vr/IVrManager.aidl b/core/java/android/service/vr/IVrManager.aidl
index fc8afe9..9b37a65 100644
--- a/core/java/android/service/vr/IVrManager.aidl
+++ b/core/java/android/service/vr/IVrManager.aidl
@@ -86,17 +86,5 @@
      * currently, else return the display id of the virtual display
      */
     int getVr2dDisplayId();
-
-    /**
-     * Initiate connection for system controller data.
-     *
-     * @param fd Controller data file descriptor.
-     */
-    void connectController(in FileDescriptor fd);
-
-    /**
-     * Sever connection for system controller data.
-     */
-    void disconnectController();
 }
 
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index 91f43d6..585f882 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -1520,6 +1520,18 @@
     /**
      * Returns a CharSequence concatenating the specified CharSequences,
      * retaining their spans if any.
+     *
+     * If there are no parameters, an empty string will be returned.
+     *
+     * If the number of parameters is exactly one, that parameter is returned as output, even if it
+     * is null.
+     *
+     * If the number of parameters is at least two, any null CharSequence among the parameters is
+     * treated as if it was the string <code>"null"</code>.
+     *
+     * If there are paragraph spans in the source CharSequences that satisfy paragraph boundary
+     * requirements in the sources but would no longer satisfy them in the concatenated
+     * CharSequence, they may get extended in the resulting CharSequence or not retained.
      */
     public static CharSequence concat(CharSequence... text) {
         if (text.length == 0) {
@@ -1531,35 +1543,29 @@
         }
 
         boolean spanned = false;
-        for (int i = 0; i < text.length; i++) {
-            if (text[i] instanceof Spanned) {
+        for (CharSequence piece : text) {
+            if (piece instanceof Spanned) {
                 spanned = true;
                 break;
             }
         }
 
-        StringBuilder sb = new StringBuilder();
-        for (int i = 0; i < text.length; i++) {
-            sb.append(text[i]);
-        }
-
-        if (!spanned) {
+        if (spanned) {
+            final SpannableStringBuilder ssb = new SpannableStringBuilder();
+            for (CharSequence piece : text) {
+                // If a piece is null, we append the string "null" for compatibility with the
+                // behavior of StringBuilder and the behavior of the concat() method in earlier
+                // versions of Android.
+                ssb.append(piece == null ? "null" : piece);
+            }
+            return new SpannedString(ssb);
+        } else {
+            final StringBuilder sb = new StringBuilder();
+            for (CharSequence piece : text) {
+                sb.append(piece);
+            }
             return sb.toString();
         }
-
-        SpannableString ss = new SpannableString(sb);
-        int off = 0;
-        for (int i = 0; i < text.length; i++) {
-            int len = text[i].length();
-
-            if (text[i] instanceof Spanned) {
-                copySpansFrom((Spanned) text[i], 0, len, Object.class, ss, off);
-            }
-
-            off += len;
-        }
-
-        return new SpannedString(ss);
     }
 
     /**
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 39f1170..c250ca0 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -7237,44 +7237,53 @@
 
         RectF position = mAttachInfo.mTmpTransformRect;
         position.set(0, 0, mRight - mLeft, mBottom - mTop);
+        mapRectFromViewToScreenCoords(position, clipToParent);
+        outRect.set(Math.round(position.left), Math.round(position.top),
+                Math.round(position.right), Math.round(position.bottom));
+    }
 
+    /**
+     * Map a rectangle from view-relative coordinates to screen-relative coordinates
+     *
+     * @param rect The rectangle to be mapped
+     * @param clipToParent Whether to clip child bounds to the parent ones.
+     * @hide
+     */
+    public void mapRectFromViewToScreenCoords(RectF rect, boolean clipToParent) {
         if (!hasIdentityMatrix()) {
-            getMatrix().mapRect(position);
+            getMatrix().mapRect(rect);
         }
 
-        position.offset(mLeft, mTop);
+        rect.offset(mLeft, mTop);
 
         ViewParent parent = mParent;
         while (parent instanceof View) {
             View parentView = (View) parent;
 
-            position.offset(-parentView.mScrollX, -parentView.mScrollY);
+            rect.offset(-parentView.mScrollX, -parentView.mScrollY);
 
             if (clipToParent) {
-                position.left = Math.max(position.left, 0);
-                position.top = Math.max(position.top, 0);
-                position.right = Math.min(position.right, parentView.getWidth());
-                position.bottom = Math.min(position.bottom, parentView.getHeight());
+                rect.left = Math.max(rect.left, 0);
+                rect.top = Math.max(rect.top, 0);
+                rect.right = Math.min(rect.right, parentView.getWidth());
+                rect.bottom = Math.min(rect.bottom, parentView.getHeight());
             }
 
             if (!parentView.hasIdentityMatrix()) {
-                parentView.getMatrix().mapRect(position);
+                parentView.getMatrix().mapRect(rect);
             }
 
-            position.offset(parentView.mLeft, parentView.mTop);
+            rect.offset(parentView.mLeft, parentView.mTop);
 
             parent = parentView.mParent;
         }
 
         if (parent instanceof ViewRootImpl) {
             ViewRootImpl viewRootImpl = (ViewRootImpl) parent;
-            position.offset(0, -viewRootImpl.mCurScrollY);
+            rect.offset(0, -viewRootImpl.mCurScrollY);
         }
 
-        position.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop);
-
-        outRect.set(Math.round(position.left), Math.round(position.top),
-                Math.round(position.right), Math.round(position.bottom));
+        rect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop);
     }
 
     /**
@@ -7351,10 +7360,12 @@
         }
 
         structure.setDimens(mLeft, mTop, mScrollX, mScrollY, mRight - mLeft, mBottom - mTop);
-        if (!hasIdentityMatrix()) {
-            structure.setTransformation(getMatrix());
+        if (!forAutofill) {
+            if (!hasIdentityMatrix()) {
+                structure.setTransformation(getMatrix());
+            }
+            structure.setElevation(getZ());
         }
-        structure.setElevation(getZ());
         structure.setVisibility(getVisibility());
         structure.setEnabled(isEnabled());
         if (isClickable()) {
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index a081f0b..7362c70 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -102,7 +102,9 @@
                         string, selectionStartIndex, selectionEndIndex);
                 final int start = startEnd[0];
                 final int end = startEnd[1];
-                if (start >= 0 && end <= string.length() && start <= end) {
+                if (start <= end
+                        && start >= 0 && end <= string.length()
+                        && start <= selectionStartIndex && end >= selectionEndIndex) {
                     final TextSelection.Builder tsBuilder = new TextSelection.Builder(start, end);
                     final SmartSelection.ClassificationResult[] results =
                             smartSelection.classifyText(
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index eaf1115..bf44f62 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -10136,7 +10136,11 @@
             if (lineCount <= 1) {
                 // Simple case: this is a single line.
                 final CharSequence text = getText();
-                structure.setText(text, getSelectionStart(), getSelectionEnd());
+                if (forAutofill) {
+                    structure.setText(text);
+                } else {
+                    structure.setText(text, getSelectionStart(), getSelectionEnd());
+                }
             } else {
                 // Complex case: multi-line, could be scrolled or within a scroll container
                 // so some lines are not visible.
@@ -10172,9 +10176,11 @@
                 if (expandedBottomLine >= lineCount) {
                     expandedBottomLine = lineCount - 1;
                 }
+
                 // Convert lines into character offsets.
                 int expandedTopChar = layout.getLineStart(expandedTopLine);
                 int expandedBottomChar = layout.getLineEnd(expandedBottomLine);
+
                 // Take into account selection -- if there is a selection, we need to expand
                 // the text we are returning to include that selection.
                 final int selStart = getSelectionStart();
@@ -10187,48 +10193,57 @@
                         expandedBottomChar = selEnd;
                     }
                 }
+
                 // Get the text and trim it to the range we are reporting.
                 CharSequence text = getText();
                 if (expandedTopChar > 0 || expandedBottomChar < text.length()) {
                     text = text.subSequence(expandedTopChar, expandedBottomChar);
                 }
-                structure.setText(text, selStart - expandedTopChar, selEnd - expandedTopChar);
-                final int[] lineOffsets = new int[bottomLine - topLine + 1];
-                final int[] lineBaselines = new int[bottomLine - topLine + 1];
-                final int baselineOffset = getBaselineOffset();
-                for (int i = topLine; i <= bottomLine; i++) {
-                    lineOffsets[i - topLine] = layout.getLineStart(i);
-                    lineBaselines[i - topLine] = layout.getLineBaseline(i) + baselineOffset;
+
+                if (forAutofill) {
+                    structure.setText(text);
+                } else {
+                    structure.setText(text, selStart - expandedTopChar, selEnd - expandedTopChar);
+
+                    final int[] lineOffsets = new int[bottomLine - topLine + 1];
+                    final int[] lineBaselines = new int[bottomLine - topLine + 1];
+                    final int baselineOffset = getBaselineOffset();
+                    for (int i = topLine; i <= bottomLine; i++) {
+                        lineOffsets[i - topLine] = layout.getLineStart(i);
+                        lineBaselines[i - topLine] = layout.getLineBaseline(i) + baselineOffset;
+                    }
+                    structure.setTextLines(lineOffsets, lineBaselines);
                 }
-                structure.setTextLines(lineOffsets, lineBaselines);
             }
 
-            // Extract style information that applies to the TextView as a whole.
-            int style = 0;
-            int typefaceStyle = getTypefaceStyle();
-            if ((typefaceStyle & Typeface.BOLD) != 0) {
-                style |= AssistStructure.ViewNode.TEXT_STYLE_BOLD;
-            }
-            if ((typefaceStyle & Typeface.ITALIC) != 0) {
-                style |= AssistStructure.ViewNode.TEXT_STYLE_ITALIC;
-            }
+            if (!forAutofill) {
+                // Extract style information that applies to the TextView as a whole.
+                int style = 0;
+                int typefaceStyle = getTypefaceStyle();
+                if ((typefaceStyle & Typeface.BOLD) != 0) {
+                    style |= AssistStructure.ViewNode.TEXT_STYLE_BOLD;
+                }
+                if ((typefaceStyle & Typeface.ITALIC) != 0) {
+                    style |= AssistStructure.ViewNode.TEXT_STYLE_ITALIC;
+                }
 
-            // Global styles can also be set via TextView.setPaintFlags().
-            int paintFlags = mTextPaint.getFlags();
-            if ((paintFlags & Paint.FAKE_BOLD_TEXT_FLAG) != 0) {
-                style |= AssistStructure.ViewNode.TEXT_STYLE_BOLD;
-            }
-            if ((paintFlags & Paint.UNDERLINE_TEXT_FLAG) != 0) {
-                style |= AssistStructure.ViewNode.TEXT_STYLE_UNDERLINE;
-            }
-            if ((paintFlags & Paint.STRIKE_THRU_TEXT_FLAG) != 0) {
-                style |= AssistStructure.ViewNode.TEXT_STYLE_STRIKE_THRU;
-            }
+                // Global styles can also be set via TextView.setPaintFlags().
+                int paintFlags = mTextPaint.getFlags();
+                if ((paintFlags & Paint.FAKE_BOLD_TEXT_FLAG) != 0) {
+                    style |= AssistStructure.ViewNode.TEXT_STYLE_BOLD;
+                }
+                if ((paintFlags & Paint.UNDERLINE_TEXT_FLAG) != 0) {
+                    style |= AssistStructure.ViewNode.TEXT_STYLE_UNDERLINE;
+                }
+                if ((paintFlags & Paint.STRIKE_THRU_TEXT_FLAG) != 0) {
+                    style |= AssistStructure.ViewNode.TEXT_STYLE_STRIKE_THRU;
+                }
 
-            // TextView does not have its own text background color. A background is either part
-            // of the View (and can be any drawable) or a BackgroundColorSpan inside the text.
-            structure.setTextStyle(getTextSize(), getCurrentTextColor(),
-                    AssistStructure.ViewNode.TEXT_COLOR_UNDEFINED /* bgColor */, style);
+                // TextView does not have its own text background color. A background is either part
+                // of the View (and can be any drawable) or a BackgroundColorSpan inside the text.
+                structure.setTextStyle(getTextSize(), getCurrentTextColor(),
+                        AssistStructure.ViewNode.TEXT_COLOR_UNDEFINED /* bgColor */, style);
+            }
         }
         structure.setHint(getHint());
         structure.setInputType(getInputType());
@@ -10385,14 +10400,13 @@
                     positionInfoStartIndex + positionInfoLength,
                     viewportToContentHorizontalOffset(), viewportToContentVerticalOffset());
             CursorAnchorInfo cursorAnchorInfo = builder.setMatrix(null).build();
-            int[] locationOnScreen = getLocationOnScreen();
             for (int i = 0; i < positionInfoLength; i++) {
                 int flags = cursorAnchorInfo.getCharacterBoundsFlags(positionInfoStartIndex + i);
                 if ((flags & FLAG_HAS_VISIBLE_REGION) == FLAG_HAS_VISIBLE_REGION) {
                     RectF bounds = cursorAnchorInfo
                             .getCharacterBounds(positionInfoStartIndex + i);
                     if (bounds != null) {
-                        bounds.offset(locationOnScreen[0], locationOnScreen[1]);
+                        mapRectFromViewToScreenCoords(bounds, true);
                         boundingRects[i] = bounds;
                     }
                 }
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index 73886a7..91bc681 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -583,4 +583,8 @@
         }
         return size - leftIdx;
     }
+
+    public static @NonNull String[] defeatNullable(@Nullable String[] val) {
+        return (val != null) ? val : EmptyArray.STRING;
+    }
 }
diff --git a/core/jni/android_os_VintfObject.cpp b/core/jni/android_os_VintfObject.cpp
index 033f2df..fa9379e 100644
--- a/core/jni/android_os_VintfObject.cpp
+++ b/core/jni/android_os_VintfObject.cpp
@@ -23,23 +23,34 @@
 
 #include <JNIHelp.h>
 #include <vintf/VintfObject.h>
+#include <vintf/parse_string.h>
 #include <vintf/parse_xml.h>
 
 #include "core_jni_helpers.h"
 
 static jclass gString;
+static jclass gHashMapClazz;
+static jmethodID gHashMapInit;
+static jmethodID gHashMapPut;
 
 namespace android {
 
+using vintf::HalManifest;
+using vintf::SchemaType;
 using vintf::VintfObject;
+using vintf::XmlConverter;
+using vintf::Vndk;
 using vintf::gHalManifestConverter;
 using vintf::gCompatibilityMatrixConverter;
-using vintf::XmlConverter;
+using vintf::to_string;
 
-static inline jobjectArray toJavaStringArray(JNIEnv* env, const std::vector<std::string>& v) {
+template<typename V>
+static inline jobjectArray toJavaStringArray(JNIEnv* env, const V& v) {
+    size_t i;
+    typename V::const_iterator it;
     jobjectArray ret = env->NewObjectArray(v.size(), gString, NULL /* init element */);
-    for (size_t i = 0; i < v.size(); ++i) {
-        env->SetObjectArrayElement(ret, i, env->NewStringUTF(v[i].c_str()));
+    for (i = 0, it = v.begin(); it != v.end(); ++i, ++it) {
+        env->SetObjectArrayElement(ret, i, env->NewStringUTF(it->c_str()));
     }
     return ret;
 }
@@ -55,7 +66,18 @@
     }
 }
 
-static jobjectArray android_os_VintfObject_report(JNIEnv* env, jclass clazz)
+static void tryAddHalNamesAndVersions(const HalManifest *manifest,
+        const std::string& description,
+        std::set<std::string> *output) {
+    if (manifest == nullptr) {
+        LOG(WARNING) << __FUNCTION__ << "Cannot get " << description;
+    } else {
+        auto names = manifest->getHalNamesAndVersions();
+        output->insert(names.begin(), names.end());
+    }
+}
+
+static jobjectArray android_os_VintfObject_report(JNIEnv* env, jclass)
 {
     std::vector<std::string> cStrings;
 
@@ -71,7 +93,7 @@
     return toJavaStringArray(env, cStrings);
 }
 
-static jint android_os_VintfObject_verify(JNIEnv *env, jclass clazz, jobjectArray packageInfo) {
+static jint android_os_VintfObject_verify(JNIEnv* env, jclass, jobjectArray packageInfo) {
     size_t count = env->GetArrayLength(packageInfo);
     std::vector<std::string> cPackageInfo{count};
     for (size_t i = 0; i < count; ++i) {
@@ -84,20 +106,60 @@
     return status;
 }
 
+static jobjectArray android_os_VintfObject_getHalNamesAndVersions(JNIEnv* env, jclass) {
+    std::set<std::string> halNames;
+    tryAddHalNamesAndVersions(VintfObject::GetDeviceHalManifest(),
+            "device manifest", &halNames);
+    tryAddHalNamesAndVersions(VintfObject::GetFrameworkHalManifest(),
+            "framework manifest", &halNames);
+    return toJavaStringArray(env, halNames);
+}
+
+static jstring android_os_VintfObject_getSepolicyVersion(JNIEnv* env, jclass) {
+    const HalManifest *manifest = VintfObject::GetDeviceHalManifest();
+    if (manifest == nullptr || manifest->type() != SchemaType::DEVICE) {
+        LOG(WARNING) << __FUNCTION__ << "Cannot get device manifest";
+        return nullptr;
+    }
+    std::string cString = to_string(manifest->sepolicyVersion());
+    return env->NewStringUTF(cString.c_str());
+}
+
+static jobject android_os_VintfObject_getVndkSnapshots(JNIEnv* env, jclass) {
+    const HalManifest *manifest = VintfObject::GetFrameworkHalManifest();
+    if (manifest == nullptr || manifest->type() != SchemaType::FRAMEWORK) {
+        LOG(WARNING) << __FUNCTION__ << "Cannot get framework manifest";
+        return nullptr;
+    }
+    jobject jMap = env->NewObject(gHashMapClazz, gHashMapInit);
+    for (const Vndk &vndk : manifest->vndks()) {
+        std::string key = to_string(vndk.versionRange());
+        env->CallObjectMethod(jMap, gHashMapPut,
+                env->NewStringUTF(key.c_str()), toJavaStringArray(env, vndk.libraries()));
+    }
+    return jMap;
+}
+
 // ----------------------------------------------------------------------------
 
 static const JNINativeMethod gVintfObjectMethods[] = {
     {"report", "()[Ljava/lang/String;", (void*)android_os_VintfObject_report},
     {"verify", "([Ljava/lang/String;)I", (void*)android_os_VintfObject_verify},
+    {"getHalNamesAndVersions", "()[Ljava/lang/String;", (void*)android_os_VintfObject_getHalNamesAndVersions},
+    {"getSepolicyVersion", "()Ljava/lang/String;", (void*)android_os_VintfObject_getSepolicyVersion},
+    {"getVndkSnapshots", "()Ljava/util/Map;", (void*)android_os_VintfObject_getVndkSnapshots},
 };
 
-
 const char* const kVintfObjectPathName = "android/os/VintfObject";
 
 int register_android_os_VintfObject(JNIEnv* env)
 {
 
     gString = MakeGlobalRefOrDie(env, FindClassOrDie(env, "java/lang/String"));
+    gHashMapClazz = MakeGlobalRefOrDie(env, FindClassOrDie(env, "java/util/HashMap"));
+    gHashMapInit = GetMethodIDOrDie(env, gHashMapClazz, "<init>", "()V");
+    gHashMapPut = GetMethodIDOrDie(env, gHashMapClazz,
+            "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
 
     return RegisterMethodsOrDie(env, kVintfObjectPathName, gVintfObjectMethods,
             NELEM(gVintfObjectMethods));
diff --git a/core/res/res/drawable/sym_def_app_icon.xml b/core/res/res/drawable/sym_def_app_icon.xml
index 0fdb0dd..9c02402 100644
--- a/core/res/res/drawable/sym_def_app_icon.xml
+++ b/core/res/res/drawable/sym_def_app_icon.xml
@@ -2,10 +2,7 @@
 <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
     <background android:drawable="@android:color/white" />
     <foreground>
-        <inset android:insetLeft="27.7%"
-            android:insetTop="27.7%"
-            android:insetRight="27.7%"
-            android:insetBottom="27.7%">
+        <inset android:inset="27.7%">
             <bitmap android:src="@mipmap/sym_def_app_icon"/>
         </inset>
     </foreground>
diff --git a/core/tests/coretests/src/android/content/res/FontResourcesParserTest.java b/core/tests/coretests/src/android/content/res/FontResourcesParserTest.java
index 5e426e8..9c904d1 100644
--- a/core/tests/coretests/src/android/content/res/FontResourcesParserTest.java
+++ b/core/tests/coretests/src/android/content/res/FontResourcesParserTest.java
@@ -68,19 +68,19 @@
         assertEquals(4, fileEntries.length);
         FontFileResourceEntry font1 = fileEntries[0];
         assertEquals(400, font1.getWeight());
-        assertEquals(false, font1.isItalic());
+        assertEquals(0, font1.getItalic());
         assertEquals("res/font/samplefont.ttf", font1.getFileName());
         FontFileResourceEntry font2 = fileEntries[1];
         assertEquals(400, font2.getWeight());
-        assertEquals(true, font2.isItalic());
+        assertEquals(1, font2.getItalic());
         assertEquals("res/font/samplefont2.ttf", font2.getFileName());
         FontFileResourceEntry font3 = fileEntries[2];
         assertEquals(800, font3.getWeight());
-        assertEquals(false, font3.isItalic());
+        assertEquals(0, font3.getItalic());
         assertEquals("res/font/samplefont3.ttf", font3.getFileName());
         FontFileResourceEntry font4 = fileEntries[3];
         assertEquals(800, font4.getWeight());
-        assertEquals(true, font4.isItalic());
+        assertEquals(1, font4.getItalic());
         assertEquals("res/font/samplefont4.ttf", font4.getFileName());
     }
 
diff --git a/core/tests/coretests/src/android/text/method/BackspaceTest.java b/core/tests/coretests/src/android/text/method/BackspaceTest.java
index 6e41831..8b5cc60 100644
--- a/core/tests/coretests/src/android/text/method/BackspaceTest.java
+++ b/core/tests/coretests/src/android/text/method/BackspaceTest.java
@@ -16,10 +16,13 @@
 
 package android.text.method;
 
+import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.text.InputType;
+import android.util.KeyUtils;
 import android.view.KeyEvent;
+import android.widget.EditText;
 import android.widget.TextView.BufferType;
 import org.junit.Before;
 import org.junit.Test;
@@ -33,13 +36,21 @@
  */
 @SmallTest
 @RunWith(AndroidJUnit4.class)
-public class BackspaceTest extends KeyListenerTestCase {
+public class BackspaceTest {
+    private EditText mTextView;
+
     private static final BaseKeyListener mKeyListener = new BaseKeyListener() {
         public int getInputType() {
             return InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL;
         }
     };
 
+    @Before
+    public void setup() {
+        mTextView = new EditText(InstrumentationRegistry.getInstrumentation().getContext());
+    }
+
+
     // Sync the state to the TextView and call onKeyDown with KEYCODE_DEL key event.
     // Then update the state to the result of TextView.
     private void backspace(final EditorState state, int modifiers) {
@@ -47,7 +58,8 @@
         mTextView.setKeyListener(mKeyListener);
         mTextView.setSelection(state.mSelectionStart, state.mSelectionEnd);
 
-        final KeyEvent keyEvent = getKey(KeyEvent.KEYCODE_DEL, modifiers);
+        final KeyEvent keyEvent = KeyUtils.generateKeyEvent(
+            KeyEvent.KEYCODE_DEL, KeyEvent.ACTION_DOWN, modifiers);
         mTextView.onKeyDown(keyEvent.getKeyCode(), keyEvent);
 
         state.mText = mTextView.getText();
diff --git a/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java b/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java
index 6914e21..c3a5f80 100644
--- a/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java
+++ b/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java
@@ -16,10 +16,13 @@
 
 package android.text.method;
 
+import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.text.InputType;
+import android.util.KeyUtils;
 import android.view.KeyEvent;
+import android.widget.EditText;
 import android.widget.TextView.BufferType;
 
 import org.junit.Before;
@@ -34,13 +37,20 @@
  */
 @SmallTest
 @RunWith(AndroidJUnit4.class)
-public class ForwardDeleteTest extends KeyListenerTestCase {
+public class ForwardDeleteTest {
+    private EditText mTextView;
+
     private static final BaseKeyListener mKeyListener = new BaseKeyListener() {
         public int getInputType() {
             return InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL;
         }
     };
 
+    @Before
+    public void setup() {
+        mTextView = new EditText(InstrumentationRegistry.getInstrumentation().getContext());
+    }
+
     // Sync the state to the TextView and call onKeyDown with KEYCODE_FORWARD_DEL key event.
     // Then update the state to the result of TextView.
     private void forwardDelete(final EditorState state, int modifiers) {
@@ -48,7 +58,8 @@
         mTextView.setKeyListener(mKeyListener);
         mTextView.setSelection(state.mSelectionStart, state.mSelectionEnd);
 
-        final KeyEvent keyEvent = getKey(KeyEvent.KEYCODE_FORWARD_DEL, modifiers);
+        final KeyEvent keyEvent = KeyUtils.generateKeyEvent(
+            KeyEvent.KEYCODE_FORWARD_DEL, KeyEvent.ACTION_DOWN, modifiers);
         mTextView.onKeyDown(keyEvent.getKeyCode(), keyEvent);
 
         state.mText = mTextView.getText();
diff --git a/core/tests/coretests/src/android/text/method/KeyListenerTestCase.java b/core/tests/coretests/src/android/text/method/KeyListenerTestCase.java
deleted file mode 100644
index 99a0091..0000000
--- a/core/tests/coretests/src/android/text/method/KeyListenerTestCase.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.text.method;
-
-import android.app.Instrumentation;
-import android.support.test.InstrumentationRegistry;
-import android.view.KeyEvent;
-import android.widget.EditText;
-
-public abstract class KeyListenerTestCase {
-    protected Instrumentation mInstrumentation;
-    protected EditText mTextView;
-
-    public KeyListenerTestCase() {
-    }
-
-    protected void setup() {
-        mInstrumentation = InstrumentationRegistry.getInstrumentation();
-        mTextView = new EditText(mInstrumentation.getContext());
-    }
-
-    protected static KeyEvent getKey(int keycode, int metaState) {
-        long currentTime = System.currentTimeMillis();
-        return new KeyEvent(currentTime, currentTime, KeyEvent.ACTION_DOWN, keycode,
-                0 /* repeat */, metaState);
-    }
-}
diff --git a/core/tests/coretests/src/android/util/KeyUtils.java b/core/tests/coretests/src/android/util/KeyUtils.java
index b58fda3..593f727 100644
--- a/core/tests/coretests/src/android/util/KeyUtils.java
+++ b/core/tests/coretests/src/android/util/KeyUtils.java
@@ -85,4 +85,19 @@
         }
         inst.sendKeySync(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER));
     }
+
+    /**
+     * Generates a {@link KeyEvent}.
+     *
+     * @param keycode The integer keycode for the event to be generated.
+     * @param keyEventAction The integer {@link KeyEvent} action code.
+     * @param metaState Flags indicating which meta keys are currently pressed.
+     *
+     * @return a new {@link KeyEvent} for current time.
+     */
+    public static KeyEvent generateKeyEvent(int keycode, int keyEventAction, int metaState) {
+        long currentTime = System.currentTimeMillis();
+        return new KeyEvent(currentTime, currentTime, keyEventAction, keycode,
+            0 /* repeat */, metaState);
+    }
 }
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
index 742fd60..7b7031b 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
@@ -40,6 +40,7 @@
 public class TextClassificationManagerTest {
 
     private static final LocaleList LOCALES = LocaleList.forLanguageTags("en");
+    private static final String NO_TYPE = null;
 
     private TextClassificationManager mTcm;
     private TextClassifier mClassifier;
@@ -102,6 +103,19 @@
     }
 
     @Test
+    public void testSmartSelection_withEmoji() {
+        if (isTextClassifierDisabled()) return;
+
+        String text = "\uD83D\uDE02 Hello.";
+        String selected = "Hello";
+        int startIndex = text.indexOf(selected);
+        int endIndex = startIndex + selected.length();
+
+        assertThat(mClassifier.suggestSelection(text, startIndex, endIndex, LOCALES),
+                isTextSelection(startIndex, endIndex, NO_TYPE));
+    }
+
+    @Test
     public void testClassifyText() {
         if (isTextClassifierDisabled()) return;
 
@@ -172,12 +186,17 @@
                     TextSelection selection = (TextSelection) o;
                     return startIndex == selection.getSelectionStartIndex()
                             && endIndex == selection.getSelectionEndIndex()
-                            && selection.getEntityCount() > 0
-                            && type.equals(selection.getEntity(0));
+                            && typeMatches(selection, type);
                 }
                 return false;
             }
 
+            private boolean typeMatches(TextSelection selection, String type) {
+                return type == null
+                        || (selection.getEntityCount() > 0
+                                && type.trim().equalsIgnoreCase(selection.getEntity(0)));
+            }
+
             @Override
             public void describeTo(Description description) {
                 description.appendValue(
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index abdab39..8a36120 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -23,6 +23,7 @@
 import android.annotation.Size;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.StrictMode;
 import android.os.Trace;
 import android.util.DisplayMetrics;
 import android.util.Log;
@@ -600,6 +601,13 @@
         src.position(position);
     }
 
+    private void noteHardwareBitmapSlowCall() {
+        if (getConfig() == Config.HARDWARE) {
+            StrictMode.noteSlowCall("Warning: attempt to read pixels from hardware "
+                    + "bitmap, which is very slow operation");
+        }
+    }
+
     /**
      * Tries to make a new bitmap based on the dimensions of this bitmap,
      * setting the new bitmap's config to the one specified, and then copying
@@ -618,6 +626,7 @@
         if (config == Config.HARDWARE && isMutable) {
             throw new IllegalArgumentException("Hardware bitmaps are always immutable");
         }
+        noteHardwareBitmapSlowCall();
         Bitmap b = nativeCopy(mNativePtr, config.nativeInt, isMutable);
         if (b != null) {
             b.setPremultiplied(mRequestPremultiplied);
@@ -635,6 +644,7 @@
      */
     public Bitmap createAshmemBitmap() {
         checkRecycled("Can't copy a recycled bitmap");
+        noteHardwareBitmapSlowCall();
         Bitmap b = nativeCopyAshmem(mNativePtr);
         if (b != null) {
             b.setPremultiplied(mRequestPremultiplied);
@@ -652,6 +662,7 @@
      */
     public Bitmap createAshmemBitmap(Config config) {
         checkRecycled("Can't copy a recycled bitmap");
+        noteHardwareBitmapSlowCall();
         Bitmap b = nativeCopyAshmemConfig(mNativePtr, config.nativeInt);
         if (b != null) {
             b.setPremultiplied(mRequestPremultiplied);
@@ -772,6 +783,7 @@
 
         boolean isHardware = source.getConfig() == Config.HARDWARE;
         if (isHardware) {
+            source.noteHardwareBitmapSlowCall();
             source = nativeCopyPreserveInternalConfig(source.mNativePtr);
         }
 
@@ -1218,6 +1230,7 @@
         if (quality < 0 || quality > 100) {
             throw new IllegalArgumentException("quality must be 0..100");
         }
+        StrictMode.noteSlowCall("Compression of a bitmap is slow");
         Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "Bitmap.compress");
         boolean result = nativeCompress(mNativePtr, format.nativeInt,
                 quality, stream, new byte[WORKING_COMPRESS_STORAGE]);
@@ -1792,6 +1805,7 @@
      */
     public void writeToParcel(Parcel p, int flags) {
         checkRecycled("Can't parcel a recycled bitmap");
+        noteHardwareBitmapSlowCall();
         if (!nativeWriteToParcel(mNativePtr, mIsMutable, mDensity, p)) {
             throw new RuntimeException("native writeToParcel failed");
         }
@@ -1838,6 +1852,7 @@
     public Bitmap extractAlpha(Paint paint, int[] offsetXY) {
         checkRecycled("Can't extractAlpha on a recycled bitmap");
         long nativePaint = paint != null ? paint.getNativeInstance() : 0;
+        noteHardwareBitmapSlowCall();
         Bitmap bm = nativeExtractAlpha(mNativePtr, nativePaint, offsetXY);
         if (bm == null) {
             throw new RuntimeException("Failed to extractAlpha on Bitmap");
@@ -1853,6 +1868,8 @@
      */
     public boolean sameAs(Bitmap other) {
         checkRecycled("Can't call sameAs on a recycled bitmap!");
+        noteHardwareBitmapSlowCall();
+        other.noteHardwareBitmapSlowCall();
         if (this == other) return true;
         if (other == null) return false;
         if (other.isRecycled()) {
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index f38d8d2..79898bc 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -233,8 +233,7 @@
                 // TODO: Add ttc and variation font support. (b/37853920)
                 if (!fontFamily.addFontFromAssetManager(mgr, fontFile.getFileName(),
                         0 /* resourceCookie */, false /* isAsset */, 0 /* ttcIndex */,
-                        fontFile.getWeight(), fontFile.isItalic() ? STYLE_ITALIC : STYLE_NORMAL,
-                        null /* axes */)) {
+                        fontFile.getWeight(), fontFile.getItalic(), null /* axes */)) {
                     return null;
                 }
             }
diff --git a/graphics/java/android/graphics/drawable/InsetDrawable.java b/graphics/java/android/graphics/drawable/InsetDrawable.java
index bc40191..443aa49 100644
--- a/graphics/java/android/graphics/drawable/InsetDrawable.java
+++ b/graphics/java/android/graphics/drawable/InsetDrawable.java
@@ -188,19 +188,19 @@
 
         // Inset attribute may be overridden by more specific attributes.
         if (a.hasValue(R.styleable.InsetDrawable_inset)) {
-            final InsetValue inset = getInset(a, R.styleable.InsetDrawable_inset, 0);
+            final InsetValue inset = getInset(a, R.styleable.InsetDrawable_inset, new InsetValue());
             state.mInsetLeft = inset;
             state.mInsetTop = inset;
             state.mInsetRight = inset;
             state.mInsetBottom = inset;
         }
-        state.mInsetLeft = getInset(a, R.styleable.InsetDrawable_insetLeft, 0);
-        state.mInsetTop = getInset(a, R.styleable.InsetDrawable_insetTop, 0);
-        state.mInsetRight = getInset(a, R.styleable.InsetDrawable_insetRight, 0);
-        state.mInsetBottom = getInset(a, R.styleable.InsetDrawable_insetBottom, 0);
+        state.mInsetLeft = getInset(a, R.styleable.InsetDrawable_insetLeft, state.mInsetLeft);
+        state.mInsetTop = getInset(a, R.styleable.InsetDrawable_insetTop, state.mInsetTop);
+        state.mInsetRight = getInset(a, R.styleable.InsetDrawable_insetRight, state.mInsetRight);
+        state.mInsetBottom = getInset(a, R.styleable.InsetDrawable_insetBottom, state.mInsetBottom);
     }
 
-    private InsetValue getInset(@NonNull TypedArray a, int index, int defaultValue) {
+    private InsetValue getInset(@NonNull TypedArray a, int index, InsetValue defaultValue) {
         if (a.hasValue(index)) {
             TypedValue tv = a.peekValue(index);
             if (tv.type == TypedValue.TYPE_FRACTION) {
@@ -210,10 +210,13 @@
                 }
                 return new InsetValue(f, 0);
             } else {
-                return new InsetValue(0f, a.getDimensionPixelOffset(index, defaultValue));
+                int dimension = a.getDimensionPixelOffset(index, 0);
+                if (dimension != 0) {
+                    return new InsetValue(0, dimension);
+                }
             }
         }
-        return new InsetValue();
+        return defaultValue;
     }
 
     private void getInsets(Rect out) {
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index d7f75fc..d765584 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -486,7 +486,6 @@
 void Bitmap::getSkBitmap(SkBitmap* outBitmap) {
     outBitmap->setHasHardwareMipMap(mHasHardwareMipMap);
     if (isHardware()) {
-        ALOGW("Warning: attempt to read pixels from hardware bitmap, which is very slow operation");
         outBitmap->allocPixels(info());
         uirenderer::renderthread::RenderProxy::copyGraphicBufferInto(graphicBuffer(), outBitmap);
         return;
diff --git a/packages/SettingsLib/src/com/android/settingslib/SecureTouchListener.java b/packages/SettingsLib/src/com/android/settingslib/SecureTouchListener.java
new file mode 100644
index 0000000..766c42b
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/SecureTouchListener.java
@@ -0,0 +1,44 @@
+package com.android.settingslib;
+
+import android.os.SystemClock;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.Toast;
+
+/**
+ * A touch listener which consumes touches when another window is partly or wholly obscuring the
+ * window containing the view this listener is attached to.
+ * Optionally accepts a string to show the user as a toast when consuming an insecure touch
+ */
+public class SecureTouchListener implements View.OnTouchListener {
+
+    private static final long TAP_DEBOUNCE_TIME = 2000;
+    private long mLastToastTime = 0;
+    private String mWarningText;
+
+    public SecureTouchListener() {
+        this(null);
+    }
+
+    public SecureTouchListener(String warningText) {
+        mWarningText = warningText;
+    }
+
+    @Override
+    public boolean onTouch(View v, MotionEvent event) {
+        if ((event.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0
+                || (event.getFlags() & MotionEvent.FLAG_WINDOW_IS_PARTIALLY_OBSCURED) != 0) {
+            if (mWarningText != null) {
+                // Show a toast warning the user
+                final long currentTime = SystemClock.uptimeMillis();
+                if (currentTime - mLastToastTime > TAP_DEBOUNCE_TIME) {
+                    mLastToastTime = currentTime;
+                    Toast.makeText(v.getContext(), mWarningText, Toast.LENGTH_SHORT).show();
+                }
+            }
+            // Consume the touch event
+            return true;
+        }
+        return false;
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java
index ea28fe6..5a57e69 100644
--- a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java
+++ b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java
@@ -152,6 +152,12 @@
         final MeasurementDetails details = new MeasurementDetails();
         if (mVolume == null) return details;
 
+        if (mVolume.getType() == VolumeInfo.TYPE_PUBLIC) {
+            details.totalSize = mVolume.getPath().getTotalSpace();
+            details.availSize = mVolume.getPath().getUsableSpace();
+            return details;
+        }
+
         try {
             details.totalSize = mStats.getTotalBytes(mVolume.fsUuid);
             details.availSize = mStats.getFreeBytes(mVolume.fsUuid);
@@ -161,7 +167,6 @@
             return details;
         }
 
-
         final long finishTotal = SystemClock.elapsedRealtime();
         Log.d(TAG, "Measured total storage in " + (finishTotal - start) + "ms");
 
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 4b304b2..14e2a85 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -1142,28 +1142,55 @@
         } finally {
             Binder.restoreCallingIdentity(token);
         }
+
+        final SettingsState ssaidSettings = mSettingsRegistry.getSettingsLocked(
+                SETTINGS_TYPE_SSAID, owningUserId);
+
         if (instantSsaid != null) {
             // Use the stored value if it is still valid.
             if (ssaid != null && instantSsaid.equals(ssaid.getValue())) {
-                return ssaid;
+                return mascaradeSsaidSetting(ssaidSettings, ssaid);
             }
             // The value has changed, update the stored value.
-            final SettingsState ssaidSettings = mSettingsRegistry.getSettingsLocked(
-                    SETTINGS_TYPE_SSAID, owningUserId);
             final boolean success = ssaidSettings.insertSettingLocked(name, instantSsaid, null,
                     true, callingPkg.packageName);
             if (!success) {
                 throw new IllegalStateException("Failed to update instant app android id");
             }
-            return mSettingsRegistry.getSettingLocked(SETTINGS_TYPE_SSAID, owningUserId, name);
+            Setting setting = mSettingsRegistry.getSettingLocked(SETTINGS_TYPE_SSAID,
+                    owningUserId, name);
+            return mascaradeSsaidSetting(ssaidSettings, setting);
         }
 
         // Lazy initialize ssaid if not yet present in ssaid table.
         if (ssaid == null || ssaid.isNull() || ssaid.getValue() == null) {
-            return mSettingsRegistry.generateSsaidLocked(callingPkg, owningUserId);
+            Setting setting = mSettingsRegistry.generateSsaidLocked(callingPkg, owningUserId);
+            return mascaradeSsaidSetting(ssaidSettings, setting);
         }
 
-        return ssaid;
+        return mascaradeSsaidSetting(ssaidSettings, ssaid);
+    }
+
+    private Setting mascaradeSsaidSetting(SettingsState settingsState, Setting ssaidSetting) {
+        // SSAID settings are located in a dedicated table for internal bookkeeping
+        // but for the world they reside in the secure table, so adjust the key here.
+        // We have a special name when looking it up but want the world to see it as
+        // "android_id".
+        if (ssaidSetting != null) {
+            return settingsState.new Setting(ssaidSetting) {
+                @Override
+                public int getKey() {
+                    final int userId = getUserIdFromKey(super.getKey());
+                    return makeKey(SETTINGS_TYPE_SECURE, userId);
+                }
+
+                @Override
+                public String getName() {
+                    return Settings.Secure.ANDROID_ID;
+                }
+            };
+        }
+        return null;
     }
 
     private boolean insertSecureSetting(String name, String value, String tag,
@@ -1173,7 +1200,6 @@
                     + ", " + tag  + ", " + makeDefault + ", "  + requestingUserId
                     + ", " + forceNotify + ")");
         }
-
         return mutateSecureSetting(name, value, tag, makeDefault, requestingUserId,
                 MUTATION_OPERATION_INSERT, forceNotify, 0);
     }
@@ -1879,6 +1905,7 @@
         Bundle result = new Bundle();
         result.putString(Settings.NameValueTable.VALUE,
                 !setting.isNull() ? setting.getValue() : null);
+
         mSettingsRegistry.mGenerationRegistry.addGenerationData(result, setting.getKey());
         return result;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 5690495..41fb5f7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -579,6 +579,7 @@
                     .setComponent(aiaComponent)
                     .setAction(Intent.ACTION_VIEW)
                     .addCategory(Intent.CATEGORY_BROWSABLE)
+                    .addCategory("unique:" + System.currentTimeMillis())
                     .putExtra(Intent.EXTRA_PACKAGE_NAME, appInfo.packageName)
                     .putExtra(Intent.EXTRA_VERSION_CODE, appInfo.versionCode)
                     .putExtra(Intent.EXTRA_EPHEMERAL_FAILURE, pendingIntent);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/EmergencyCryptkeeperText.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EmergencyCryptkeeperText.java
index a2d1baf..c726189 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/EmergencyCryptkeeperText.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EmergencyCryptkeeperText.java
@@ -47,6 +47,11 @@
         public void onPhoneStateChanged(int phoneState) {
             update();
         }
+
+        @Override
+        public void onRefreshCarrierInfo() {
+            update();
+        }
     };
     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
         @Override
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index ac81565..b2712ff 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -373,11 +373,6 @@
     }
 
     private void onPackageBroadcastReceived(Intent intent, int userId) {
-        if (!mUserManager.isUserUnlockingOrUnlocked(userId) ||
-                isProfileWithLockedParent(userId)) {
-            return;
-        }
-
         final String action = intent.getAction();
         boolean added = false;
         boolean changed = false;
@@ -408,7 +403,11 @@
         }
 
         synchronized (mLock) {
-            ensureGroupStateLoadedLocked(userId);
+            if (!mUserManager.isUserUnlockingOrUnlocked(userId) ||
+                    isProfileWithLockedParent(userId)) {
+                return;
+            }
+            ensureGroupStateLoadedLocked(userId, /* enforceUserUnlockingOrUnlocked */ false);
 
             Bundle extras = intent.getExtras();
 
@@ -844,7 +843,7 @@
         mSecurityPolicy.enforceCallFromPackage(callingPackage);
 
         synchronized (mLock) {
-            ensureGroupStateLoadedLocked(userId);
+            ensureGroupStateLoadedLocked(userId, /* enforceUserUnlockingOrUnlocked */ false);
 
             // NOTE: The lookup is enforcing security across users by making
             // sure the caller can only access hosts it owns.
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index b536ad9..9081746 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -213,7 +213,7 @@
                             if (!doit) {
                                 return true;
                             }
-                            handleActiveAutofillServiceRemoved(getChangingUserId());
+                            removeCachedServiceLocked(getChangingUserId());
                         }
                     }
                 }
@@ -602,6 +602,31 @@
         public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
             if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
 
+            boolean showHistory = true;
+            boolean uiOnly = false;
+            if (args != null) {
+                for (String arg : args) {
+                    switch(arg) {
+                        case "--no-history":
+                            showHistory = false;
+                            break;
+                        case "--ui-only":
+                            uiOnly = true;
+                            break;
+                        case "--help":
+                            pw.println("Usage: dumpsys autofill [--ui-only|--no-history]");
+                            return;
+                        default:
+                            throw new IllegalArgumentException("Invalid dump arg: " + arg);
+                    }
+                }
+            }
+
+            if (uiOnly) {
+                mUi.dump(pw);
+                return;
+            }
+
             boolean oldDebug = sDebug;
             try {
                 synchronized (mLock) {
@@ -624,8 +649,10 @@
                     }
                     mUi.dump(pw);
                 }
-                pw.println("Requests history:");
-                mRequestsHistory.reverseDump(fd, pw, args);
+                if (showHistory) {
+                    pw.println("Requests history:");
+                    mRequestsHistory.reverseDump(fd, pw, args);
+                }
             } finally {
                 setDebugLocked(oldDebug);
             }
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 4507eae..3ab8b8d 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -19,17 +19,21 @@
 import static android.view.autofill.AutofillManager.ACTION_START_SESSION;
 import static android.view.autofill.AutofillManager.NO_SESSION;
 
+import static com.android.server.autofill.Helper.sDebug;
 import static com.android.server.autofill.Helper.sVerbose;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.ActivityManager;
 import android.app.AppGlobals;
+import android.app.IActivityManager;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ServiceInfo;
 import android.graphics.Rect;
+import android.os.AsyncTask;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.IBinder;
@@ -46,6 +50,7 @@
 import android.service.autofill.FillResponse;
 import android.service.autofill.IAutoFillService;
 import android.text.TextUtils;
+import android.util.ArrayMap;
 import android.util.LocalLog;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -72,6 +77,9 @@
     private static final String TAG = "AutofillManagerServiceImpl";
     private static final int MAX_SESSION_ID_CREATE_TRIES = 2048;
 
+    /** Minimum interval to prune abandoned sessions */
+    private static final int MAX_ABANDONED_SESSION_MILLIS = 30000;
+
     static final int MSG_SERVICE_SAVE = 1;
 
     private final int mUserId;
@@ -104,10 +112,10 @@
             mHandlerCallback, true);
 
     /**
-     * Cache of pending {@link Session}s, keyed by {@code activityToken}.
+     * Cache of pending {@link Session}s, keyed by sessionId.
      *
      * <p>They're kept until the {@link AutofillService} finished handling a request, an error
-     * occurs, or the session times out.
+     * occurs, or the session is abandoned.
      */
     @GuardedBy("mLock")
     private final SparseArray<Session> mSessions = new SparseArray<>();
@@ -116,6 +124,9 @@
     @GuardedBy("mLock")
     private FillEventHistory mEventHistory;
 
+    /** When was {@link PruneTask} last executed? */
+    private long mLastPrune = 0;
+
     AutofillManagerServiceImpl(Context context, Object lock, LocalLog requestsHistory,
             int userId, AutoFillUI ui, boolean disabled) {
         mContext = context;
@@ -260,6 +271,9 @@
             return 0;
         }
 
+        // Occasionally clean up abandoned sessions
+        pruneAbandonedSessionsLocked();
+
         final Session newSession = createSessionByTokenLocked(activityToken, uid, windowToken,
                 appCallbackToken, hasCallback, flags, packageName);
         if (newSession == null) {
@@ -277,6 +291,20 @@
         return newSession.id;
     }
 
+    /**
+     * Remove abandoned sessions if needed.
+     */
+    private void pruneAbandonedSessionsLocked() {
+        long now = System.currentTimeMillis();
+        if (mLastPrune < now - MAX_ABANDONED_SESSION_MILLIS) {
+            mLastPrune = now;
+
+            if (mSessions.size() > 0) {
+                (new PruneTask()).execute();
+            }
+        }
+    }
+
     void finishSessionLocked(int sessionId, int uid) {
         if (!isEnabled()) {
             return;
@@ -513,6 +541,7 @@
         pw.print(prefix); pw.print("Default component: ");
             pw.println(mContext.getString(R.string.config_defaultAutofillService));
         pw.print(prefix); pw.print("Disabled: "); pw.println(mDisabled);
+        pw.print(prefix); pw.print("Last prune: "); pw.println(mLastPrune);
 
         final int size = mSessions.size();
         if (size == 0) {
@@ -604,4 +633,62 @@
                 + ", component=" + (mInfo != null
                 ? mInfo.getServiceInfo().getComponentName() : null) + "]";
     }
+
+    /** Task used to prune abandoned session */
+    private class PruneTask extends AsyncTask<Void, Void, Void> {
+        @Override
+        protected Void doInBackground(Void... ignored) {
+            int numSessionsToRemove;
+            ArrayMap<IBinder, Integer> sessionsToRemove;
+
+            synchronized (mLock) {
+                numSessionsToRemove = mSessions.size();
+                sessionsToRemove = new ArrayMap<>(numSessionsToRemove);
+
+                for (int i = 0; i < numSessionsToRemove; i++) {
+                    Session session = mSessions.valueAt(i);
+
+                    sessionsToRemove.put(session.getActivityTokenLocked(), session.id);
+                }
+            }
+
+            IActivityManager am = ActivityManager.getService();
+
+            // Only remove sessions which's activities are not known to the activity manager anymore
+            for (int i = 0; i < numSessionsToRemove; i++) {
+                try {
+                    // The activity manager cannot resolve activities that have been removed
+                    if (am.getActivityClassForToken(sessionsToRemove.keyAt(i)) != null) {
+                        sessionsToRemove.removeAt(i);
+                        i--;
+                        numSessionsToRemove--;
+                    }
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Cannot figure out if activity is finished", e);
+                }
+            }
+
+            synchronized (mLock) {
+                for (int i = 0; i < numSessionsToRemove; i++) {
+                    Session sessionToRemove = mSessions.get(sessionsToRemove.valueAt(i));
+
+                    if (sessionToRemove != null) {
+                        if (sessionToRemove.isSavingLocked()) {
+                            if (sVerbose) {
+                                Slog.v(TAG, "Session " + sessionToRemove.id + " is saving");
+                            }
+                        } else {
+                            if (sDebug) {
+                                Slog.i(TAG, "Prune session " + sessionToRemove.id + " ("
+                                    + sessionToRemove.getActivityTokenLocked() + ")");
+                            }
+                            sessionToRemove.removeSelfLocked();
+                        }
+                    }
+                }
+            }
+
+            return null;
+        }
+    }
 }
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 25bb7cc..a98821d 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -176,6 +176,10 @@
     @GuardedBy("mLock")
     private boolean mDestroyed;
 
+    /** Whether the session is currently saving */
+    @GuardedBy("mLock")
+    private boolean mIsSaving;
+
     /**
      * Receiver of assist data from the app's {@link Activity}.
      */
@@ -360,7 +364,7 @@
      *
      * @return The activity token
      */
-    IBinder getActivityTokenLocked() {
+    @NonNull IBinder getActivityTokenLocked() {
         return mActivityToken;
     }
 
@@ -473,6 +477,8 @@
     @Override
     public void onSaveRequestSuccess(@NonNull String servicePackageName) {
         synchronized (mLock) {
+            mIsSaving = false;
+
             if (mDestroyed) {
                 Slog.w(TAG, "Call to Session#onSaveRequestSuccess() rejected - session: "
                         + id + " destroyed");
@@ -495,6 +501,8 @@
     public void onSaveRequestFailure(@Nullable CharSequence message,
             @NonNull String servicePackageName) {
         synchronized (mLock) {
+            mIsSaving = false;
+
             if (mDestroyed) {
                 Slog.w(TAG, "Call to Session#onSaveRequestFailure() rejected - session: "
                         + id + " destroyed");
@@ -595,6 +603,8 @@
     @Override
     public void cancelSave() {
         synchronized (mLock) {
+            mIsSaving = false;
+
             if (mDestroyed) {
                 Slog.w(TAG, "Call to Session#cancelSave() rejected - session: "
                         + id + " destroyed");
@@ -842,6 +852,8 @@
             if (atLeastOneChanged) {
                 mService.setSaveShown();
                 getUiForShowing().showSaveUi(mService.getServiceLabel(), saveInfo, mPackageName);
+
+                mIsSaving = true;
                 return false;
             }
         }
@@ -855,6 +867,13 @@
     }
 
     /**
+     * Returns whether the session is currently showing the save UI
+     */
+    boolean isSavingLocked() {
+        return mIsSaving;
+    }
+
+    /**
      * Calls service when user requested save.
      */
     void callSaveLocked() {
@@ -1050,6 +1069,9 @@
                 }
                 break;
             case ACTION_VIEW_ENTERED:
+                if (sVerbose && virtualBounds != null) {
+                    Slog.w(TAG, "entered on virtual child " + id + ": " + virtualBounds);
+                }
                 requestNewFillResponseIfNecessaryLocked(id, viewState, flags);
 
                 // Remove the UI if the ViewState has changed.
@@ -1351,6 +1373,7 @@
         pw.print(prefix); pw.print("mCurrentViewId: "); pw.println(mCurrentViewId);
         pw.print(prefix); pw.print("mViewStates size: "); pw.println(mViewStates.size());
         pw.print(prefix); pw.print("mDestroyed: "); pw.println(mDestroyed);
+        pw.print(prefix); pw.print("mIsSaving: "); pw.println(mIsSaving);
         final String prefix2 = prefix + "  ";
         for (Map.Entry<AutofillId, ViewState> entry : mViewStates.entrySet()) {
             pw.print(prefix); pw.print("State for id "); pw.println(entry.getKey());
diff --git a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
index 086742e..7428460 100644
--- a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
+++ b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
@@ -264,6 +264,10 @@
                 public void onDestroy() {
                     if (log.getType() == MetricsProto.MetricsEvent.TYPE_UNKNOWN) {
                         log.setType(MetricsProto.MetricsEvent.TYPE_CLOSE);
+
+                        if (mCallback != null) {
+                            mCallback.cancelSave();
+                        }
                     }
                     mMetricsLogger.write(log);
                 }
@@ -282,13 +286,18 @@
         pw.println("Autofill UI");
         final String prefix = "  ";
         final String prefix2 = "    ";
-        pw.print(prefix); pw.print("showsSaveUi: "); pw.println(mSaveUi != null);
         if (mFillUi != null) {
             pw.print(prefix); pw.println("showsFillUi: true");
             mFillUi.dump(pw, prefix2);
         } else {
             pw.print(prefix); pw.println("showsFillUi: false");
         }
+        if (mSaveUi != null) {
+            pw.print(prefix); pw.println("showsSaveUi: true");
+            mSaveUi.dump(pw, prefix2);
+        } else {
+            pw.print(prefix); pw.println("showsSaveUi: false");
+        }
     }
 
     @android.annotation.UiThread
diff --git a/services/autofill/java/com/android/server/autofill/ui/FillUi.java b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
index dd297a6..922962f 100644
--- a/services/autofill/java/com/android/server/autofill/ui/FillUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
@@ -398,6 +398,7 @@
             }
             return false;
         }
+
     }
 
     public void dump(PrintWriter pw, String prefix) {
@@ -408,5 +409,21 @@
         pw.print(prefix); pw.print("mContentWidth: "); pw.println(mContentWidth);
         pw.print(prefix); pw.print("mContentHeight: "); pw.println(mContentHeight);
         pw.print(prefix); pw.print("mDestroyed: "); pw.println(mDestroyed);
+        pw.print(prefix); pw.print("mWindow: ");
+        if (mWindow == null) {
+            pw.println("N/A");
+        } else {
+            final String prefix2 = prefix + "  ";
+            pw.println();
+            pw.print(prefix2); pw.print("showing: "); pw.println(mWindow.mShowing);
+            pw.print(prefix2); pw.print("view: "); pw.println(mWindow.mContentView);
+            pw.print(prefix2); pw.print("screen coordinates: ");
+            if (mWindow.mContentView == null) {
+                pw.println("N/A");
+            } else {
+                final int[] coordinates = mWindow.mContentView.getLocationOnScreen();
+                pw.print(coordinates[0]); pw.print("x"); pw.println(coordinates[1]);
+            }
+        }
     }
 }
diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
index bcdb118..d25ffce 100644
--- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
@@ -37,6 +37,8 @@
 import com.android.internal.R;
 import com.android.server.UiThread;
 
+import java.io.PrintWriter;
+
 /**
  * Autofill Save Prompt
  */
@@ -96,6 +98,9 @@
 
     private final @NonNull OneTimeListener mListener;
 
+    private final CharSequence mTitle;
+    private final CharSequence mSubTitle;
+
     private boolean mDestroyed;
 
     SaveUi(@NonNull Context context, @NonNull CharSequence providerLabel, @NonNull SaveInfo info,
@@ -126,37 +131,36 @@
             types.add(context.getString(R.string.autofill_save_type_email_address));
         }
 
-        final CharSequence title;
         switch (types.size()) {
             case 1:
-                title = Html.fromHtml(context.getString(R.string.autofill_save_title_with_type,
+                mTitle = Html.fromHtml(context.getString(R.string.autofill_save_title_with_type,
                         types.valueAt(0), providerLabel), 0);
                 break;
             case 2:
-                title = Html.fromHtml(context.getString(R.string.autofill_save_title_with_2types,
+                mTitle = Html.fromHtml(context.getString(R.string.autofill_save_title_with_2types,
                         types.valueAt(0), types.valueAt(1), providerLabel), 0);
                 break;
             case 3:
-                title = Html.fromHtml(context.getString(R.string.autofill_save_title_with_3types,
+                mTitle = Html.fromHtml(context.getString(R.string.autofill_save_title_with_3types,
                         types.valueAt(0), types.valueAt(1), types.valueAt(2), providerLabel), 0);
                 break;
             default:
                 // Use generic if more than 3 or invalid type (size 0).
-                title = Html.fromHtml(
+                mTitle = Html.fromHtml(
                         context.getString(R.string.autofill_save_title, providerLabel), 0);
         }
 
-        titleView.setText(title);
-        final CharSequence subTitle = info.getDescription();
-        if (subTitle != null) {
+        titleView.setText(mTitle);
+        mSubTitle = info.getDescription();
+        if (mSubTitle != null) {
             final TextView subTitleView = (TextView) view.findViewById(R.id.autofill_save_subtitle);
-            subTitleView.setText(subTitle);
+            subTitleView.setText(mSubTitle);
             subTitleView.setVisibility(View.VISIBLE);
         }
 
-        Slog.i(TAG, "Showing save dialog: " + title);
+        Slog.i(TAG, "Showing save dialog: " + mTitle);
         if (sDebug) {
-            Slog.d(TAG, "SubTitle: " + subTitle);
+            Slog.d(TAG, "SubTitle: " + mSubTitle);
         }
 
         final TextView noButton = view.findViewById(R.id.autofill_save_no);
@@ -207,4 +211,18 @@
             throw new IllegalStateException("cannot interact with a destroyed instance");
         }
     }
+
+    void dump(PrintWriter pw, String prefix) {
+        pw.print(prefix); pw.print("title: "); pw.println(mTitle);
+        pw.print(prefix); pw.print("subtitle: "); pw.println(mSubTitle);
+
+        final View view = mDialog.getWindow().getDecorView();
+        final int[] loc = view.getLocationOnScreen();
+        pw.print(prefix); pw.print("coordinates: ");
+            pw.print('('); pw.print(loc[0]); pw.print(','); pw.print(loc[1]);pw.print(')');
+            pw.print('(');
+                pw.print(loc[0] + view.getWidth()); pw.print(',');
+                pw.print(loc[1] + view.getHeight());pw.println(')');
+        pw.print(prefix); pw.print("destroyed: "); pw.println(mDestroyed);
+    }
 }
diff --git a/services/core/Android.mk b/services/core/Android.mk
index f896478..15493467 100644
--- a/services/core/Android.mk
+++ b/services/core/Android.mk
@@ -13,7 +13,6 @@
     ../../../../system/netd/server/binder/android/net/INetd.aidl \
     ../../../../system/netd/server/binder/android/net/metrics/INetdEventListener.aidl \
     ../../../native/cmds/installd/binder/android/os/IInstalld.aidl \
-    ../../../native/services/vr/vr_window_manager/aidl/android/service/vr/IVrWindowManager.aidl \
 
 LOCAL_AIDL_INCLUDES += \
     system/netd/server/binder
diff --git a/services/core/java/com/android/server/SyntheticPasswordManager.java b/services/core/java/com/android/server/SyntheticPasswordManager.java
index 6ec74e1..f797517 100644
--- a/services/core/java/com/android/server/SyntheticPasswordManager.java
+++ b/services/core/java/com/android/server/SyntheticPasswordManager.java
@@ -346,11 +346,14 @@
         PasswordData pwd = PasswordData.create(credentialType);
         byte[] pwdToken = computePasswordToken(credential, pwd);
 
+        // In case GK enrollment leaves persistent state around (in RPMB), this will nuke them
+        // to prevent them from accumulating and causing problems.
+        gatekeeper.clearSecureUserId(fakeUid(userId));
         GateKeeperResponse response = gatekeeper.enroll(fakeUid(userId), null, null,
                 passwordTokenToGkInput(pwdToken));
         if (response.getResponseCode() != GateKeeperResponse.RESPONSE_OK) {
             Log.e(TAG, "Fail to enroll user password when creating SP for user " + userId);
-            return 0;
+            return DEFAULT_HANDLE;
         }
         pwd.passwordHandle = response.getPayload();
         long sid = sidFromPasswordHandle(pwd.passwordHandle);
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index a5615a9..1ed46a0 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -622,6 +622,17 @@
                             != ActivityManager.APP_START_MODE_NORMAL) {
                         if (stopping == null) {
                             stopping = new ArrayList<>();
+                            String compName = service.name.flattenToShortString();
+                            EventLogTags.writeAmStopIdleService(service.appInfo.uid, compName);
+                            StringBuilder sb = new StringBuilder(64);
+                            sb.append("Stopping service due to app idle: ");
+                            UserHandle.formatUid(sb, service.appInfo.uid);
+                            sb.append(" ");
+                            TimeUtils.formatDuration(service.createTime
+                                    - SystemClock.elapsedRealtime(), sb);
+                            sb.append(" ");
+                            sb.append(compName);
+                            Slog.w(TAG, sb.toString());
                             stopping.add(service);
                         }
                     }
@@ -1364,7 +1375,7 @@
                 // This could have made the service more important.
                 mAm.updateLruProcessLocked(s.app, s.app.hasClientActivities
                         || s.app.treatLikeActivity, b.client);
-                mAm.updateOomAdjLocked(s.app);
+                mAm.updateOomAdjLocked(s.app, true);
             }
 
             if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Bind " + s + " with " + b
@@ -1479,13 +1490,15 @@
                                 r.binding.service.app.hasClientActivities
                                 || r.binding.service.app.treatLikeActivity, null);
                     }
-                    mAm.updateOomAdjLocked(r.binding.service.app);
+                    mAm.updateOomAdjLocked(r.binding.service.app, false);
                 }
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
         }
 
+        mAm.updateOomAdjLocked();
+
         return true;
     }
 
@@ -2225,7 +2238,7 @@
             bumpServiceExecutingLocked(r, execInFg, "start");
             if (!oomAdjusted) {
                 oomAdjusted = true;
-                mAm.updateOomAdjLocked(r.app);
+                mAm.updateOomAdjLocked(r.app, true);
             }
             if (r.fgRequired && !r.fgWaiting) {
                 if (!r.isForeground) {
@@ -2349,7 +2362,7 @@
                 if (ibr.hasBound) {
                     try {
                         bumpServiceExecutingLocked(r, false, "bring down unbind");
-                        mAm.updateOomAdjLocked(r.app);
+                        mAm.updateOomAdjLocked(r.app, true);
                         ibr.hasBound = false;
                         ibr.requested = false;
                         r.app.thread.scheduleUnbindService(r,
@@ -2441,7 +2454,7 @@
                     bumpServiceExecutingLocked(r, false, "destroy");
                     mDestroyingServices.add(r);
                     r.destroying = true;
-                    mAm.updateOomAdjLocked(r.app);
+                    mAm.updateOomAdjLocked(r.app, true);
                     r.app.thread.scheduleStopService(r);
                 } catch (Exception e) {
                     Slog.w(TAG, "Exception when destroying service "
@@ -2542,7 +2555,7 @@
                         // it to go down there and we want it to start out near the top.
                         mAm.updateLruProcessLocked(s.app, false, null);
                     }
-                    mAm.updateOomAdjLocked(s.app);
+                    mAm.updateOomAdjLocked(s.app, true);
                     b.intent.hasBound = false;
                     // Assume the client doesn't want to know about a rebind;
                     // we will deal with that later if it asks for one.
@@ -2695,7 +2708,7 @@
                     mDestroyingServices.remove(r);
                     r.bindings.clear();
                 }
-                mAm.updateOomAdjLocked(r.app);
+                mAm.updateOomAdjLocked(r.app, true);
             }
             r.executeFg = false;
             if (r.tracker != null) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 6d69915..268adc5 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -812,15 +812,28 @@
     final SparseArray<ProcessRecord> mPidsSelfLocked = new SparseArray<ProcessRecord>();
 
     /**
-     * All of the processes that have been forced to be foreground.  The key
+     * All of the processes that have been forced to be important.  The key
      * is the pid of the caller who requested it (we hold a death
      * link on it).
      */
-    abstract class ForegroundToken implements IBinder.DeathRecipient {
-        int pid;
-        IBinder token;
+    abstract class ImportanceToken implements IBinder.DeathRecipient {
+        final int pid;
+        final IBinder token;
+        final String reason;
+
+        ImportanceToken(int _pid, IBinder _token, String _reason) {
+            pid = _pid;
+            token = _token;
+            reason = _reason;
+        }
+
+        @Override
+        public String toString() {
+            return "ImportanceToken { " + Integer.toHexString(System.identityHashCode(this))
+                    + " " + reason + " " + pid + " " + token + " }";
+        }
     }
-    final SparseArray<ForegroundToken> mForegroundProcesses = new SparseArray<ForegroundToken>();
+    final SparseArray<ImportanceToken> mImportantProcesses = new SparseArray<ImportanceToken>();
 
     /**
      * List of records for processes that someone had tried to start before the
@@ -6499,6 +6512,7 @@
                 if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
                         "No more processes in " + old.uidRecord);
                 enqueueUidChangeLocked(old.uidRecord, -1, UidRecord.CHANGE_GONE);
+                EventLogTags.writeAmUidStopped(uid);
                 mActiveUids.remove(uid);
                 noteUidProcessState(uid, ActivityManager.PROCESS_STATE_NONEXISTENT);
             }
@@ -6530,6 +6544,7 @@
             }
             uidRec.updateHasInternetPermission();
             mActiveUids.put(proc.uid, uidRec);
+            EventLogTags.writeAmUidRunning(uidRec.uid);
             noteUidProcessState(uidRec.uid, uidRec.curProcState);
             enqueueUidChangeLocked(uidRec, -1, UidRecord.CHANGE_ACTIVE);
         }
@@ -6717,7 +6732,7 @@
         app.makeActive(thread, mProcessStats);
         app.curAdj = app.setAdj = app.verifiedAdj = ProcessList.INVALID_ADJ;
         app.curSchedGroup = app.setSchedGroup = ProcessList.SCHED_GROUP_DEFAULT;
-        app.forcingToForeground = null;
+        app.forcingToImportant = null;
         updateProcessForegroundLocked(app, false, false);
         app.hasShownUi = false;
         app.debugging = false;
@@ -7717,20 +7732,20 @@
         }
     }
 
-    void foregroundTokenDied(ForegroundToken token) {
+    void importanceTokenDied(ImportanceToken token) {
         synchronized (ActivityManagerService.this) {
             synchronized (mPidsSelfLocked) {
-                ForegroundToken cur
-                    = mForegroundProcesses.get(token.pid);
+                ImportanceToken cur
+                    = mImportantProcesses.get(token.pid);
                 if (cur != token) {
                     return;
                 }
-                mForegroundProcesses.remove(token.pid);
+                mImportantProcesses.remove(token.pid);
                 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
                 if (pr == null) {
                     return;
                 }
-                pr.forcingToForeground = null;
+                pr.forcingToImportant = null;
                 updateProcessForegroundLocked(pr, false, false);
             }
             updateOomAdjLocked();
@@ -7738,9 +7753,9 @@
     }
 
     @Override
-    public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
+    public void setProcessImportant(IBinder token, int pid, boolean isForeground, String reason) {
         enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
-                "setProcessForeground()");
+                "setProcessImportant()");
         synchronized(this) {
             boolean changed = false;
 
@@ -7750,28 +7765,26 @@
                     Slog.w(TAG, "setProcessForeground called on unknown pid: " + pid);
                     return;
                 }
-                ForegroundToken oldToken = mForegroundProcesses.get(pid);
+                ImportanceToken oldToken = mImportantProcesses.get(pid);
                 if (oldToken != null) {
                     oldToken.token.unlinkToDeath(oldToken, 0);
-                    mForegroundProcesses.remove(pid);
+                    mImportantProcesses.remove(pid);
                     if (pr != null) {
-                        pr.forcingToForeground = null;
+                        pr.forcingToImportant = null;
                     }
                     changed = true;
                 }
                 if (isForeground && token != null) {
-                    ForegroundToken newToken = new ForegroundToken() {
+                    ImportanceToken newToken = new ImportanceToken(pid, token, reason) {
                         @Override
                         public void binderDied() {
-                            foregroundTokenDied(this);
+                            importanceTokenDied(this);
                         }
                     };
-                    newToken.pid = pid;
-                    newToken.token = token;
                     try {
                         token.linkToDeath(newToken, 0);
-                        mForegroundProcesses.put(pid, newToken);
-                        pr.forcingToForeground = token;
+                        mImportantProcesses.put(pid, newToken);
+                        pr.forcingToImportant = newToken;
                         changed = true;
                     } catch (RemoteException e) {
                         // If the process died while doing this, we will later
@@ -11313,7 +11326,7 @@
 
                 checkTime(startTime, "getContentProviderImpl: before updateOomAdj");
                 final int verifiedAdj = cpr.proc.verifiedAdj;
-                boolean success = updateOomAdjLocked(cpr.proc);
+                boolean success = updateOomAdjLocked(cpr.proc, true);
                 // XXX things have changed so updateOomAdjLocked doesn't actually tell us
                 // if the process has been successfully adjusted.  So to reduce races with
                 // it, we will check whether the process still exists.  Note that this doesn't
@@ -11775,7 +11788,7 @@
                         dst.proc = r;
                         dst.notifyAll();
                     }
-                    updateOomAdjLocked(r);
+                    updateOomAdjLocked(r, true);
                     maybeUpdateProviderUsageStatsLocked(r, src.info.packageName,
                             src.info.authority);
                 }
@@ -13506,7 +13519,7 @@
                     }
                 }
                 if (changed) {
-                    updateOomAdjLocked(pr);
+                    updateOomAdjLocked(pr, true);
                 }
             }
         } finally {
@@ -15490,12 +15503,12 @@
             }
         }
 
-        if (mForegroundProcesses.size() > 0) {
+        if (mImportantProcesses.size() > 0) {
             synchronized (mPidsSelfLocked) {
                 boolean printed = false;
-                for (int i=0; i<mForegroundProcesses.size(); i++) {
+                for (int i = 0; i< mImportantProcesses.size(); i++) {
                     ProcessRecord r = mPidsSelfLocked.get(
-                            mForegroundProcesses.valueAt(i).pid);
+                            mImportantProcesses.valueAt(i).pid);
                     if (dumpPackage != null && (r == null
                             || !r.pkgList.containsKey(dumpPackage))) {
                         continue;
@@ -15507,8 +15520,8 @@
                         printed = true;
                         printedAnything = true;
                     }
-                    pw.print("    PID #"); pw.print(mForegroundProcesses.keyAt(i));
-                            pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
+                    pw.print("    PID #"); pw.print(mImportantProcesses.keyAt(i));
+                            pw.print(": "); pw.println(mImportantProcesses.valueAt(i));
                 }
             }
         }
@@ -17779,7 +17792,7 @@
         app.unlinkDeathRecipient();
         app.makeInactive(mProcessStats);
         app.waitingToKill = null;
-        app.forcingToForeground = null;
+        app.forcingToImportant = null;
         updateProcessForegroundLocked(app, false, false);
         app.foregroundActivities = false;
         app.hasShownUi = false;
@@ -18279,7 +18292,7 @@
             mBackupAppName = app.packageName;
 
             // Try not to kill the process during backup
-            updateOomAdjLocked(proc);
+            updateOomAdjLocked(proc, true);
 
             // If the process is already attached, schedule the creation of the backup agent now.
             // If it is not yet live, this will be done when it attaches to the framework.
@@ -18376,7 +18389,7 @@
 
                 // Not backing this app up any more; reset its OOM adjustment
                 final ProcessRecord proc = mBackupTarget.app;
-                updateOomAdjLocked(proc);
+                updateOomAdjLocked(proc, true);
                 proc.inFullBackup = false;
 
                 oldBackupUid = mBackupTarget != null ? mBackupTarget.appInfo.uid : -1;
@@ -20774,14 +20787,6 @@
                 app.cached = false;
                 app.adjType = "fg-service";
                 schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
-            } else if (app.forcingToForeground != null) {
-                // The user is aware of this app, so make it visible.
-                adj = ProcessList.PERCEPTIBLE_APP_ADJ;
-                procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
-                app.cached = false;
-                app.adjType = "force-fg";
-                app.adjSource = app.forcingToForeground;
-                schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
             } else if (app.hasOverlayUi) {
                 // The process is display an overlay UI.
                 adj = ProcessList.PERCEPTIBLE_APP_ADJ;
@@ -20792,6 +20797,21 @@
             }
         }
 
+        if (adj > ProcessList.PERCEPTIBLE_APP_ADJ
+                || procState > ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND) {
+            if (app.forcingToImportant != null) {
+                // This is currently used for toasts...  they are not interactive, and
+                // we don't want them to cause the app to become fully foreground (and
+                // thus out of background check), so we yes the best background level we can.
+                adj = ProcessList.PERCEPTIBLE_APP_ADJ;
+                procState = ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND;
+                app.cached = false;
+                app.adjType = "force-imp";
+                app.adjSource = app.forcingToImportant;
+                schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
+            }
+        }
+
         if (app == mHeavyWeightProcess) {
             if (adj > ProcessList.HEAVY_WEIGHT_APP_ADJ) {
                 // We don't want to kill the current heavy-weight process.
@@ -22032,10 +22052,7 @@
                         + mConstants.SERVICE_USAGE_INTERACTION_TIME;
             }
         } else {
-            // If the app was being forced to the foreground, by say a Toast, then
-            // no need to treat it as an interaction
-            isInteraction = app.forcingToForeground == null
-                    && app.curProcState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
+            isInteraction = app.curProcState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
             app.fgInteractionTime = 0;
         }
         if (isInteraction && (!app.reportedInteraction || (nowElapsed-app.interactionEventTime)
@@ -22136,7 +22153,14 @@
         return act;
     }
 
-    final boolean updateOomAdjLocked(ProcessRecord app) {
+    /**
+     * Update OomAdj for a specific process.
+     * @param app The process to update
+     * @param oomAdjAll If it's ok to call updateOomAdjLocked() for all running apps
+     *                  if necessary, or skip.
+     * @return whether updateOomAdjLocked(app) was successful.
+     */
+    final boolean updateOomAdjLocked(ProcessRecord app, boolean oomAdjAll) {
         final ActivityRecord TOP_ACT = resumedAppLocked();
         final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
         final boolean wasCached = app.cached;
@@ -22151,7 +22175,8 @@
                 ? app.curRawAdj : ProcessList.UNKNOWN_ADJ;
         boolean success = updateOomAdjLocked(app, cachedAdj, TOP_APP, false,
                 SystemClock.uptimeMillis());
-        if (wasCached != app.cached || app.curRawAdj == ProcessList.UNKNOWN_ADJ) {
+        if (oomAdjAll
+                && (wasCached != app.cached || app.curRawAdj == ProcessList.UNKNOWN_ADJ)) {
             // Changed to/from cached state, so apps after it in the LRU
             // list may also be changed.
             updateOomAdjLocked();
@@ -22565,6 +22590,7 @@
                 } else {
                     if (uidRec.idle) {
                         uidChange = UidRecord.CHANGE_ACTIVE;
+                        EventLogTags.writeAmUidActive(uidRec.uid);
                         uidRec.idle = false;
                     }
                     uidRec.lastBackgroundTime = 0;
@@ -22643,6 +22669,7 @@
                         if (UserHandle.getAppId(uidRec.uid) == appId) {
                             if (userId == UserHandle.USER_ALL ||
                                     userId == UserHandle.getUserId(uidRec.uid)) {
+                                EventLogTags.writeAmUidIdle(uidRec.uid);
                                 uidRec.idle = true;
                                 Slog.w(TAG, "Idling uid " + UserHandle.formatUid(uidRec.uid)
                                         + " from package " + packageName + " user " + userId);
@@ -22677,6 +22704,7 @@
                 final long bgTime = uidRec.lastBackgroundTime;
                 if (bgTime > 0 && !uidRec.idle) {
                     if (bgTime <= maxBgTime) {
+                        EventLogTags.writeAmUidIdle(uidRec.uid);
                         uidRec.idle = true;
                         doStopUidLocked(uidRec.uid, uidRec);
                     } else {
@@ -23729,7 +23757,7 @@
                 }
                 pr.hasOverlayUi = hasOverlayUi;
                 //Slog.i(TAG, "Setting hasOverlayUi=" + pr.hasOverlayUi + " for pid=" + pid);
-                updateOomAdjLocked(pr);
+                updateOomAdjLocked(pr, true);
             }
         }
 
@@ -23867,6 +23895,34 @@
         }
     }
 
+    public void waitForBroadcastIdle(PrintWriter pw) {
+        enforceCallingPermission(permission.DUMP, "waitForBroadcastIdle()");
+        while (true) {
+            boolean idle = true;
+            synchronized (this) {
+                for (BroadcastQueue queue : mBroadcastQueues) {
+                    if (!queue.isIdle()) {
+                        final String msg = "Waiting for queue " + queue + " to become idle...";
+                        pw.println(msg);
+                        pw.flush();
+                        Slog.v(TAG, msg);
+                        idle = false;
+                    }
+                }
+            }
+
+            if (idle) {
+                final String msg = "All broadcast queues are idle!";
+                pw.println(msg);
+                pw.flush();
+                Slog.v(TAG, msg);
+                return;
+            } else {
+                SystemClock.sleep(1000);
+            }
+        }
+    }
+
     /**
      * Return the user id of the last resumed activity.
      */
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index b6bfb00..dab122f 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -251,6 +251,8 @@
                     return runUpdateApplicationInfo(pw);
                 case "no-home-screen":
                     return runNoHomeScreen(pw);
+                case "wait-for-broadcast-idle":
+                    return runWaitForBroadcastIdle(pw);
                 default:
                     return handleDefaultCommands(cmd);
             }
@@ -2419,6 +2421,11 @@
         return 0;
     }
 
+    int runWaitForBroadcastIdle(PrintWriter pw) throws RemoteException {
+        mInternal.waitForBroadcastIdle(pw);
+        return 0;
+    }
+
     private Resources getResources(PrintWriter pw) throws RemoteException {
         // system resources does not contain all the device configuration, construct it manually.
         Configuration config = mInterface.getConfiguration();
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index d6bfb35..cfb5478 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -740,6 +740,8 @@
         }
         // If we've created a crash dialog, show it without the lock held
         if(data.proc.crashDialog != null) {
+            Slog.i(TAG, "Showing crash dialog for package " + data.proc.info.packageName
+                    + " u" + data.proc.userId);
             data.proc.crashDialog.show();
         }
     }
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index d08298b..639b7a9 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -51,7 +51,6 @@
 import android.util.EventLog;
 import android.util.Slog;
 import android.util.TimeUtils;
-import com.android.server.DeviceIdleController;
 
 import static com.android.server.am.ActivityManagerDebugConfig.*;
 
@@ -204,6 +203,11 @@
         mDelayBehindServices = allowDelayBehindServices;
     }
 
+    @Override
+    public String toString() {
+        return mQueueName;
+    }
+
     public boolean isPendingBroadcastProcessLocked(int pid) {
         return mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid;
     }
@@ -682,7 +686,7 @@
                 // are already core system stuff so don't matter for this.
                 r.curApp = filter.receiverList.app;
                 filter.receiverList.app.curReceivers.add(r);
-                mService.updateOomAdjLocked(r.curApp);
+                mService.updateOomAdjLocked(r.curApp, true);
             }
         }
         try {
@@ -1579,6 +1583,11 @@
                 record.intent == null ? "" : record.intent.getAction());
     }
 
+    final boolean isIdle() {
+        return mParallelBroadcasts.isEmpty() && mOrderedBroadcasts.isEmpty()
+                && (mPendingBroadcast == null);
+    }
+
     final boolean dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args,
             int opti, boolean dumpAll, String dumpPackage, boolean needSep) {
         SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
diff --git a/services/core/java/com/android/server/am/EventLogTags.logtags b/services/core/java/com/android/server/am/EventLogTags.logtags
index f618fc7..372ab6b 100644
--- a/services/core/java/com/android/server/am/EventLogTags.logtags
+++ b/services/core/java/com/android/server/am/EventLogTags.logtags
@@ -114,3 +114,14 @@
 
 # UserState has changed
 30051 am_user_state_changed (id|1|5),(state|1|5)
+
+# Note when any processes of a uid have started running
+30052 am_uid_running (UID|1|5)
+# Note when all processes of a uid have stopped.
+30053 am_uid_stopped (UID|1|5)
+# Note when the state of a uid has become active.
+30054 am_uid_active (UID|1|5)
+# Note when the state of a uid has become idle (background check enforced).
+30055 am_uid_idle (UID|1|5)
+# Note when a service is being forcibly stopped because its app went idle.
+30056 am_stop_idle_service (UID|1|5),(Component Name|3)
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index fbc2bd2..b222e3a 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -135,7 +135,7 @@
     long interactionEventTime;  // The time we sent the last interaction event
     long fgInteractionTime;     // When we became foreground for interaction purposes
     String waitingToKill;       // Process is waiting to be killed when in the bg, and reason
-    IBinder forcingToForeground;// Token that is forcing this process to be foreground
+    Object forcingToImportant;  // Token that is forcing this process to be important
     int adjSeq;                 // Sequence id for identifying oom_adj assignment cycles
     int lruSeq;                 // Sequence id for identifying LRU update cycles
     CompatibilityInfo compat;   // last used compatibility mode
@@ -302,9 +302,9 @@
                     pw.print(" hasAboveClient="); pw.print(hasAboveClient);
                     pw.print(" treatLikeActivity="); pw.println(treatLikeActivity);
         }
-        if (foregroundServices || forcingToForeground != null) {
+        if (foregroundServices || forcingToImportant != null) {
             pw.print(prefix); pw.print("foregroundServices="); pw.print(foregroundServices);
-                    pw.print(" forcingToForeground="); pw.println(forcingToForeground);
+                    pw.print(" forcingToImportant="); pw.println(forcingToImportant);
         }
         if (reportedInteraction || fgInteractionTime != 0) {
             pw.print(prefix); pw.print("reportedInteraction=");
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 3b5e5bc..6a310f2 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -439,7 +439,7 @@
                 }
             }
 
-            Slog.d(TAG, "Sending BOOT_COMPLETE user #" + userId);
+            Slog.i(TAG, "Sending BOOT_COMPLETE user #" + userId);
             // Do not report secondary users, runtime restarts or first boot/upgrade
             if (userId == UserHandle.USER_SYSTEM
                     && !mInjector.isRuntimeRestarted() && !mInjector.isFirstBootOrUpgrade()) {
@@ -451,7 +451,14 @@
             bootIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
             bootIntent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT
                     | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
-            mInjector.broadcastIntentLocked(bootIntent, null, null, 0, null, null,
+            mInjector.broadcastIntentLocked(bootIntent, null, new IIntentReceiver.Stub() {
+                @Override
+                public void performReceive(Intent intent, int resultCode, String data,
+                        Bundle extras, boolean ordered, boolean sticky, int sendingUser)
+                        throws RemoteException {
+                    Slog.i(UserController.TAG, "Finished processing BOOT_COMPLETED for u" + userId);
+                }
+            }, 0, null, null,
                     new String[] { android.Manifest.permission.RECEIVE_BOOT_COMPLETED },
                     AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID, userId);
         }
diff --git a/services/core/java/com/android/server/audio/FocusRequester.java b/services/core/java/com/android/server/audio/FocusRequester.java
index 73cbffd..125095c 100644
--- a/services/core/java/com/android/server/audio/FocusRequester.java
+++ b/services/core/java/com/android/server/audio/FocusRequester.java
@@ -322,8 +322,8 @@
                 if (mFocusLossWasNotified) {
                     fd.dispatchAudioFocusChange(focusGain, mClientId);
                 }
-                mFocusController.unduckPlayers(this);
             }
+            mFocusController.unduckPlayers(this);
             mFocusLossWasNotified = false;
         } catch (android.os.RemoteException e) {
             Log.e(TAG, "Failure to signal gain of audio focus due to: ", e);
@@ -333,6 +333,15 @@
     /**
      * Called synchronized on MediaFocusControl.mAudioFocusLock
      */
+    void handleFocusGainFromRequest(int focusRequestResult) {
+        if (focusRequestResult == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
+            mFocusController.unduckPlayers(this);
+        }
+    }
+
+    /**
+     * Called synchronized on MediaFocusControl.mAudioFocusLock
+     */
     void handleFocusLoss(int focusLoss, @Nullable final FocusRequester fr) {
         try {
             if (focusLoss != mFocusLossReceived) {
@@ -381,6 +390,8 @@
                         Log.v(TAG, "NOT dispatching " + focusChangeToString(mFocusLossReceived)
                             + " to " + mClientId + ", ducking implemented by framework");
                     }
+                    mFocusController.notifyExtPolicyFocusLoss_syncAf(
+                            toAudioFocusInfo(), false /* wasDispatched */);
                     return; // with mFocusLossWasNotified = false
                 }
 
diff --git a/services/core/java/com/android/server/audio/MediaFocusControl.java b/services/core/java/com/android/server/audio/MediaFocusControl.java
index f5c13c1..7d742ff 100644
--- a/services/core/java/com/android/server/audio/MediaFocusControl.java
+++ b/services/core/java/com/android/server/audio/MediaFocusControl.java
@@ -752,6 +752,7 @@
 
                 // push focus requester at the top of the audio focus stack
                 mFocusStack.push(nfr);
+                nfr.handleFocusGainFromRequest(AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
             }
             notifyExtPolicyFocusGrant_syncAf(nfr.toAudioFocusInfo(),
                     AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
diff --git a/services/core/java/com/android/server/display/NightDisplayService.java b/services/core/java/com/android/server/display/NightDisplayService.java
index 7849896..d574265 100644
--- a/services/core/java/com/android/server/display/NightDisplayService.java
+++ b/services/core/java/com/android/server/display/NightDisplayService.java
@@ -567,22 +567,27 @@
 
         private final TwilightManager mTwilightManager;
 
-        private Calendar mLastActivatedTime;
-
         TwilightAutoMode() {
             mTwilightManager = getLocalService(TwilightManager.class);
         }
 
         private void updateActivated(TwilightState state) {
-            boolean activate = state != null && state.isNight();
-            if (state != null && mLastActivatedTime != null) {
+            if (state == null) {
+                // If there isn't a valid TwilightState then just keep the current activated
+                // state.
+                return;
+            }
+
+            boolean activate = state.isNight();
+            final Calendar lastActivatedTime = getLastActivatedTime();
+            if (lastActivatedTime != null) {
                 final Calendar now = Calendar.getInstance();
                 final Calendar sunrise = state.sunrise();
                 final Calendar sunset = state.sunset();
 
                 // Maintain the existing activated state if within the current period.
-                if (mLastActivatedTime.before(now)
-                        && (mLastActivatedTime.after(sunrise) ^ mLastActivatedTime.after(sunset))) {
+                if (lastActivatedTime.before(now)
+                        && (lastActivatedTime.after(sunrise) ^ lastActivatedTime.after(sunset))) {
                     activate = mController.isActivated();
                 }
             }
@@ -595,7 +600,6 @@
         @Override
         public void onStart() {
             mTwilightManager.registerListener(this, mHandler);
-            mLastActivatedTime = getLastActivatedTime();
 
             // Force an update to initialize state.
             updateActivated(mTwilightManager.getLastTwilightState());
@@ -604,14 +608,10 @@
         @Override
         public void onStop() {
             mTwilightManager.unregisterListener(this);
-            mLastActivatedTime = null;
         }
 
         @Override
         public void onActivated(boolean activated) {
-            if (mIsActivated != null) {
-                mLastActivatedTime = getLastActivatedTime();
-            }
         }
 
         @Override
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 1d843c1..70766f9 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2871,8 +2871,7 @@
                                 adjustedSbn.getUser(), GroupHelper.AUTOGROUP_KEY,
                                 System.currentTimeMillis());
                 summaryRecord = new NotificationRecord(getContext(), summarySbn,
-                        notificationRecord.getChannel(), mRankingHelper.supportsChannels(
-                                summarySbn.getPackageName(), summarySbn.getUid()));
+                        notificationRecord.getChannel());
                 summaries.put(pkg, summarySbn.getKey());
             }
         }
@@ -3211,8 +3210,7 @@
         final StatusBarNotification n = new StatusBarNotification(
                 pkg, opPkg, id, tag, notificationUid, callingPid, notification,
                 user, null, System.currentTimeMillis());
-        final NotificationRecord r = new NotificationRecord(getContext(), n, channel,
-                mRankingHelper.supportsChannels(pkg, notificationUid));
+        final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
 
         if (!checkDisqualifyingFeatures(userId, notificationUid, id,tag, r)) {
             return;
@@ -3937,7 +3935,7 @@
             }
         }
         try {
-            mAm.setProcessForeground(mForegroundToken, pid, toastCount > 0);
+            mAm.setProcessImportant(mForegroundToken, pid, toastCount > 0, "toast");
         } catch (RemoteException e) {
             // Shouldn't happen.
         }
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index f019a5c..5a5e658 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -116,7 +116,7 @@
     private int mSuppressedVisualEffects = 0;
     private String mUserExplanation;
     private String mPeopleExplanation;
-    private boolean mSupportsChannels = false;
+    private boolean mPreChannelsNotification = true;
     private Uri mSound;
     private long[] mVibration;
     private AudioAttributes mAttributes;
@@ -129,7 +129,7 @@
 
     @VisibleForTesting
     public NotificationRecord(Context context, StatusBarNotification sbn,
-            NotificationChannel channel, boolean supportsChannels)
+            NotificationChannel channel)
     {
         this.sbn = sbn;
         mOriginalFlags = sbn.getNotification().flags;
@@ -139,7 +139,7 @@
         mContext = context;
         stats = new NotificationUsageStats.SingleNotificationStats();
         mChannel = channel;
-        mSupportsChannels = supportsChannels;
+        mPreChannelsNotification = isPreChannelsNotification();
         mSound = calculateSound();
         mVibration = calculateVibration();
         mAttributes = calculateAttributes();
@@ -147,11 +147,27 @@
         mLight = calculateLights();
     }
 
+    private boolean isPreChannelsNotification() {
+        try {
+            if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(getChannel().getId())) {
+                  final ApplicationInfo applicationInfo =
+                        mContext.getPackageManager().getApplicationInfoAsUser(sbn.getPackageName(),
+                                0, UserHandle.getUserId(sbn.getUid()));
+                if (applicationInfo.targetSdkVersion <= Build.VERSION_CODES.N_MR1) {
+                    return true;
+                }
+            }
+        } catch (NameNotFoundException e) {
+            Slog.e(TAG, "Can't find package", e);
+        }
+        return false;
+    }
+
     private Uri calculateSound() {
         final Notification n = sbn.getNotification();
 
         Uri sound = mChannel.getSound();
-        if (!mSupportsChannels && (getChannel().getUserLockedFields()
+        if (mPreChannelsNotification && (getChannel().getUserLockedFields()
                 & NotificationChannel.USER_LOCKED_SOUND) == 0) {
 
             final boolean useDefaultSound = (n.defaults & Notification.DEFAULT_SOUND) != 0;
@@ -176,7 +192,7 @@
                 : defaultLightColor;
         Light light = getChannel().shouldShowLights() ? new Light(channelLightColor,
                 defaultLightOn, defaultLightOff) : null;
-        if (!mSupportsChannels
+        if (mPreChannelsNotification
                 && (getChannel().getUserLockedFields()
                 & NotificationChannel.USER_LOCKED_LIGHTS) == 0) {
             final Notification notification = sbn.getNotification();
@@ -207,7 +223,7 @@
         } else {
             vibration = null;
         }
-        if (!mSupportsChannels
+        if (mPreChannelsNotification
                 && (getChannel().getUserLockedFields()
                 & NotificationChannel.USER_LOCKED_VIBRATION) == 0) {
             final Notification notification = sbn.getNotification();
@@ -229,7 +245,7 @@
             attributes = Notification.AUDIO_ATTRIBUTES_DEFAULT;
         }
 
-        if (!mSupportsChannels
+        if (mPreChannelsNotification
                 && (getChannel().getUserLockedFields()
                 & NotificationChannel.USER_LOCKED_SOUND) == 0) {
             if (n.audioAttributes != null) {
@@ -278,7 +294,7 @@
         stats.requestedImportance = requestedImportance;
         stats.isNoisy = mSound != null || mVibration != null;
 
-        if (!mSupportsChannels
+        if (mPreChannelsNotification
                 && (importance == IMPORTANCE_UNSPECIFIED
                 || (getChannel().getUserLockedFields()
                 & NotificationChannel.USER_LOCKED_IMPORTANCE) == 0)) {
@@ -445,7 +461,7 @@
         pw.println(prefix + "mVisibleSinceMs=" + mVisibleSinceMs);
         pw.println(prefix + "mUpdateTimeMs=" + mUpdateTimeMs);
         pw.println(prefix + "mSuppressedVisualEffects= " + mSuppressedVisualEffects);
-        if (!mSupportsChannels) {
+        if (mPreChannelsNotification) {
             pw.println(prefix + String.format("defaults=0x%08x flags=0x%08x",
                     notification.defaults, notification.flags));
             pw.println(prefix + "n.sound=" + notification.sound);
diff --git a/services/core/java/com/android/server/notification/RankingConfig.java b/services/core/java/com/android/server/notification/RankingConfig.java
index 14d796f..4d19b52 100644
--- a/services/core/java/com/android/server/notification/RankingConfig.java
+++ b/services/core/java/com/android/server/notification/RankingConfig.java
@@ -42,6 +42,4 @@
     void permanentlyDeleteNotificationChannel(String pkg, int uid, String channelId);
     void permanentlyDeleteNotificationChannels(String pkg, int uid);
     ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg, int uid, boolean includeDeleted);
-
-    boolean supportsChannels(String pkg, int uid);
 }
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index 1e741de..7758516 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -273,14 +273,8 @@
     }
 
     private boolean shouldHaveDefaultChannel(Record r) throws NameNotFoundException {
-        if (supportsChannels(r)) {
-            return false;
-        }
-
         final int userId = UserHandle.getUserId(r.uid);
-        final ApplicationInfo applicationInfo = mPm.getApplicationInfoAsUser(r.pkg,
-                PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
-                userId);
+        final ApplicationInfo applicationInfo = mPm.getApplicationInfoAsUser(r.pkg, 0, userId);
         if (applicationInfo.targetSdkVersion > Build.VERSION_CODES.N_MR1) {
             // O apps should not have the default channel.
             return false;
@@ -506,31 +500,6 @@
     }
 
     @Override
-    public boolean supportsChannels(String pkg, int uid) {
-        Record r = getOrCreateRecord(pkg, uid);
-
-        if (r == null) {
-            return false;
-        }
-
-        if (r.channels.size() == 1
-                && r.channels.containsKey(NotificationChannel.DEFAULT_CHANNEL_ID)) {
-            return false;
-        }
-
-        return true;
-    }
-
-    private boolean supportsChannels(Record r) {
-        if (r.channels.size() == 1
-                && r.channels.containsKey(NotificationChannel.DEFAULT_CHANNEL_ID)) {
-            return false;
-        }
-
-        return (r.channels.size() > 0);
-    }
-
-    @Override
     public void createNotificationChannelGroup(String pkg, int uid, NotificationChannelGroup group,
             boolean fromTargetApp) {
         Preconditions.checkNotNull(pkg);
@@ -602,10 +571,6 @@
         r.channels.put(channel.getId(), channel);
         MetricsLogger.action(getChannelLog(channel, pkg).setType(
                 MetricsProto.MetricsEvent.TYPE_OPEN));
-
-        // Remove Default Channel.
-        r.channels.remove(NotificationChannel.DEFAULT_CHANNEL_ID);
-
         updateConfig();
     }
 
@@ -702,7 +667,13 @@
         if (r == null) {
             return;
         }
-        r.channels.clear();
+        int N = r.channels.size() - 1;
+        for (int i = N; i >= 0; i--) {
+            String key = r.channels.keyAt(i);
+            if (!NotificationChannel.DEFAULT_CHANNEL_ID.equals(key)) {
+                r.channels.remove(key);
+            }
+        }
         updateConfig();
     }
 
@@ -1066,8 +1037,6 @@
                 final int uid = uidList[i];
                 synchronized (mRecords) {
                     mRecords.remove(recordKey(pkg, uid));
-                    // reset to default settings and re-add misc channel for pre-O apps
-                    getOrCreateRecord(pkg, uid);
                 }
                 mRestoredWithoutUids.remove(pkg);
                 updated = true;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 55285c8..0173533 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -6498,11 +6498,12 @@
             String resolvedType, int flags, int userId) {
         // first, check to see if we've got an instant app already installed
         final boolean alreadyResolvedLocally = (flags & PackageManager.MATCH_INSTANT) != 0;
-        boolean localInstantAppAvailable = false;
+        ResolveInfo localInstantApp = null;
         boolean blockResolution = false;
         if (!alreadyResolvedLocally) {
             final List<ResolveInfo> instantApps = mActivities.queryIntent(intent, resolvedType,
                     flags
+                        | PackageManager.GET_RESOLVED_FILTER
                         | PackageManager.MATCH_INSTANT
                         | PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY,
                     userId);
@@ -6529,7 +6530,7 @@
                         if (DEBUG_EPHEMERAL) {
                             Slog.v(TAG, "Found installed instant app; pkg: " + packageName);
                         }
-                        localInstantAppAvailable = true;
+                        localInstantApp = info;
                         break;
                     }
                 }
@@ -6537,17 +6538,29 @@
         }
         // no app installed, let's see if one's available
         AuxiliaryResolveInfo auxiliaryResponse = null;
-        if (!localInstantAppAvailable && !blockResolution) {
-            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveEphemeral");
-            final InstantAppRequest requestObject = new InstantAppRequest(
-                    null /*responseObj*/, intent /*origIntent*/, resolvedType,
-                    null /*callingPackage*/, userId, null /*verificationBundle*/);
-            auxiliaryResponse =
-                    InstantAppResolver.doInstantAppResolutionPhaseOne(
-                            mContext, mInstantAppResolverConnection, requestObject);
-            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+        if (!blockResolution) {
+            if (localInstantApp == null) {
+                // we don't have an instant app locally, resolve externally
+                Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveEphemeral");
+                final InstantAppRequest requestObject = new InstantAppRequest(
+                        null /*responseObj*/, intent /*origIntent*/, resolvedType,
+                        null /*callingPackage*/, userId, null /*verificationBundle*/);
+                auxiliaryResponse =
+                        InstantAppResolver.doInstantAppResolutionPhaseOne(
+                                mContext, mInstantAppResolverConnection, requestObject);
+                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+            } else {
+                // we have an instant application locally, but, we can't admit that since
+                // callers shouldn't be able to determine prior browsing. create a dummy
+                // auxiliary response so the downstream code behaves as if there's an
+                // instant application available externally. when it comes time to start
+                // the instant application, we'll do the right thing.
+                final ApplicationInfo ai = localInstantApp.activityInfo.applicationInfo;
+                auxiliaryResponse = new AuxiliaryResolveInfo(
+                        ai.packageName, null /*splitName*/, ai.versionCode, null /*failureIntent*/);
+            }
         }
-        if (localInstantAppAvailable || auxiliaryResponse != null) {
+        if (auxiliaryResponse != null) {
             if (DEBUG_EPHEMERAL) {
                 Slog.v(TAG, "Adding ephemeral installer to the ResolveInfo list");
             }
@@ -6567,7 +6580,7 @@
                 ephemeralInstaller.filter = new IntentFilter(intent.getAction());
                 ephemeralInstaller.filter.addDataPath(
                         intent.getData().getPath(), PatternMatcher.PATTERN_LITERAL);
-                ephemeralInstaller.instantAppAvailable = true;
+                ephemeralInstaller.isInstantAppAvailable = true;
                 result.add(ephemeralInstaller);
             }
         }
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index bed8f1a..7f0528a 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -1611,6 +1611,11 @@
      */
     private void fixUpIncomingShortcutInfo(@NonNull ShortcutInfo shortcut, boolean forUpdate,
             boolean forPinRequest) {
+        if (shortcut.isReturnedByServer()) {
+            Log.w(TAG,
+                    "Re-publishing ShortcutInfo returned by server is not supported."
+                    + " Some information such as icon may lost from shortcut.");
+        }
         Preconditions.checkNotNull(shortcut, "Null shortcut detected");
         if (shortcut.getActivity() != null) {
             Preconditions.checkState(
@@ -1670,6 +1675,13 @@
         }
     }
 
+    private List<ShortcutInfo> setReturnedByServer(List<ShortcutInfo> shortcuts) {
+        for (int i = shortcuts.size() - 1; i >= 0; i--) {
+            shortcuts.get(i).setReturnedByServer();
+        }
+        return shortcuts;
+    }
+
     // === APIs ===
 
     @Override
@@ -2049,7 +2061,7 @@
         final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
         ps.findAll(ret, query, cloneFlags);
 
-        return new ParceledListSlice<>(ret);
+        return new ParceledListSlice<>(setReturnedByServer(ret));
     }
 
     @Override
@@ -2406,7 +2418,7 @@
                     });
                 }
             }
-            return ret;
+            return setReturnedByServer(ret);
         }
 
         private void getShortcutsInnerLocked(int launcherUserId, @NonNull String callingPackage,
diff --git a/services/core/java/com/android/server/storage/DiskStatsLoggingService.java b/services/core/java/com/android/server/storage/DiskStatsLoggingService.java
index 4035ade..9a08ac3 100644
--- a/services/core/java/com/android/server/storage/DiskStatsLoggingService.java
+++ b/services/core/java/com/android/server/storage/DiskStatsLoggingService.java
@@ -73,13 +73,13 @@
         final int userId = UserHandle.myUserId();
         UserEnvironment environment = new UserEnvironment(userId);
         LogRunnable task = new LogRunnable();
-        task.setRootDirectory(environment.getExternalStorageDirectory());
         task.setDownloadsDirectory(
                 environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS));
         task.setSystemSize(FileCollector.getSystemSize(this));
         task.setLogOutputFile(new File(DUMPSYS_CACHE_PATH));
         task.setAppCollector(collector);
         task.setJobService(this, params);
+        task.setContext(this);
         AsyncTask.execute(task);
         return true;
     }
@@ -106,7 +106,8 @@
     }
 
     private static boolean isCharging(Context context) {
-        BatteryManager batteryManager = context.getSystemService(BatteryManager.class);
+        BatteryManager batteryManager =
+                (BatteryManager) context.getSystemService(Context.BATTERY_SERVICE);
         if (batteryManager != null) {
             return batteryManager.isCharging();
         }
@@ -127,14 +128,10 @@
         private JobParameters mParams;
         private AppCollector mCollector;
         private File mOutputFile;
-        private File mRootDirectory;
         private File mDownloadsDirectory;
+        private Context mContext;
         private long mSystemSize;
 
-        public void setRootDirectory(File file) {
-            mRootDirectory = file;
-        }
-
         public void setDownloadsDirectory(File file) {
             mDownloadsDirectory = file;
         }
@@ -151,14 +148,25 @@
             mSystemSize = size;
         }
 
+        public void setContext(Context context) {
+            mContext = context;
+        }
+
         public void setJobService(JobService jobService, JobParameters params) {
             mJobService = jobService;
             mParams = params;
         }
 
         public void run() {
-            FileCollector.MeasurementResult mainCategories =
-                    FileCollector.getMeasurementResult(mRootDirectory);
+            FileCollector.MeasurementResult mainCategories;
+            try {
+                mainCategories = FileCollector.getMeasurementResult(mContext);
+            } catch (IllegalStateException e) {
+                // This can occur if installd has an issue.
+                Log.e(TAG, "Error while measuring storage", e);
+                finishJob(true);
+                return;
+            }
             FileCollector.MeasurementResult downloads =
                     FileCollector.getMeasurementResult(mDownloadsDirectory);
 
@@ -168,12 +176,10 @@
                 needsReschedule = false;
                 logToFile(mainCategories, downloads, stats, mSystemSize);
             } else {
-                Log.w("TAG", "Timed out while fetching package stats.");
+                Log.w(TAG, "Timed out while fetching package stats.");
             }
 
-            if (mJobService != null) {
-                mJobService.jobFinished(mParams, needsReschedule);
-            }
+            finishJob(needsReschedule);
         }
 
         private void logToFile(MeasurementResult mainCategories, MeasurementResult downloads,
@@ -187,5 +193,11 @@
                 Log.e(TAG, "Exception while writing opportunistic disk file cache.", e);
             }
         }
+
+        private void finishJob(boolean needsReschedule) {
+            if (mJobService != null) {
+                mJobService.jobFinished(mParams, needsReschedule);
+            }
+        }
     }
 }
\ No newline at end of file
diff --git a/services/core/java/com/android/server/storage/FileCollector.java b/services/core/java/com/android/server/storage/FileCollector.java
index 90f9f139..0c119a7 100644
--- a/services/core/java/com/android/server/storage/FileCollector.java
+++ b/services/core/java/com/android/server/storage/FileCollector.java
@@ -17,13 +17,17 @@
 package com.android.server.storage;
 
 import android.annotation.IntDef;
+import android.app.usage.ExternalStorageStats;
+import android.app.usage.StorageStatsManager;
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.os.UserHandle;
 import android.os.storage.StorageManager;
 import android.os.storage.VolumeInfo;
 import android.util.ArrayMap;
 
 import java.io.File;
+import java.io.IOException;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.Map;
@@ -154,15 +158,46 @@
     }
 
     /**
+     * Returns the file categorization result for the primary internal storage UUID.
+     *
+     * @param context
+     */
+    public static MeasurementResult getMeasurementResult(Context context) {
+        MeasurementResult result = new MeasurementResult();
+        StorageStatsManager ssm =
+                (StorageStatsManager) context.getSystemService(Context.STORAGE_STATS_SERVICE);
+        ExternalStorageStats stats = null;
+        try {
+            stats =
+                    ssm.queryExternalStatsForUser(
+                            StorageManager.UUID_PRIVATE_INTERNAL,
+                            UserHandle.of(context.getUserId()));
+            result.imagesSize = stats.getImageBytes();
+            result.videosSize = stats.getVideoBytes();
+            result.audioSize = stats.getAudioBytes();
+            result.miscSize =
+                    stats.getTotalBytes()
+                            - result.imagesSize
+                            - result.videosSize
+                            - result.audioSize;
+        } catch (IOException e) {
+            throw new IllegalStateException("Could not query storage");
+        }
+
+        return result;
+    }
+
+    /**
      * Returns the size of a system for a given context. This is done by finding the difference
      * between the shared data and the total primary storage size.
+     *
      * @param context Context to use to get storage information.
      */
     public static long getSystemSize(Context context) {
         PackageManager pm = context.getPackageManager();
         VolumeInfo primaryVolume = pm.getPrimaryStorageCurrentVolume();
 
-        StorageManager sm = context.getSystemService(StorageManager.class);
+        StorageManager sm = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
         VolumeInfo shared = sm.findEmulatedForPrivate(primaryVolume);
         if (shared == null) {
             return 0;
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index 0e183f0..9ef7410 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -39,7 +39,6 @@
 import android.os.Message;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.service.notification.NotificationListenerService;
@@ -47,7 +46,6 @@
 import android.service.vr.IVrListener;
 import android.service.vr.IVrManager;
 import android.service.vr.IVrStateCallbacks;
-import android.service.vr.IVrWindowManager;
 import android.service.vr.VrListenerService;
 import android.text.TextUtils;
 import android.util.ArrayMap;
@@ -440,18 +438,6 @@
         }
 
         @Override
-        public void connectController(FileDescriptor fd) throws android.os.RemoteException {
-            enforceCallerPermission(Manifest.permission.RESTRICTED_VR_ACCESS);
-            VrManagerService.this.connectController(fd);
-        }
-
-        @Override
-        public void disconnectController() throws android.os.RemoteException {
-            enforceCallerPermission(Manifest.permission.RESTRICTED_VR_ACCESS);
-            VrManagerService.this.disconnectController();
-        }
-
-        @Override
         protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
             if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
 
@@ -1184,20 +1170,4 @@
             return mVrModeEnabled;
         }
     }
-
-    private void connectController(FileDescriptor fd) throws android.os.RemoteException {
-        // TODO(b/36506799): move vr_wm code to VrCore and remove this.
-        IVrWindowManager remote =
-                IVrWindowManager.Stub.asInterface(
-                        ServiceManager.getService(IVrWindowManager.SERVICE_NAME));
-        remote.connectController(fd);
-    }
-
-    private void disconnectController() throws android.os.RemoteException {
-        // TODO(b/36506799): move vr_wm code to VrCore and remove this.
-        IVrWindowManager remote =
-                IVrWindowManager.Stub.asInterface(
-                        ServiceManager.getService(IVrWindowManager.SERVICE_NAME));
-        remote.disconnectController();
-    }
 }
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 7a36da2..a38addb 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -54,6 +54,7 @@
 import android.graphics.Bitmap;
 import android.graphics.Path;
 import android.graphics.Rect;
+import android.os.Binder;
 import android.os.Debug;
 import android.os.IBinder;
 import android.os.IRemoteCallback;
@@ -1808,27 +1809,25 @@
             final IAppTransitionAnimationSpecsFuture future
                     = mNextAppTransitionAnimationsSpecsFuture;
             mNextAppTransitionAnimationsSpecsFuture = null;
-            mDefaultExecutor.execute(new Runnable() {
-                @Override
-                public void run() {
-                    AppTransitionAnimationSpec[] specs = null;
-                    try {
-                        specs = future.get();
-                    } catch (RemoteException e) {
-                        Slog.w(TAG, "Failed to fetch app transition specs: " + e);
-                    }
-                    synchronized (mService.mWindowMap) {
-                        mNextAppTransitionAnimationsSpecsPending = false;
-                        overridePendingAppTransitionMultiThumb(specs,
-                                mNextAppTransitionFutureCallback, null /* finishedCallback */,
-                                mNextAppTransitionScaleUp);
-                        mNextAppTransitionFutureCallback = null;
-                        if (specs != null) {
-                            mService.prolongAnimationsFromSpecs(specs, mNextAppTransitionScaleUp);
-                        }
-                    }
-                    mService.requestTraversal();
+            mDefaultExecutor.execute(() -> {
+                AppTransitionAnimationSpec[] specs = null;
+                try {
+                    Binder.allowBlocking(future.asBinder());
+                    specs = future.get();
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Failed to fetch app transition specs: " + e);
                 }
+                synchronized (mService.mWindowMap) {
+                    mNextAppTransitionAnimationsSpecsPending = false;
+                    overridePendingAppTransitionMultiThumb(specs,
+                            mNextAppTransitionFutureCallback, null /* finishedCallback */,
+                            mNextAppTransitionScaleUp);
+                    mNextAppTransitionFutureCallback = null;
+                    if (specs != null) {
+                        mService.prolongAnimationsFromSpecs(specs, mNextAppTransitionScaleUp);
+                    }
+                }
+                mService.requestTraversal();
             });
         }
     }
diff --git a/services/core/jni/com_android_server_lights_LightsService.cpp b/services/core/jni/com_android_server_lights_LightsService.cpp
index 813dcf5..514e996 100644
--- a/services/core/jni/com_android_server_lights_LightsService.cpp
+++ b/services/core/jni/com_android_server_lights_LightsService.cpp
@@ -29,16 +29,46 @@
 
 namespace android {
 
-using ILight     = ::android::hardware::light::V2_0::ILight;
 using Brightness = ::android::hardware::light::V2_0::Brightness;
 using Flash      = ::android::hardware::light::V2_0::Flash;
-using Type       = ::android::hardware::light::V2_0::Type;
+using ILight     = ::android::hardware::light::V2_0::ILight;
 using LightState = ::android::hardware::light::V2_0::LightState;
 using Status     = ::android::hardware::light::V2_0::Status;
+using Type       = ::android::hardware::light::V2_0::Type;
 template<typename T>
 using Return     = ::android::hardware::Return<T>;
 
-static sp<ILight> gLight;
+class LightHal {
+private:
+    static sp<ILight> sLight;
+    static bool sLightInit;
+
+    LightHal() {}
+
+public:
+    static void disassociate() {
+        sLightInit = false;
+        sLight = nullptr;
+    }
+
+    static sp<ILight> associate() {
+        if ((sLight == nullptr && !sLightInit) ||
+                (sLight != nullptr && !sLight->ping().isOk())) {
+            // will return the hal if it exists the first time.
+            sLight = ILight::getService();
+            sLightInit = true;
+
+            if (sLight == nullptr) {
+                ALOGE("Unable to get ILight interface.");
+            }
+        }
+
+        return sLight;
+    }
+};
+
+sp<ILight> LightHal::sLight = nullptr;
+bool LightHal::sLightInit = false;
 
 static bool validate(jint light, jint flash, jint brightness) {
     bool valid = true;
@@ -103,7 +133,7 @@
         const LightState &state) {
     if (!ret.isOk()) {
         ALOGE("Failed to issue set light command.");
-        gLight = nullptr;
+        LightHal::disassociate();
         return;
     }
 
@@ -137,12 +167,9 @@
         return;
     }
 
-    if (gLight == nullptr || !gLight->ping().isOk()) {
-        gLight = ILight::getService();
-    }
+    sp<ILight> hal = LightHal::associate();
 
-    if (gLight == nullptr) {
-        ALOGE("Unable to get ILight interface.");
+    if (hal == nullptr) {
         return;
     }
 
@@ -152,7 +179,7 @@
 
     {
         ALOGD_IF_SLOW(50, "Excessive delay setting light");
-        Return<Status> ret = gLight->setLight(type, state);
+        Return<Status> ret = hal->setLight(type, state);
         processReturn(ret, type, state);
     }
 }
diff --git a/services/tests/notification/src/com/android/server/notification/BadgeExtractorTest.java b/services/tests/notification/src/com/android/server/notification/BadgeExtractorTest.java
index 2e8b068..0cf4994 100644
--- a/services/tests/notification/src/com/android/server/notification/BadgeExtractorTest.java
+++ b/services/tests/notification/src/com/android/server/notification/BadgeExtractorTest.java
@@ -69,7 +69,7 @@
         Notification n = builder.build();
         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, mId, mTag, mUid,
                 mPid, n, mUser, null, System.currentTimeMillis());
-        NotificationRecord r = new NotificationRecord(getContext(), sbn, channel, true);
+        NotificationRecord r = new NotificationRecord(getContext(), sbn, channel);
         return r;
     }
 
diff --git a/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
index 5e8b3d4..d4904f5 100644
--- a/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -259,7 +259,7 @@
 
         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, id, mTag, mUid,
                 mPid, n, mUser, null, System.currentTimeMillis());
-        NotificationRecord r = new NotificationRecord(getContext(), sbn, channel, true);
+        NotificationRecord r = new NotificationRecord(getContext(), sbn, channel);
         mService.addNotification(r);
         return r;
     }
@@ -769,7 +769,7 @@
 
         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 0, mTag, mUid,
                 mPid, n, mUser, null, System.currentTimeMillis());
-        NotificationRecord r = new NotificationRecord(getContext(), sbn, channel, true);
+        NotificationRecord r = new NotificationRecord(getContext(), sbn, channel);
         mService.addNotification(r);
 
         mService.buzzBeepBlinkLocked(r);
diff --git a/services/tests/notification/src/com/android/server/notification/GlobalSortKeyComparatorTest.java b/services/tests/notification/src/com/android/server/notification/GlobalSortKeyComparatorTest.java
index 33d2d07..24cb72e 100644
--- a/services/tests/notification/src/com/android/server/notification/GlobalSortKeyComparatorTest.java
+++ b/services/tests/notification/src/com/android/server/notification/GlobalSortKeyComparatorTest.java
@@ -53,21 +53,21 @@
                 new StatusBarNotification(PKG,
                         PKG, 1, "media", UID, UID, n,
                         new UserHandle(UserHandle.myUserId()),
-                        "", 1499), getDefaultChannel(), true);
+                        "", 1499), getDefaultChannel());
         left.setGlobalSortKey("first");
 
         NotificationRecord right = new NotificationRecord(InstrumentationRegistry.getContext(),
                 new StatusBarNotification(PKG,
                         PKG, 1, "media", UID, UID, n,
                         new UserHandle(UserHandle.myUserId()),
-                        "", 1499), getDefaultChannel(), true);
+                        "", 1499), getDefaultChannel());
         right.setGlobalSortKey("second");
 
         NotificationRecord last = new NotificationRecord(InstrumentationRegistry.getContext(),
                 new StatusBarNotification(PKG,
                         PKG, 1, "media", UID, UID, n,
                         new UserHandle(UserHandle.myUserId()),
-                        "", 1499), getDefaultChannel(), true);
+                        "", 1499), getDefaultChannel());
 
 
         final List<NotificationRecord> expected = new ArrayList<>();
@@ -93,13 +93,13 @@
                 new StatusBarNotification(PKG,
                         PKG, 1, "media", UID, UID, n,
                         new UserHandle(UserHandle.myUserId()),
-                        "", 1499), getDefaultChannel(), true);
+                        "", 1499), getDefaultChannel());
 
         NotificationRecord right = new NotificationRecord(InstrumentationRegistry.getContext(),
                 new StatusBarNotification(PKG,
                         PKG, 1, "media", UID, UID, n,
                         new UserHandle(UserHandle.myUserId()),
-                        "", 1499), getDefaultChannel(), true);
+                        "", 1499), getDefaultChannel());
         right.setGlobalSortKey("not null");
 
         final List<NotificationRecord> expected = new ArrayList<>();
@@ -124,14 +124,14 @@
                 new StatusBarNotification(PKG,
                         PKG, 1, "media", UID, UID, n,
                         new UserHandle(UserHandle.myUserId()),
-                        "", 1499), getDefaultChannel(), true);
+                        "", 1499), getDefaultChannel());
         left.setGlobalSortKey("not null");
 
         NotificationRecord right = new NotificationRecord(InstrumentationRegistry.getContext(),
                 new StatusBarNotification(PKG,
                         PKG, 1, "media", UID, UID, n,
                         new UserHandle(UserHandle.myUserId()),
-                        "", 1499), getDefaultChannel(), true);
+                        "", 1499), getDefaultChannel());
 
         final List<NotificationRecord> expected = new ArrayList<>();
         expected.add(left);
diff --git a/services/tests/notification/src/com/android/server/notification/ImportanceExtractorTest.java b/services/tests/notification/src/com/android/server/notification/ImportanceExtractorTest.java
index 7a2dbaf..3dbd803 100644
--- a/services/tests/notification/src/com/android/server/notification/ImportanceExtractorTest.java
+++ b/services/tests/notification/src/com/android/server/notification/ImportanceExtractorTest.java
@@ -71,7 +71,7 @@
         Notification n = builder.build();
         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, mId, mTag, mUid,
                 mPid, n, mUser, null, System.currentTimeMillis());
-        NotificationRecord r = new NotificationRecord(getContext(), sbn, channel, true);
+        NotificationRecord r = new NotificationRecord(getContext(), sbn, channel);
         return r;
     }
 
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java b/services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java
index ccd2db0..84945ab 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java
@@ -108,7 +108,7 @@
                 .build();
         mRecordMinCall = new NotificationRecord(mContext, new StatusBarNotification(callPkg,
                 callPkg, 1, "minCall", callUid, callUid, n1,
-                new UserHandle(userId), "", 2000), getDefaultChannel(), false);
+                new UserHandle(userId), "", 2000), getDefaultChannel());
         mRecordMinCall.setUserImportance(NotificationManager.IMPORTANCE_MIN);
 
         Notification n2 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
@@ -118,7 +118,7 @@
                 .build();
         mRecordHighCall = new NotificationRecord(mContext, new StatusBarNotification(callPkg,
                 callPkg, 1, "highcall", callUid, callUid, n2,
-                new UserHandle(userId), "", 1999), getDefaultChannel(), false);
+                new UserHandle(userId), "", 1999), getDefaultChannel());
         mRecordHighCall.setUserImportance(NotificationManager.IMPORTANCE_HIGH);
 
         Notification n3 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
@@ -128,14 +128,14 @@
                 .build();
         mRecordDefaultMedia = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
                 pkg2, 1, "media", uid2, uid2, n3, new UserHandle(userId),
-                "", 1499), getDefaultChannel(), false);
+                "", 1499), getDefaultChannel());
         mRecordDefaultMedia.setUserImportance(NotificationManager.IMPORTANCE_DEFAULT);
 
         Notification n4 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
                 .setStyle(new Notification.MessagingStyle("sender!")).build();
         mRecordInlineReply = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
                 pkg2, 1, "inlinereply", uid2, uid2, n4, new UserHandle(userId),
-                "", 1599), getDefaultChannel(), false);
+                "", 1599), getDefaultChannel());
         mRecordInlineReply.setUserImportance(NotificationManager.IMPORTANCE_HIGH);
         mRecordInlineReply.setPackagePriority(Notification.PRIORITY_MAX);
 
@@ -143,27 +143,27 @@
                 .setCategory(Notification.CATEGORY_MESSAGE).build();
         mRecordSms = new NotificationRecord(mContext, new StatusBarNotification(smsPkg,
                 smsPkg, 1, "sms", smsUid, smsUid, n5, new UserHandle(userId),
-                "", 1299), getDefaultChannel(), false);
+                "", 1299), getDefaultChannel());
         mRecordSms.setUserImportance(NotificationManager.IMPORTANCE_DEFAULT);
 
         Notification n6 = new Notification.Builder(mContext, TEST_CHANNEL_ID).build();
         mRecordStarredContact = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
                 pkg2, 1, "starred", uid2, uid2, n6, new UserHandle(userId),
-                "", 1259), getDefaultChannel(), false);
+                "", 1259), getDefaultChannel());
         mRecordStarredContact.setContactAffinity(ValidateNotificationPeople.STARRED_CONTACT);
         mRecordStarredContact.setUserImportance(NotificationManager.IMPORTANCE_DEFAULT);
 
         Notification n7 = new Notification.Builder(mContext, TEST_CHANNEL_ID).build();
         mRecordContact = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
                 pkg2, 1, "contact", uid2, uid2, n7, new UserHandle(userId),
-                "", 1259), getDefaultChannel(), false);
+                "", 1259), getDefaultChannel());
         mRecordContact.setContactAffinity(ValidateNotificationPeople.VALID_CONTACT);
         mRecordContact.setUserImportance(NotificationManager.IMPORTANCE_DEFAULT);
 
         Notification n8 = new Notification.Builder(mContext, TEST_CHANNEL_ID).build();
         mRecordUrgent = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
                 pkg2, 1, "urgent", uid2, uid2, n8, new UserHandle(userId),
-                "", 1258), getDefaultChannel(), false);
+                "", 1258), getDefaultChannel());
         mRecordUrgent.setUserImportance(NotificationManager.IMPORTANCE_HIGH);
 
         Notification n9 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
@@ -173,7 +173,7 @@
                 .build();
         mRecordCheater = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
                 pkg2, 1, "cheater", uid2, uid2, n9, new UserHandle(userId),
-                "", 9258), getDefaultChannel(), false);
+                "", 9258), getDefaultChannel());
         mRecordCheater.setUserImportance(NotificationManager.IMPORTANCE_LOW);
         mRecordCheater.setPackagePriority(Notification.PRIORITY_MAX);
 
@@ -181,7 +181,7 @@
                 .setStyle(new Notification.InboxStyle().setSummaryText("message!")).build();
         mRecordEmail = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
                 pkg2, 1, "email", uid2, uid2, n10, new UserHandle(userId),
-                "", 1599), getDefaultChannel(), false);
+                "", 1599), getDefaultChannel());
         mRecordEmail.setUserImportance(NotificationManager.IMPORTANCE_HIGH);
 
         Notification n11 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
@@ -190,7 +190,7 @@
                 .build();
         mRecordCheaterColorized = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
                 pkg2, 1, "cheater", uid2, uid2, n11, new UserHandle(userId),
-                "", 9258), getDefaultChannel(), false);
+                "", 9258), getDefaultChannel());
         mRecordCheaterColorized.setUserImportance(NotificationManager.IMPORTANCE_LOW);
     }
 
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
index f3eb4f8..177c02d 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -165,7 +165,7 @@
 
         StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, id, "tag", uid, 0,
                 nb.build(), new UserHandle(uid), null, 0);
-        return new NotificationRecord(mContext, sbn, channel, true);
+        return new NotificationRecord(mContext, sbn, channel);
     }
     private NotificationRecord generateNotificationRecord(NotificationChannel channel) {
         return generateNotificationRecord(channel, null);
@@ -184,7 +184,7 @@
         }
         StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, "tag", uid, 0,
                 nb.build(), new UserHandle(uid), null, 0);
-        return new NotificationRecord(mContext, sbn, channel, true);
+        return new NotificationRecord(mContext, sbn, channel);
     }
 
     @Test
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java b/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java
index 66f3799..1c8ca84 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java
@@ -21,6 +21,7 @@
 import static junit.framework.Assert.assertNull;
 import static junit.framework.Assert.assertTrue;
 
+import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.when;
 
@@ -60,10 +61,6 @@
     private final Context mMockContext = Mockito.mock(Context.class);
     @Mock PackageManager mPm;
 
-    // constants for targetSdk version. N is pre channels, O is post.
-    private final boolean N = false;
-    private final boolean O = true;
-
     private final String pkg = "com.android.server.notification";
     private final int uid = 9583;
     private final String pkg2 = "pkg2";
@@ -79,6 +76,7 @@
             new NotificationChannel(NotificationChannel.DEFAULT_CHANNEL_ID, "test",
                     NotificationManager.IMPORTANCE_UNSPECIFIED);
     private android.os.UserHandle mUser = UserHandle.of(ActivityManager.getCurrentUser());
+    final ApplicationInfo legacy = new ApplicationInfo();
     final ApplicationInfo upgrade = new ApplicationInfo();
 
     private static final long[] CUSTOM_VIBRATION = new long[] {
@@ -102,13 +100,17 @@
                 InstrumentationRegistry.getContext().getResources());
         when(mMockContext.getPackageManager()).thenReturn(mPm);
 
+        legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1;
         upgrade.targetSdkVersion = Build.VERSION_CODES.N_MR1 + 1;
-        when(mMockContext.getApplicationInfo()).thenReturn(upgrade);
+        try {
+            when(mPm.getApplicationInfoAsUser(eq(pkg), anyInt(), anyInt())).thenReturn(legacy);
+            when(mPm.getApplicationInfoAsUser(eq(pkg2), anyInt(), anyInt())).thenReturn(upgrade);
+        } catch (PackageManager.NameNotFoundException e) {}
     }
 
-    private StatusBarNotification getNotification(boolean supportsChannels, boolean noisy,
-            boolean defaultSound, boolean buzzy, boolean defaultVibration, boolean lights,
-            boolean defaultLights) {
+    private StatusBarNotification getNotification(boolean preO, boolean noisy, boolean defaultSound,
+            boolean buzzy, boolean defaultVibration, boolean lights, boolean defaultLights) {
+        when(mMockContext.getApplicationInfo()).thenReturn(preO ? legacy : upgrade);
         final Builder builder = new Builder(mMockContext)
                 .setContentTitle("foo")
                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
@@ -147,13 +149,13 @@
         }
 
         builder.setDefaults(defaults);
-        if (supportsChannels) {
+        if (!preO) {
             builder.setChannelId(channelId);
         }
 
 
         Notification n = builder.build();
-        if (!supportsChannels) {
+        if (preO) {
             return new StatusBarNotification(pkg, pkg, id1, tag1, uid, uid, n,
                     mUser, null, uid);
         } else {
@@ -170,11 +172,11 @@
     public void testSound_default_preUpgradeUsesNotification() throws Exception {
         defaultChannel.setSound(null, null);
         // pre upgrade, default sound.
-        StatusBarNotification sbn = getNotification(N, true /* noisy */,
+        StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /*defaultLights */);
 
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
         assertEquals(Settings.System.DEFAULT_NOTIFICATION_URI, record.getSound());
         assertEquals(Notification.AUDIO_ATTRIBUTES_DEFAULT, record.getAudioAttributes());
     }
@@ -183,11 +185,11 @@
     public void testSound_custom_preUpgradeUsesNotification() throws Exception {
         defaultChannel.setSound(null, null);
         // pre upgrade, custom sound.
-        StatusBarNotification sbn = getNotification(N, true /* noisy */,
+        StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
                 false /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /*defaultLights */);
 
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
         assertEquals(CUSTOM_SOUND, record.getSound());
         assertEquals(CUSTOM_ATTRIBUTES, record.getAudioAttributes());
     }
@@ -197,11 +199,11 @@
         defaultChannel.setSound(CUSTOM_SOUND, CUSTOM_ATTRIBUTES);
         defaultChannel.lockFields(NotificationChannel.USER_LOCKED_SOUND);
         // pre upgrade, default sound.
-        StatusBarNotification sbn = getNotification(N, true /* noisy */,
+        StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /*defaultLights */);
 
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
         assertEquals(CUSTOM_SOUND, record.getSound());
         assertEquals(CUSTOM_ATTRIBUTES, record.getAudioAttributes());
     }
@@ -209,11 +211,11 @@
     @Test
     public void testSound_noSound_preUpgrade() throws Exception {
         // pre upgrade, default sound.
-        StatusBarNotification sbn = getNotification(N, false /* noisy */,
+        StatusBarNotification sbn = getNotification(true /*preO */, false /* noisy */,
                 false /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /*defaultLights */);
 
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
         assertEquals(null, record.getSound());
         assertEquals(Notification.AUDIO_ATTRIBUTES_DEFAULT, record.getAudioAttributes());
     }
@@ -222,11 +224,11 @@
     public void testSound_default_upgradeUsesChannel() throws Exception {
         channel.setSound(CUSTOM_SOUND, CUSTOM_ATTRIBUTES);
         // post upgrade, default sound.
-        StatusBarNotification sbn = getNotification(O, true /* noisy */,
+        StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /*defaultLights */);
 
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel, O);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
         assertEquals(CUSTOM_SOUND, record.getSound());
         assertEquals(CUSTOM_ATTRIBUTES, record.getAudioAttributes());
     }
@@ -235,11 +237,11 @@
     public void testVibration_default_preUpgradeUsesNotification() throws Exception {
         defaultChannel.enableVibration(false);
         // pre upgrade, default vibration.
-        StatusBarNotification sbn = getNotification(N, false /* noisy */,
+        StatusBarNotification sbn = getNotification(true /*preO */, false /* noisy */,
                 false /* defaultSound */, true /* buzzy */, true /* defaultBuzz */,
                 false /* lights */, false /*defaultLights */);
 
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
         assertNotNull(record.getVibration());
     }
 
@@ -247,11 +249,11 @@
     public void testVibration_custom_preUpgradeUsesNotification() throws Exception {
         defaultChannel.enableVibration(false);
         // pre upgrade, custom vibration.
-        StatusBarNotification sbn = getNotification(N, false /* noisy */,
+        StatusBarNotification sbn = getNotification(true /*preO */, false /* noisy */,
                 false /* defaultSound */, true /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /*defaultLights */);
 
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
         assertEquals(CUSTOM_VIBRATION, record.getVibration());
     }
 
@@ -260,11 +262,11 @@
         defaultChannel.enableVibration(true);
         defaultChannel.lockFields(NotificationChannel.USER_LOCKED_VIBRATION);
         // pre upgrade, custom vibration.
-        StatusBarNotification sbn = getNotification(N, false /* noisy */,
+        StatusBarNotification sbn = getNotification(true /*preO */, false /* noisy */,
                 false /* defaultSound */, true /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /*defaultLights */);
 
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
         assertTrue(!Objects.equals(CUSTOM_VIBRATION, record.getVibration()));
     }
 
@@ -272,20 +274,20 @@
     public void testVibration_custom_upgradeUsesChannel() throws Exception {
         channel.enableVibration(true);
         // post upgrade, custom vibration.
-        StatusBarNotification sbn = getNotification(O, false /* noisy */,
+        StatusBarNotification sbn = getNotification(false /*preO */, false /* noisy */,
                 false /* defaultSound */, true /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /*defaultLights */);
 
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel, O);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
         assertEquals(CUSTOM_CHANNEL_VIBRATION, record.getVibration());
     }
 
     @Test
     public void testImportance_preUpgrade() throws Exception {
-        StatusBarNotification sbn = getNotification(N, true /* noisy */,
+        StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /*defaultLights */);
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
         assertEquals(NotificationManager.IMPORTANCE_HIGH, record.getImportance());
     }
 
@@ -293,11 +295,11 @@
     public void testImportance_locked_preUpgrade() throws Exception {
         defaultChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
         defaultChannel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
-        StatusBarNotification sbn = getNotification(N, true /* noisy */,
+        StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /*defaultLights */);
 
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
         assertEquals(NotificationManager.IMPORTANCE_LOW, record.getImportance());
     }
 
@@ -305,39 +307,39 @@
     public void testImportance_locked_unspecified_preUpgrade() throws Exception {
         defaultChannel.setImportance(NotificationManager.IMPORTANCE_UNSPECIFIED);
         defaultChannel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
-        StatusBarNotification sbn = getNotification(N, true /* noisy */,
+        StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /*defaultLights */);
 
-        NotificationRecord record =  new NotificationRecord(mMockContext, sbn, defaultChannel, N);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
         assertEquals(NotificationManager.IMPORTANCE_HIGH, record.getImportance());
     }
 
     @Test
     public void testImportance_upgrade() throws Exception {
-        StatusBarNotification sbn = getNotification(O, true /* noisy */,
+        StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /*defaultLights */);
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel, O);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
         assertEquals(NotificationManager.IMPORTANCE_DEFAULT, record.getImportance());
     }
 
     @Test
     public void testLights_preUpgrade_noLight() throws Exception {
-        StatusBarNotification sbn = getNotification(N, true /* noisy */,
+        StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /*defaultLights */);
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
         assertNull(record.getLight());
     }
 
 
     @Test
     public void testLights_preUpgrade() throws Exception {
-        StatusBarNotification sbn = getNotification(N, true /* noisy */,
+        StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 true /* lights */, false /*defaultLights */);
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
         assertEquals(CUSTOM_LIGHT, record.getLight());
     }
 
@@ -345,11 +347,11 @@
     public void testLights_locked_preUpgrade() throws Exception {
         defaultChannel.enableLights(true);
         defaultChannel.lockFields(NotificationChannel.USER_LOCKED_LIGHTS);
-        StatusBarNotification sbn = getNotification(N, true /* noisy */,
+        StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 true /* lights */, false /*defaultLights */);
 
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
         assertFalse(CUSTOM_LIGHT.equals(record.getLight()));
     }
 
@@ -364,10 +366,10 @@
 
         NotificationRecord.Light expected = new NotificationRecord.Light(
                 defaultLightColor, defaultLightOn, defaultLightOff);
-        StatusBarNotification sbn = getNotification(O, true /* noisy */,
+        StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 true /* lights */, true /*defaultLights */);
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel, O);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
         assertEquals(expected, record.getLight());
     }
 
@@ -380,19 +382,19 @@
 
         NotificationRecord.Light expected = new NotificationRecord.Light(
                 Color.BLUE, defaultLightOn, defaultLightOff);
-        StatusBarNotification sbn = getNotification(O, true /* noisy */,
+        StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 true /* lights */, false /*defaultLights */);
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel, O);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
         assertEquals(expected, record.getLight());
     }
 
     @Test
     public void testLights_upgrade_noLight() throws Exception {
-        StatusBarNotification sbn = getNotification(O, true /* noisy */,
+        StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /*defaultLights */);
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, O);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
         assertNull(record.getLight());
     }
 }
diff --git a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
index 8ab6d08..7bef033 100644
--- a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
@@ -124,7 +124,7 @@
                 .build();
         mRecordGroupGSortA = new NotificationRecord(getContext(), new StatusBarNotification(
                 "package", "package", 1, null, 0, 0, mNotiGroupGSortA, user,
-                null, System.currentTimeMillis()), getDefaultChannel(), false);
+                null, System.currentTimeMillis()), getDefaultChannel());
 
         mNotiGroupGSortB = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
                 .setContentTitle("B")
@@ -134,7 +134,7 @@
                 .build();
         mRecordGroupGSortB = new NotificationRecord(getContext(), new StatusBarNotification(
                 "package", "package", 1, null, 0, 0, mNotiGroupGSortB, user,
-                null, System.currentTimeMillis()), getDefaultChannel(), false);
+                null, System.currentTimeMillis()), getDefaultChannel());
 
         mNotiNoGroup = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
                 .setContentTitle("C")
@@ -142,7 +142,7 @@
                 .build();
         mRecordNoGroup = new NotificationRecord(getContext(), new StatusBarNotification(
                 "package", "package", 1, null, 0, 0, mNotiNoGroup, user,
-                null, System.currentTimeMillis()), getDefaultChannel(), false);
+                null, System.currentTimeMillis()), getDefaultChannel());
 
         mNotiNoGroup2 = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
                 .setContentTitle("D")
@@ -150,7 +150,7 @@
                 .build();
         mRecordNoGroup2 = new NotificationRecord(getContext(), new StatusBarNotification(
                 "package", "package", 1, null, 0, 0, mNotiNoGroup2, user,
-                null, System.currentTimeMillis()), getDefaultChannel(), false);
+                null, System.currentTimeMillis()), getDefaultChannel());
 
         mNotiNoGroupSortA = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
                 .setContentTitle("E")
@@ -159,7 +159,7 @@
                 .build();
         mRecordNoGroupSortA = new NotificationRecord(getContext(), new StatusBarNotification(
                 "package", "package", 1, null, 0, 0, mNotiNoGroupSortA, user,
-                null, System.currentTimeMillis()), getDefaultChannel(), false);
+                null, System.currentTimeMillis()), getDefaultChannel());
 
         mAudioAttributes = new AudioAttributes.Builder()
                 .setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN)
@@ -373,7 +373,7 @@
         assertNull(mHelper.getNotificationChannel(PKG, UID, channel1.getId(), false));
         assertNull(mHelper.getNotificationChannel(PKG, UID, channel3.getId(), false));
         assertNull(mHelper.getNotificationChannelGroup(ncg.getId(), PKG, UID));
-        assertEquals(ncg2, mHelper.getNotificationChannelGroup(ncg2.getId(), PKG, UID));
+        //assertEquals(ncg2, mHelper.getNotificationChannelGroup(ncg2.getId(), PKG, UID));
         assertEquals(channel2, mHelper.getNotificationChannel(PKG, UID, channel2.getId(), false));
     }
 
@@ -696,14 +696,20 @@
         // Returns only non-deleted channels
         List<NotificationChannel> channels =
                 mHelper.getNotificationChannels(PKG, UID, false).getList();
-        assertEquals(1, channels.size());
-        compareChannels(channel2, channels.get(0));
+        assertEquals(2, channels.size());   // Default channel + non-deleted channel
+        for (NotificationChannel nc : channels) {
+            if (!NotificationChannel.DEFAULT_CHANNEL_ID.equals(nc.getId())) {
+                compareChannels(channel2, nc);
+            }
+        }
 
         // Returns deleted channels too
         channels = mHelper.getNotificationChannels(PKG, UID, true).getList();
-        assertEquals(2, channels.size());
+        assertEquals(3, channels.size());               // Includes default channel
         for (NotificationChannel nc : channels) {
-            compareChannels(channelMap.get(nc.getId()), nc);
+            if (!NotificationChannel.DEFAULT_CHANNEL_ID.equals(nc.getId())) {
+                compareChannels(channelMap.get(nc.getId()), nc);
+            }
         }
     }
 
@@ -801,8 +807,8 @@
 
         mHelper.permanentlyDeleteNotificationChannels(PKG, UID);
 
-        // No channels remain
-        assertEquals(0, mHelper.getNotificationChannels(PKG, UID, true).getList().size());
+        // Only default channel remains
+        assertEquals(1, mHelper.getNotificationChannels(PKG, UID, true).getList().size());
     }
 
     @Test
@@ -881,32 +887,13 @@
 
         mHelper.onPackagesChanged(true, UserHandle.USER_SYSTEM, new String[]{PKG}, new int[]{UID});
 
-        // since this is a pre upgrade app, clearing data should restore the default channel
-        assertEquals(1, mHelper.getNotificationChannels(PKG, UID, true).getList().size());
-        assertEquals(NotificationChannel.DEFAULT_CHANNEL_ID,
-                mHelper.getNotificationChannels(PKG, UID, true).getList().get(0).getId());
+        assertEquals(0, mHelper.getNotificationChannels(PKG, UID, true).getList().size());
 
         // Not deleted
         mHelper.createNotificationChannel(PKG, UID, channel1, true);
+
         mHelper.onPackagesChanged(false, UserHandle.USER_SYSTEM, new String[]{PKG}, new int[]{UID});
-        assertEquals(1, mHelper.getNotificationChannels(PKG, UID, false).getList().size());
-    }
-
-    @Test
-    public void testOnPackageChanged_packageRemoval_updatedPackage() throws Exception {
-        // Deleted
-        NotificationChannel channel1 =
-                new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
-        mHelper.createNotificationChannel(UPDATED_PKG, UID2, channel1, true);
-        mHelper.onPackagesChanged(
-                true, UserHandle.USER_SYSTEM, new String[]{UPDATED_PKG}, new int[]{UID2});
-        assertEquals(0, mHelper.getNotificationChannels(UPDATED_PKG, UID2, true).getList().size());
-
-        // Not deleted
-        mHelper.createNotificationChannel(UPDATED_PKG, UID2, channel1, true);
-        mHelper.onPackagesChanged(
-                false, UserHandle.USER_SYSTEM, new String[]{UPDATED_PKG}, new int[]{UID2});
-        assertEquals(1, mHelper.getNotificationChannels(UPDATED_PKG, UID2, false).getList().size());
+        assertEquals(2, mHelper.getNotificationChannels(PKG, UID, false).getList().size());
     }
 
     @Test
@@ -927,23 +914,7 @@
 
         mHelper.onPackagesChanged(true, UserHandle.USER_SYSTEM, new String[]{PKG}, new int[]{UID});
 
-        // default channel restored
-        assertEquals(1, mHelper.getNotificationChannelGroups(PKG, UID, true).getList().size());
-        assertNull(mHelper.getNotificationChannelGroups(PKG, UID, true).getList().get(0).getId());
-    }
-
-    @Test
-    public void testOnPackageChanged_packageRemoval_groups_upgraded() throws Exception {
-        NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
-        mHelper.createNotificationChannelGroup(UPDATED_PKG, UID2, ncg, true);
-        NotificationChannelGroup ncg2 = new NotificationChannelGroup("group2", "name2");
-        mHelper.createNotificationChannelGroup(UPDATED_PKG, UID2, ncg2, true);
-
-        mHelper.onPackagesChanged(
-                true, UserHandle.USER_SYSTEM, new String[]{UPDATED_PKG}, new int[]{UID2});
-
-        assertEquals(0,
-                mHelper.getNotificationChannelGroups(UPDATED_PKG, UID2, true).getList().size());
+        assertEquals(0, mHelper.getNotificationChannelGroups(PKG, UID, true).getList().size());
     }
 
     @Test
@@ -1017,8 +988,9 @@
         assertEquals(3, actual.size());
         for (NotificationChannelGroup group : actual) {
             if (group.getId() == null) {
-                assertEquals(1, group.getChannels().size());
-                assertTrue(channel3.getId().equals(group.getChannels().get(0).getId()));
+                assertEquals(2, group.getChannels().size()); // misc channel too
+                assertTrue(channel3.getId().equals(group.getChannels().get(0).getId())
+                        || channel3.getId().equals(group.getChannels().get(1).getId()));
             } else if (group.getId().equals(ncg.getId())) {
                 assertEquals(2, group.getChannels().size());
                 if (group.getChannels().get(0).getId().equals(channel1.getId())) {
@@ -1052,8 +1024,12 @@
         List<NotificationChannelGroup> actual =
                 mHelper.getNotificationChannelGroups(PKG, UID, true).getList();
 
-        assertEquals(1, actual.size());
-        assertEquals(1, actual.get(0).getChannels().size());
+        assertEquals(2, actual.size());
+        for (NotificationChannelGroup group : actual) {
+            if (Objects.equals(group.getId(), ncg.getId())) {
+                assertEquals(1, group.getChannels().size());
+            }
+        }
     }
 
     @Test
diff --git a/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java b/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java
index b1cb4d7..bc25860 100644
--- a/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java
@@ -312,7 +312,7 @@
                 TEST_CHANNEL_ID, "name", NotificationManager.IMPORTANCE_LOW);
         return new NotificationRecord(getContext(), new StatusBarNotification(
                 pkg, pkg, id, tag, 0, 0, n, user, null,
-                System.currentTimeMillis()), notificationChannel, true);
+                System.currentTimeMillis()), notificationChannel);
     }
 
     private NotificationRecord getNotificationRecord(String pkg, int id, String tag,
diff --git a/services/tests/servicestests/src/com/android/server/NightDisplayServiceTest.java b/services/tests/servicestests/src/com/android/server/NightDisplayServiceTest.java
index 9a9c243..58a4456 100644
--- a/services/tests/servicestests/src/com/android/server/NightDisplayServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NightDisplayServiceTest.java
@@ -16,10 +16,12 @@
 
 package com.android.server;
 
+import android.annotation.NonNull;
 import android.app.ActivityManager;
 import android.app.AlarmManager;
 import android.content.Context;
 import android.content.ContextWrapper;
+import android.os.Handler;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.provider.Settings.Secure;
@@ -32,6 +34,7 @@
 import com.android.internal.util.test.FakeSettingsProvider;
 import com.android.server.display.DisplayTransformManager;
 import com.android.server.display.NightDisplayService;
+import com.android.server.twilight.TwilightListener;
 import com.android.server.twilight.TwilightManager;
 import com.android.server.twilight.TwilightState;
 import org.junit.After;
@@ -41,6 +44,10 @@
 import org.mockito.Mockito;
 
 import java.util.Calendar;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
 import static com.google.common.truth.Truth.assertWithMessage;
 import static org.mockito.Mockito.doReturn;
@@ -51,7 +58,7 @@
     private Context mContext;
     private int mUserId;
 
-    private TwilightManager mTwilightManager;
+    private MockTwilightManager mTwilightManager;
 
     private NightDisplayController mNightDisplayController;
     private NightDisplayService mNightDisplayService;
@@ -73,7 +80,7 @@
         final DisplayTransformManager dtm = Mockito.mock(DisplayTransformManager.class);
         LocalServices.addService(DisplayTransformManager.class, dtm);
 
-        mTwilightManager = Mockito.mock(TwilightManager.class);
+        mTwilightManager = new MockTwilightManager();
         LocalServices.addService(TwilightManager.class, mTwilightManager);
 
         mNightDisplayController = new NightDisplayController(mContext, mUserId);
@@ -526,23 +533,371 @@
         assertActivated(true /* activated */);
     }
 
-    /**
-     * Convenience for making a {@link LocalTime} instance with an offset relative to now.
-     *
-     * @param offsetMinutes the offset relative to now (in minutes)
-     * @return the LocalTime instance
-     */
-    private LocalTime getLocalTimeRelativeToNow(int offsetMinutes) {
-        final Calendar c = Calendar.getInstance();
-        c.add(Calendar.MINUTE, offsetMinutes);
-        return new LocalTime(c.get(Calendar.HOUR_OF_DAY), c.get(Calendar.MINUTE));
+    @Test
+    public void twilightSchedule_whenRebootedAfterNight_ifOffAfterNight_turnsOff() {
+        setAutoModeTwilight(-120 /* sunsetOffset */, -60 /* sunriseOffset */);
+        setActivated(false /* activated */, -30 /* lastActivatedTimeOffset */);
+
+        final TwilightState state = mTwilightManager.getLastTwilightState();
+        mTwilightManager.setTwilightState(null);
+
+        startService();
+        assertActivated(false /* activated */);
+
+        mTwilightManager.setTwilightState(state);
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenRebootedAfterNight_ifOffBeforeNight_turnsOff() {
+        setAutoModeTwilight(-120 /* sunsetOffset */, -60 /* sunriseOffset */);
+        setActivated(false /* activated */, -180 /* lastActivatedTimeOffset */);
+
+        final TwilightState state = mTwilightManager.getLastTwilightState();
+        mTwilightManager.setTwilightState(null);
+
+        startService();
+        assertActivated(false /* activated */);
+
+        mTwilightManager.setTwilightState(state);
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenRebootedAfterNight_ifOffDuringNight_turnsOff() {
+        setAutoModeTwilight(-120 /* sunsetOffset */, -60 /* sunriseOffset */);
+        setActivated(false /* activated */, -90 /* lastActivatedTimeOffset */);
+
+        final TwilightState state = mTwilightManager.getLastTwilightState();
+        mTwilightManager.setTwilightState(null);
+
+        startService();
+        assertActivated(false /* activated */);
+
+        mTwilightManager.setTwilightState(state);
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenRebootedAfterNight_ifOffInFuture_turnsOff() {
+        setAutoModeTwilight(-120 /* sunsetOffset */, -60 /* sunriseOffset */);
+        setActivated(false /* activated */, 30 /* lastActivatedTimeOffset */);
+
+        final TwilightState state = mTwilightManager.getLastTwilightState();
+        mTwilightManager.setTwilightState(null);
+
+        startService();
+        assertActivated(false /* activated */);
+
+        mTwilightManager.setTwilightState(state);
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenRebootedAfterNight_ifOnAfterNight_turnsOn() {
+        setAutoModeTwilight(-120 /* sunsetOffset */, -60 /* sunriseOffset */);
+        setActivated(true /* activated */, -30 /* lastActivatedTimeOffset */);
+
+        final TwilightState state = mTwilightManager.getLastTwilightState();
+        mTwilightManager.setTwilightState(null);
+
+        startService();
+        assertActivated(true /* activated */);
+
+        mTwilightManager.setTwilightState(state);
+        assertActivated(true /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenRebootedAfterNight_ifOnBeforeNight_turnsOff() {
+        setAutoModeTwilight(-120 /* sunsetOffset */, -60 /* sunriseOffset */);
+        setActivated(true /* activated */, -180 /* lastActivatedTimeOffset */);
+
+        final TwilightState state = mTwilightManager.getLastTwilightState();
+        mTwilightManager.setTwilightState(null);
+
+        startService();
+        assertActivated(true /* activated */);
+
+        mTwilightManager.setTwilightState(state);
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenRebootedAfterNight_ifOnDuringNight_turnsOff() {
+        setAutoModeTwilight(-120 /* sunsetOffset */, -60 /* sunriseOffset */);
+        setActivated(true /* activated */, -90 /* lastActivatedTimeOffset */);
+
+        final TwilightState state = mTwilightManager.getLastTwilightState();
+        mTwilightManager.setTwilightState(null);
+
+        startService();
+        assertActivated(true /* activated */);
+
+        mTwilightManager.setTwilightState(state);
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenRebootedAfterNight_ifOnInFuture_turnsOff() {
+        setAutoModeTwilight(-120 /* sunsetOffset */, -60 /* sunriseOffset */);
+        setActivated(true /* activated */, 30 /* lastActivatedTimeOffset */);
+
+        final TwilightState state = mTwilightManager.getLastTwilightState();
+        mTwilightManager.setTwilightState(null);
+
+        startService();
+        assertActivated(true /* activated */);
+
+        mTwilightManager.setTwilightState(state);
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenRebootedBeforeNight_ifOffAfterNight_turnsOff() {
+        setAutoModeTwilight(60 /* sunsetOffset */, 120 /* sunriseOffset */);
+        setActivated(false /* activated */, 180 /* lastActivatedTimeOffset */);
+
+        final TwilightState state = mTwilightManager.getLastTwilightState();
+        mTwilightManager.setTwilightState(null);
+
+        startService();
+        assertActivated(false /* activated */);
+
+        mTwilightManager.setTwilightState(state);
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenRebootedBeforeNight_ifOffBeforeNight_turnsOff() {
+        setAutoModeTwilight(60 /* sunsetOffset */, 120 /* sunriseOffset */);
+        setActivated(false /* activated */, 30 /* lastActivatedTimeOffset */);
+
+        final TwilightState state = mTwilightManager.getLastTwilightState();
+        mTwilightManager.setTwilightState(null);
+
+        startService();
+        assertActivated(false /* activated */);
+
+        mTwilightManager.setTwilightState(state);
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenRebootedBeforeNight_ifOffDuringNight_turnsOff() {
+        setAutoModeTwilight(60 /* sunsetOffset */, 120 /* sunriseOffset */);
+        setActivated(false /* activated */, 90 /* lastActivatedTimeOffset */);
+
+        final TwilightState state = mTwilightManager.getLastTwilightState();
+        mTwilightManager.setTwilightState(null);
+
+        startService();
+        assertActivated(false /* activated */);
+
+        mTwilightManager.setTwilightState(state);
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenRebootedBeforeNight_ifOffInPast_turnsOff() {
+        setAutoModeTwilight(60 /* sunsetOffset */, 120 /* sunriseOffset */);
+        setActivated(false /* activated */, -30 /* lastActivatedTimeOffset */);
+
+        final TwilightState state = mTwilightManager.getLastTwilightState();
+        mTwilightManager.setTwilightState(null);
+
+        startService();
+        assertActivated(false /* activated */);
+
+        mTwilightManager.setTwilightState(state);
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenRebootedBeforeNight_ifOnAfterNight_turnsOff() {
+        setAutoModeTwilight(60 /* sunsetOffset */, 120 /* sunriseOffset */);
+        setActivated(true /* activated */, 180 /* lastActivatedTimeOffset */);
+
+        final TwilightState state = mTwilightManager.getLastTwilightState();
+        mTwilightManager.setTwilightState(null);
+
+        startService();
+        assertActivated(true /* activated */);
+
+        mTwilightManager.setTwilightState(state);
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenRebootedBeforeNight_ifOnBeforeNight_turnsOff() {
+        setAutoModeTwilight(60 /* sunsetOffset */, 120 /* sunriseOffset */);
+        setActivated(true /* activated */, 30 /* lastActivatedTimeOffset */);
+
+        final TwilightState state = mTwilightManager.getLastTwilightState();
+        mTwilightManager.setTwilightState(null);
+
+        startService();
+        assertActivated(true /* activated */);
+
+        mTwilightManager.setTwilightState(state);
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenRebootedBeforeNight_ifOnDuringNight_turnsOff() {
+        setAutoModeTwilight(60 /* sunsetOffset */, 120 /* sunriseOffset */);
+        setActivated(true /* activated */, 90 /* lastActivatedTimeOffset */);
+
+        final TwilightState state = mTwilightManager.getLastTwilightState();
+        mTwilightManager.setTwilightState(null);
+
+        startService();
+        assertActivated(true /* activated */);
+
+        mTwilightManager.setTwilightState(state);
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenRebootedBeforeNight_ifOnInPast_turnsOn() {
+        setAutoModeTwilight(60 /* sunsetOffset */, 120 /* sunriseOffset */);
+        setActivated(true /* activated */, -30 /* lastActivatedTimeOffset */);
+
+        final TwilightState state = mTwilightManager.getLastTwilightState();
+        mTwilightManager.setTwilightState(null);
+
+        startService();
+        assertActivated(true /* activated */);
+
+        mTwilightManager.setTwilightState(state);
+        assertActivated(true /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenRebootedDuringNight_ifOffAfterNight_turnsOn() {
+        setAutoModeTwilight(-60 /* sunsetOffset */, 60 /* sunriseOffset */);
+        setActivated(false /* activated */, 90 /* lastActivatedTimeOffset */);
+
+        final TwilightState state = mTwilightManager.getLastTwilightState();
+        mTwilightManager.setTwilightState(null);
+
+        startService();
+        assertActivated(false /* activated */);
+
+        mTwilightManager.setTwilightState(state);
+        assertActivated(true /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenRebootedDuringNight_ifOffBeforeNight_turnsOn() {
+        setAutoModeTwilight(-60 /* sunsetOffset */, 60 /* sunriseOffset */);
+        setActivated(false /* activated */, -90 /* lastActivatedTimeOffset */);
+
+        final TwilightState state = mTwilightManager.getLastTwilightState();
+        mTwilightManager.setTwilightState(null);
+
+        startService();
+        assertActivated(false /* activated */);
+
+        mTwilightManager.setTwilightState(state);
+        assertActivated(true /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenRebootedDuringNight_ifOffDuringNightInFuture_turnsOn() {
+        setAutoModeTwilight(-60 /* sunsetOffset */, 60 /* sunriseOffset */);
+        setActivated(false /* activated */, 30 /* lastActivatedTimeOffset */);
+
+        final TwilightState state = mTwilightManager.getLastTwilightState();
+        mTwilightManager.setTwilightState(null);
+
+        startService();
+        assertActivated(false /* activated */);
+
+        mTwilightManager.setTwilightState(state);
+        assertActivated(true /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenRebootedDuringNight_ifOffDuringNightInPast_turnsOff() {
+        setAutoModeTwilight(-60 /* sunsetOffset */, 60 /* sunriseOffset */);
+        setActivated(false /* activated */, -30 /* lastActivatedTimeOffset */);
+
+        final TwilightState state = mTwilightManager.getLastTwilightState();
+        mTwilightManager.setTwilightState(null);
+
+        startService();
+        assertActivated(false /* activated */);
+
+        mTwilightManager.setTwilightState(state);
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenRebootedDuringNight_ifOnAfterNight_turnsOn() {
+        setAutoModeTwilight(-60 /* sunsetOffset */, 60 /* sunriseOffset */);
+        setActivated(true /* activated */, 90 /* lastActivatedTimeOffset */);
+
+        final TwilightState state = mTwilightManager.getLastTwilightState();
+        mTwilightManager.setTwilightState(null);
+
+        startService();
+        assertActivated(true /* activated */);
+
+        mTwilightManager.setTwilightState(state);
+        assertActivated(true /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenRebootedDuringNight_ifOnBeforeNight_turnsOn() {
+        setAutoModeTwilight(-60 /* sunsetOffset */, 60 /* sunriseOffset */);
+        setActivated(true /* activated */, -90 /* lastActivatedTimeOffset */);
+
+        final TwilightState state = mTwilightManager.getLastTwilightState();
+        mTwilightManager.setTwilightState(null);
+
+        startService();
+        assertActivated(true /* activated */);
+
+        mTwilightManager.setTwilightState(state);
+        assertActivated(true /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenRebootedDuringNight_ifOnDuringNightInFuture_turnsOn() {
+        setAutoModeTwilight(-60 /* sunsetOffset */, 60 /* sunriseOffset */);
+        setActivated(true /* activated */, 30 /* lastActivatedTimeOffset */);
+
+        final TwilightState state = mTwilightManager.getLastTwilightState();
+        mTwilightManager.setTwilightState(null);
+
+        startService();
+        assertActivated(true /* activated */);
+
+        mTwilightManager.setTwilightState(state);
+        assertActivated(true /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenRebootedDuringNight_ifOnDuringNightInPast_turnsOn() {
+        setAutoModeTwilight(-60 /* sunsetOffset */, 60 /* sunriseOffset */);
+        setActivated(true /* activated */, -30 /* lastActivatedTimeOffset */);
+
+        final TwilightState state = mTwilightManager.getLastTwilightState();
+        mTwilightManager.setTwilightState(null);
+
+        startService();
+        assertActivated(true /* activated */);
+
+        mTwilightManager.setTwilightState(state);
+        assertActivated(true /* activated */);
     }
 
     /**
      * Configures Night display to use a custom schedule.
      *
      * @param startTimeOffset the offset relative to now to activate Night display (in minutes)
-     * @param endTimeOffset   the offset relative to now to deactivate Night display (in minutes)
+     * @param endTimeOffset the offset relative to now to deactivate Night display (in minutes)
      */
     private void setAutoModeCustom(int startTimeOffset, int endTimeOffset) {
         mNightDisplayController.setAutoMode(NightDisplayController.AUTO_MODE_CUSTOM);
@@ -553,34 +908,21 @@
     /**
      * Configures Night display to use the twilight schedule.
      *
-     * @param sunsetOffset  the offset relative to now for sunset (in minutes)
+     * @param sunsetOffset the offset relative to now for sunset (in minutes)
      * @param sunriseOffset the offset relative to now for sunrise (in minutes)
      */
     private void setAutoModeTwilight(int sunsetOffset, int sunriseOffset) {
         mNightDisplayController.setAutoMode(NightDisplayController.AUTO_MODE_TWILIGHT);
-
-        final LocalTime sunset = getLocalTimeRelativeToNow(sunsetOffset);
-        final LocalTime sunrise = getLocalTimeRelativeToNow(sunriseOffset);
-
-        final Calendar now = Calendar.getInstance();
-        long sunsetMillis = sunset.getDateTimeBefore(now).getTimeInMillis();
-        long sunriseMillis = sunrise.getDateTimeBefore(now).getTimeInMillis();
-        if (sunsetMillis < sunriseMillis) {
-            sunsetMillis = sunset.getDateTimeAfter(now).getTimeInMillis();
-        } else {
-            sunriseMillis = sunrise.getDateTimeAfter(now).getTimeInMillis();
-        }
-
-        final TwilightState state = new TwilightState(sunriseMillis, sunsetMillis);
-        doReturn(state).when(mTwilightManager).getLastTwilightState();
+        mTwilightManager.setTwilightState(
+                getTwilightStateRelativeToNow(sunsetOffset, sunriseOffset));
     }
 
     /**
      * Configures the Night display activated state.
      *
-     * @param activated               {@code true} if Night display should be activated
+     * @param activated {@code true} if Night display should be activated
      * @param lastActivatedTimeOffset the offset relative to now to record that Night display was
-                                      activated (in minutes)
+     * activated (in minutes)
      */
     private void setActivated(boolean activated, int lastActivatedTimeOffset) {
         mNightDisplayController.setActivated(activated);
@@ -617,4 +959,93 @@
                 .that(mNightDisplayController.isActivated())
                 .isEqualTo(activated);
     }
+
+    /**
+     * Convenience for making a {@link LocalTime} instance with an offset relative to now.
+     *
+     * @param offsetMinutes the offset relative to now (in minutes)
+     * @return the LocalTime instance
+     */
+    private static LocalTime getLocalTimeRelativeToNow(int offsetMinutes) {
+        final Calendar c = Calendar.getInstance();
+        c.add(Calendar.MINUTE, offsetMinutes);
+        return new LocalTime(c.get(Calendar.HOUR_OF_DAY), c.get(Calendar.MINUTE));
+    }
+
+    /**
+     * Convenience for making a {@link TwilightState} instance with sunrise/sunset relative to now.
+     *
+     * @param sunsetOffset the offset relative to now for sunset (in minutes)
+     * @param sunriseOffset the offset relative to now for sunrise (in minutes)
+     * @return the TwilightState instance
+     */
+    private static TwilightState getTwilightStateRelativeToNow(int sunsetOffset,
+            int sunriseOffset) {
+        final LocalTime sunset = getLocalTimeRelativeToNow(sunsetOffset);
+        final LocalTime sunrise = getLocalTimeRelativeToNow(sunriseOffset);
+
+        final Calendar now = Calendar.getInstance();
+        long sunsetMillis = sunset.getDateTimeBefore(now).getTimeInMillis();
+        long sunriseMillis = sunrise.getDateTimeBefore(now).getTimeInMillis();
+        if (sunsetMillis < sunriseMillis) {
+            sunsetMillis = sunset.getDateTimeAfter(now).getTimeInMillis();
+        } else {
+            sunriseMillis = sunrise.getDateTimeAfter(now).getTimeInMillis();
+        }
+
+        return new TwilightState(sunriseMillis, sunsetMillis);
+    }
+
+    private static class MockTwilightManager implements TwilightManager {
+
+        private final Map<TwilightListener, Handler> mListeners = new HashMap<>();
+        private TwilightState mTwilightState;
+
+        /**
+         * Updates the TwilightState and notifies any registered listeners.
+         *
+         * @param state the new TwilightState to use
+         */
+        void setTwilightState(TwilightState state) {
+            synchronized (mListeners) {
+                mTwilightState = state;
+
+                final CountDownLatch latch = new CountDownLatch(mListeners.size());
+                for (Map.Entry<TwilightListener, Handler> entry : mListeners.entrySet()) {
+                    entry.getValue().post(new Runnable() {
+                        @Override
+                        public void run() {
+                            entry.getKey().onTwilightStateChanged(state);
+                            latch.countDown();
+                        }
+                    });
+                }
+
+                try {
+                    latch.await(5, TimeUnit.SECONDS);
+                } catch (InterruptedException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        }
+
+        @Override
+        public void registerListener(@NonNull TwilightListener listener, @NonNull Handler handler) {
+            synchronized (mListeners) {
+                mListeners.put(listener, handler);
+            }
+        }
+
+        @Override
+        public void unregisterListener(@NonNull TwilightListener listener) {
+            synchronized (mListeners) {
+                mListeners.remove(listener);
+            }
+        }
+
+        @Override
+        public TwilightState getLastTwilightState() {
+            return mTwilightState;
+        }
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
index 4c7bf4d..f4944f9 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -7399,4 +7399,50 @@
                     "s21", "s22");
         });
     }
+
+    public void testReturnedByServer() {
+        // Package 1 updated, with manifest shortcuts.
+        addManifestShortcutResource(
+                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+                R.xml.shortcut_1);
+        updatePackageVersion(CALLING_PACKAGE_1, 1);
+        mService.mPackageMonitor.onReceive(getTestContext(),
+                genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertWith(mManager.getManifestShortcuts())
+                    .haveIds("ms1")
+                    .forAllShortcuts(si -> assertTrue(si.isReturnedByServer()));
+
+            assertTrue(mManager.setDynamicShortcuts(list(makeShortcut("s1"))));
+
+            assertWith(mManager.getDynamicShortcuts())
+                    .haveIds("s1")
+                    .forAllShortcuts(si -> assertTrue(si.isReturnedByServer()));
+        });
+
+        // Pin them.
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
+                    list("ms1", "s1"), getCallingUser());
+            assertWith(getShortcutAsLauncher(USER_0))
+                    .haveIds("ms1", "s1")
+                    .forAllShortcuts(si -> assertTrue(si.isReturnedByServer()));
+        });
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertWith(mManager.getPinnedShortcuts())
+                    .haveIds("ms1", "s1")
+                    .forAllShortcuts(si -> assertTrue(si.isReturnedByServer()));
+        });
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            // This shows a warning log, but should still work.
+            assertTrue(mManager.setDynamicShortcuts(mManager.getDynamicShortcuts()));
+
+            assertWith(mManager.getDynamicShortcuts())
+                    .haveIds("s1")
+                    .forAllShortcuts(si -> assertTrue(si.isReturnedByServer()));
+        });
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/storage/DiskStatsLoggingServiceTest.java b/services/tests/servicestests/src/com/android/server/storage/DiskStatsLoggingServiceTest.java
index 3789086..375edf3 100644
--- a/services/tests/servicestests/src/com/android/server/storage/DiskStatsLoggingServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/storage/DiskStatsLoggingServiceTest.java
@@ -20,16 +20,31 @@
 
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyInt;
-import static org.mockito.Mockito.eq;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.isNull;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
 
 import android.app.job.JobService;
-import android.app.job.JobParameters;
+import android.app.job.JobServiceEngine;
+import android.app.usage.ExternalStorageStats;
+import android.app.usage.StorageStatsManager;
+import android.content.Context;
+import android.content.pm.PackageManager;
 import android.content.pm.PackageStats;
+import android.os.BatteryManager;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.os.storage.StorageManager;
+import android.os.storage.VolumeInfo;
+import android.provider.Settings;
 import android.test.AndroidTestCase;
+import android.test.mock.MockContentResolver;
 
+import com.android.internal.util.test.FakeSettingsProvider;
 import com.android.server.storage.DiskStatsLoggingService.LogRunnable;
 
 import libcore.io.IoUtils;
@@ -46,14 +61,17 @@
 
 import java.io.File;
 import java.io.PrintStream;
+import java.lang.reflect.Field;
 import java.util.ArrayList;
 
 @RunWith(JUnit4.class)
 public class DiskStatsLoggingServiceTest extends AndroidTestCase {
     @Rule public TemporaryFolder mTemporaryFolder;
     @Rule public TemporaryFolder mDownloads;
-    @Rule public TemporaryFolder mRootDirectory;
     @Mock private AppCollector mCollector;
+    @Mock private JobService mJobService;
+    @Mock private StorageStatsManager mSsm;
+    private ExternalStorageStats mStorageStats;
     private File mInputFile;
 
 
@@ -66,8 +84,10 @@
         mInputFile = mTemporaryFolder.newFile();
         mDownloads = new TemporaryFolder();
         mDownloads.create();
-        mRootDirectory = new TemporaryFolder();
-        mRootDirectory.create();
+        mStorageStats = new ExternalStorageStats();
+        when(mSsm.queryExternalStatsForUser(isNull(String.class), any(UserHandle.class)))
+                .thenReturn(mStorageStats);
+        when(mJobService.getSystemService(anyString())).thenReturn(mSsm);
     }
 
     @Test
@@ -75,9 +95,9 @@
         LogRunnable task = new LogRunnable();
         task.setAppCollector(mCollector);
         task.setDownloadsDirectory(mDownloads.getRoot());
-        task.setRootDirectory(mRootDirectory.getRoot());
         task.setLogOutputFile(mInputFile);
         task.setSystemSize(0L);
+        task.setContext(mJobService);
         task.run();
 
         JSONObject json = getJsonOutput();
@@ -99,10 +119,10 @@
     public void testPopulatedLogTask() throws Exception {
         // Write data to directories.
         writeDataToFile(mDownloads.newFile(), "lol");
-        writeDataToFile(mRootDirectory.newFile("test.jpg"), "1234");
-        writeDataToFile(mRootDirectory.newFile("test.mp4"), "12345");
-        writeDataToFile(mRootDirectory.newFile("test.mp3"), "123456");
-        writeDataToFile(mRootDirectory.newFile("test.whatever"), "1234567");
+        mStorageStats.audioBytes = 6L;
+        mStorageStats.imageBytes = 4L;
+        mStorageStats.videoBytes = 5L;
+        mStorageStats.totalBytes = 22L;
 
         // Write apps.
         ArrayList<PackageStats> apps = new ArrayList<>();
@@ -110,15 +130,16 @@
         testApp.dataSize = 5L;
         testApp.cacheSize = 55L;
         testApp.codeSize = 10L;
+        testApp.userHandle = UserHandle.USER_SYSTEM;
         apps.add(testApp);
-        when(mCollector.getPackageStats(anyInt())).thenReturn(apps);
+        when(mCollector.getPackageStats(anyLong())).thenReturn(apps);
 
         LogRunnable task = new LogRunnable();
         task.setAppCollector(mCollector);
         task.setDownloadsDirectory(mDownloads.getRoot());
-        task.setRootDirectory(mRootDirectory.getRoot());
         task.setLogOutputFile(mInputFile);
         task.setSystemSize(10L);
+        task.setContext(mJobService);
         task.run();
 
         JSONObject json = getJsonOutput();
@@ -143,14 +164,57 @@
         LogRunnable task = new LogRunnable();
         task.setAppCollector(mCollector);
         task.setDownloadsDirectory(mDownloads.getRoot());
-        task.setRootDirectory(mRootDirectory.getRoot());
         task.setLogOutputFile(mInputFile);
         task.setSystemSize(10L);
+        task.setContext(mJobService);
         task.run();
 
         // No exception should be thrown.
     }
 
+    @Test
+    public void testDontCrashOnRun() throws Exception {
+        DiskStatsLoggingService service = spy(new DiskStatsLoggingService());
+        BatteryManager batteryManager = mock(BatteryManager.class);
+        when(batteryManager.isCharging()).thenReturn(true);
+        doReturn(batteryManager).when(service).getSystemService(Context.BATTERY_SERVICE);
+        UserManager userManager = mock(UserManager.class);
+        when(userManager.getUsers()).thenReturn(new ArrayList<>());
+        doReturn(userManager).when(service).getSystemService(Context.USER_SERVICE);
+        doReturn(mSsm).when(service).getSystemService(Context.STORAGE_STATS_SERVICE);
+        doReturn(mock(StorageManager.class))
+                .when(service)
+                .getSystemService(Context.STORAGE_SERVICE);
+
+        MockContentResolver cr = new MockContentResolver();
+        cr.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
+        doReturn(cr).when(service).getContentResolver();
+
+        PackageManager pm = mock(PackageManager.class);
+        VolumeInfo volumeInfo =
+                new VolumeInfo(VolumeInfo.ID_PRIVATE_INTERNAL, VolumeInfo.TYPE_PRIVATE, null, null);
+        when(pm.getPrimaryStorageCurrentVolume()).thenReturn(volumeInfo);
+        doReturn(pm).when(service).getPackageManager();
+
+        doReturn(0).when(service).getUserId();
+
+        // UGGGGGHHHHHHH! jobFinished is a final method on JobService which crashes when called if
+        // the JobService isn't initialized for real. ServiceTestCase doesn't let us initialize a
+        // service which is built into the framework without crashing, though, so we can't make a
+        // real initialized service.
+        //
+        // And so, we use reflection to set the JobServiceEngine, which is used by the final method,
+        // to be something which won't crash when called.
+        final Field field = JobService.class.getDeclaredField("mEngine");
+        field.setAccessible(true);
+        field.set(service, mock(JobServiceEngine.class));
+
+        // Note: This won't clobber your on-device cache file because, technically,
+        // FrameworkServicesTests don't have write permission to actually overwrite the cache file.
+        // We log and fail on the write silently in this case.
+        service.onStartJob(null);
+    }
+
     private void writeDataToFile(File f, String data) throws Exception{
         PrintStream out = new PrintStream(f);
         out.print(data);
diff --git a/services/usage/java/com/android/server/usage/StorageStatsService.java b/services/usage/java/com/android/server/usage/StorageStatsService.java
index e13665b..dae74db 100644
--- a/services/usage/java/com/android/server/usage/StorageStatsService.java
+++ b/services/usage/java/com/android/server/usage/StorageStatsService.java
@@ -16,6 +16,8 @@
 
 package com.android.server.usage;
 
+import static com.android.internal.util.ArrayUtils.defeatNullable;
+
 import android.app.AppOpsManager;
 import android.app.usage.ExternalStorageStats;
 import android.app.usage.IStorageStatsManager;
@@ -112,9 +114,12 @@
         mStorage.registerListener(new StorageEventListener() {
             @Override
             public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
-                if ((vol.type == VolumeInfo.TYPE_PRIVATE)
-                        && (newState == VolumeInfo.STATE_MOUNTED)) {
-                    invalidateMounts();
+                switch (vol.type) {
+                    case VolumeInfo.TYPE_PRIVATE:
+                    case VolumeInfo.TYPE_EMULATED:
+                        if (newState == VolumeInfo.STATE_MOUNTED) {
+                            invalidateMounts();
+                        }
                 }
             }
         });
@@ -178,9 +183,11 @@
         long cacheBytes = 0;
         final long token = Binder.clearCallingIdentity();
         try {
-            for (UserInfo user : mUser.getUsers()) {
-                final StorageStats stats = queryStatsForUser(volumeUuid, user.id, null);
-                cacheBytes += stats.cacheBytes;
+            if (isQuotaSupported(volumeUuid, callingPackage)) {
+                for (UserInfo user : mUser.getUsers()) {
+                    final StorageStats stats = queryStatsForUser(volumeUuid, user.id, null);
+                    cacheBytes += stats.cacheBytes;
+                }
             }
         } finally {
             Binder.restoreCallingIdentity(token);
@@ -232,7 +239,7 @@
             enforcePermission(Binder.getCallingUid(), callingPackage);
         }
 
-        if (mPackage.getPackagesForUid(appInfo.uid).length == 1) {
+        if (defeatNullable(mPackage.getPackagesForUid(appInfo.uid)).length == 1) {
             // Only one package inside UID means we can fast-path
             return queryStatsForUid(volumeUuid, appInfo.uid, callingPackage);
         } else {
@@ -276,7 +283,7 @@
             enforcePermission(Binder.getCallingUid(), callingPackage);
         }
 
-        final String[] packageNames = mPackage.getPackagesForUid(uid);
+        final String[] packageNames = defeatNullable(mPackage.getPackagesForUid(uid));
         final long[] ceDataInodes = new long[packageNames.length];
         String[] codePaths = new String[0];
 
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index b34fcdc..adf897d 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -336,14 +336,13 @@
      */
     @Test
     public void testCorrectLooperIsUsedForHandler() throws Exception {
-        // record thread from looper.getThread and check ids.
         TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
         when(mWifiService.startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class)))
                 .thenReturn(ERROR_INCOMPATIBLE_MODE);
         mWifiManager.startLocalOnlyHotspot(callback, mHandler);
         mLooper.dispatchAll();
         assertEquals(ERROR_INCOMPATIBLE_MODE, callback.mFailureReason);
-        assertEquals(mLooper.getLooper().getThread().getId(), callback.mCallingThreadId);
+        verify(mContext, never()).getMainLooper();
     }
 
     /**
@@ -362,6 +361,7 @@
         altLooper.dispatchAll();
         assertEquals(ERROR_INCOMPATIBLE_MODE, callback.mFailureReason);
         assertEquals(altLooper.getLooper().getThread().getId(), callback.mCallingThreadId);
+        verify(mContext).getMainLooper();
     }
 
     /**
@@ -632,12 +632,11 @@
      */
     @Test
     public void testCorrectLooperIsUsedForObserverHandler() throws Exception {
-        // record thread from looper.getThread and check ids.
         TestLocalOnlyHotspotObserver observer = new TestLocalOnlyHotspotObserver();
         mWifiManager.watchLocalOnlyHotspot(observer, mHandler);
         mLooper.dispatchAll();
         assertTrue(observer.mOnRegistered);
-        assertEquals(mLooper.getLooper().getThread().getId(), observer.mCallingThreadId);
+        verify(mContext, never()).getMainLooper();
     }
 
     /**
@@ -654,6 +653,7 @@
         altLooper.dispatchAll();
         assertTrue(observer.mOnRegistered);
         assertEquals(altLooper.getLooper().getThread().getId(), observer.mCallingThreadId);
+        verify(mContext).getMainLooper();
     }
 
     /**