Merge "Fix VR current component changes being ignored."
diff --git a/api/current.txt b/api/current.txt
index 62365cc..35000a6 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -410,6 +410,7 @@
     field public static final int colorControlHighlight = 16843820; // 0x101042c
     field public static final int colorControlNormal = 16843817; // 0x1010429
     field public static final int colorEdgeEffect = 16843982; // 0x10104ce
+    field public static final int colorError = 16844100; // 0x1010544
     field public static final int colorFocusedHighlight = 16843663; // 0x101038f
     field public static final int colorForeground = 16842800; // 0x1010030
     field public static final int colorForegroundInverse = 16843270; // 0x1010206
@@ -1316,7 +1317,6 @@
     field public static final int textCheckMarkInverse = 16842823; // 0x1010047
     field public static final int textColor = 16842904; // 0x1010098
     field public static final int textColorAlertDialogListItem = 16843526; // 0x1010306
-    field public static final int textColorError = 16844100; // 0x1010544
     field public static final int textColorHighlight = 16842905; // 0x1010099
     field public static final int textColorHighlightInverse = 16843599; // 0x101034f
     field public static final int textColorHint = 16842906; // 0x101009a
@@ -9041,6 +9041,7 @@
     field public static final java.lang.String ACTION_CALL = "android.intent.action.CALL";
     field public static final java.lang.String ACTION_CALL_BUTTON = "android.intent.action.CALL_BUTTON";
     field public static final java.lang.String ACTION_CAMERA_BUTTON = "android.intent.action.CAMERA_BUTTON";
+    field public static final java.lang.String ACTION_CARRIER_SETUP = "android.intent.action.CARRIER_SETUP";
     field public static final java.lang.String ACTION_CHOOSER = "android.intent.action.CHOOSER";
     field public static final java.lang.String ACTION_CLEAR_PACKAGE = "android.intent.action.CLEAR_PACKAGE";
     field public static final java.lang.String ACTION_CLOSE_SYSTEM_DIALOGS = "android.intent.action.CLOSE_SYSTEM_DIALOGS";
diff --git a/api/removed.txt b/api/removed.txt
index e467811..9baeebc 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -169,10 +169,6 @@
     method public android.graphics.drawable.Drawable getBadgedDrawableForUser(android.graphics.drawable.Drawable, android.os.UserHandle, android.graphics.Rect, int);
     method public android.graphics.drawable.Drawable getBadgedIconForUser(android.graphics.drawable.Drawable, android.os.UserHandle);
     method public java.lang.CharSequence getBadgedLabelForUser(java.lang.CharSequence, android.os.UserHandle);
-    method public deprecated boolean isUserRunningAndLocked();
-    method public deprecated boolean isUserRunningAndLocked(android.os.UserHandle);
-    method public deprecated boolean isUserRunningAndUnlocked();
-    method public deprecated boolean isUserRunningAndUnlocked(android.os.UserHandle);
   }
 
 }
diff --git a/api/system-current.txt b/api/system-current.txt
index 8626f1b..59dd315 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -523,6 +523,7 @@
     field public static final int colorControlHighlight = 16843820; // 0x101042c
     field public static final int colorControlNormal = 16843817; // 0x1010429
     field public static final int colorEdgeEffect = 16843982; // 0x10104ce
+    field public static final int colorError = 16844100; // 0x1010544
     field public static final int colorFocusedHighlight = 16843663; // 0x101038f
     field public static final int colorForeground = 16842800; // 0x1010030
     field public static final int colorForegroundInverse = 16843270; // 0x1010206
@@ -1433,7 +1434,6 @@
     field public static final int textCheckMarkInverse = 16842823; // 0x1010047
     field public static final int textColor = 16842904; // 0x1010098
     field public static final int textColorAlertDialogListItem = 16843526; // 0x1010306
-    field public static final int textColorError = 16844100; // 0x1010544
     field public static final int textColorHighlight = 16842905; // 0x1010099
     field public static final int textColorHighlightInverse = 16843599; // 0x101034f
     field public static final int textColorHint = 16842906; // 0x101009a
@@ -9515,6 +9515,7 @@
     field public static final java.lang.String ACTION_CALL = "android.intent.action.CALL";
     field public static final java.lang.String ACTION_CALL_BUTTON = "android.intent.action.CALL_BUTTON";
     field public static final java.lang.String ACTION_CAMERA_BUTTON = "android.intent.action.CAMERA_BUTTON";
+    field public static final java.lang.String ACTION_CARRIER_SETUP = "android.intent.action.CARRIER_SETUP";
     field public static final java.lang.String ACTION_CHOOSER = "android.intent.action.CHOOSER";
     field public static final java.lang.String ACTION_CLEAR_PACKAGE = "android.intent.action.CLEAR_PACKAGE";
     field public static final java.lang.String ACTION_CLOSE_SYSTEM_DIALOGS = "android.intent.action.CLOSE_SYSTEM_DIALOGS";
@@ -25876,6 +25877,12 @@
     method public static final boolean isChannelUriForTunerInput(android.net.Uri);
     method public static final boolean isProgramUri(android.net.Uri);
     field public static final java.lang.String AUTHORITY = "android.media.tv";
+    field public static final java.lang.String EXTRA_COLUMN_NAME = "android.media.tv.extra.COLUMN_NAME";
+    field public static final java.lang.String EXTRA_EXISTING_COLUMN_NAMES = "android.media.tv.extra.EXISTING_COLUMN_NAMES";
+    field public static final java.lang.String EXTRA_DATA_TYPE = "android.media.tv.extra.DATA_TYPE";
+    field public static final java.lang.String EXTRA_DEFAULT_VALUE = "android.media.tv.extra.DEFAULT_VALUE";
+    field public static final java.lang.String METHOD_ADD_COLUMN = "add_column";
+    field public static final java.lang.String METHOD_GET_COLUMNS = "get_columns";
   }
 
   public static abstract interface TvContract.BaseProgramColumns implements android.media.tv.TvContract.BaseTvColumns {
@@ -27124,7 +27131,8 @@
   }
 
   public abstract class NetworkRecommendationProvider {
-    ctor public NetworkRecommendationProvider(android.os.Handler);
+    ctor public deprecated NetworkRecommendationProvider(android.os.Handler);
+    ctor public NetworkRecommendationProvider(android.content.Context, java.util.concurrent.Executor);
     method public final android.os.IBinder getBinder();
     method public abstract void onRequestRecommendation(android.net.RecommendationRequest, android.net.NetworkRecommendationProvider.ResultCallback);
     method public abstract void onRequestScores(android.net.NetworkKey[]);
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 6773112..4642992 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -163,10 +163,6 @@
     method public android.graphics.drawable.Drawable getBadgedDrawableForUser(android.graphics.drawable.Drawable, android.os.UserHandle, android.graphics.Rect, int);
     method public android.graphics.drawable.Drawable getBadgedIconForUser(android.graphics.drawable.Drawable, android.os.UserHandle);
     method public java.lang.CharSequence getBadgedLabelForUser(java.lang.CharSequence, android.os.UserHandle);
-    method public deprecated boolean isUserRunningAndLocked();
-    method public deprecated boolean isUserRunningAndLocked(android.os.UserHandle);
-    method public deprecated boolean isUserRunningAndUnlocked();
-    method public deprecated boolean isUserRunningAndUnlocked(android.os.UserHandle);
   }
 
 }
diff --git a/api/test-current.txt b/api/test-current.txt
index 44386be..12c2cc8 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -410,6 +410,7 @@
     field public static final int colorControlHighlight = 16843820; // 0x101042c
     field public static final int colorControlNormal = 16843817; // 0x1010429
     field public static final int colorEdgeEffect = 16843982; // 0x10104ce
+    field public static final int colorError = 16844100; // 0x1010544
     field public static final int colorFocusedHighlight = 16843663; // 0x101038f
     field public static final int colorForeground = 16842800; // 0x1010030
     field public static final int colorForegroundInverse = 16843270; // 0x1010206
@@ -1316,7 +1317,6 @@
     field public static final int textCheckMarkInverse = 16842823; // 0x1010047
     field public static final int textColor = 16842904; // 0x1010098
     field public static final int textColorAlertDialogListItem = 16843526; // 0x1010306
-    field public static final int textColorError = 16844100; // 0x1010544
     field public static final int textColorHighlight = 16842905; // 0x1010099
     field public static final int textColorHighlightInverse = 16843599; // 0x101034f
     field public static final int textColorHint = 16842906; // 0x101009a
@@ -9070,6 +9070,7 @@
     field public static final java.lang.String ACTION_CALL = "android.intent.action.CALL";
     field public static final java.lang.String ACTION_CALL_BUTTON = "android.intent.action.CALL_BUTTON";
     field public static final java.lang.String ACTION_CAMERA_BUTTON = "android.intent.action.CAMERA_BUTTON";
+    field public static final java.lang.String ACTION_CARRIER_SETUP = "android.intent.action.CARRIER_SETUP";
     field public static final java.lang.String ACTION_CHOOSER = "android.intent.action.CHOOSER";
     field public static final java.lang.String ACTION_CLEAR_PACKAGE = "android.intent.action.CLEAR_PACKAGE";
     field public static final java.lang.String ACTION_CLOSE_SYSTEM_DIALOGS = "android.intent.action.CLOSE_SYSTEM_DIALOGS";
diff --git a/api/test-removed.txt b/api/test-removed.txt
index e467811..9baeebc 100644
--- a/api/test-removed.txt
+++ b/api/test-removed.txt
@@ -169,10 +169,6 @@
     method public android.graphics.drawable.Drawable getBadgedDrawableForUser(android.graphics.drawable.Drawable, android.os.UserHandle, android.graphics.Rect, int);
     method public android.graphics.drawable.Drawable getBadgedIconForUser(android.graphics.drawable.Drawable, android.os.UserHandle);
     method public java.lang.CharSequence getBadgedLabelForUser(java.lang.CharSequence, android.os.UserHandle);
-    method public deprecated boolean isUserRunningAndLocked();
-    method public deprecated boolean isUserRunningAndLocked(android.os.UserHandle);
-    method public deprecated boolean isUserRunningAndUnlocked();
-    method public deprecated boolean isUserRunningAndUnlocked(android.os.UserHandle);
   }
 
 }
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 812daf8..64fc44b 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -2702,11 +2702,11 @@
         }
 
         /**
-         * Specifies the time at which this notification should be canceled, if it is not already
-         * canceled.
+         * Specifies a duration in milliseconds after which this notification should be canceled,
+         * if it is not already canceled.
          */
-        public Builder setTimeout(long when) {
-            mN.mTimeout = when;
+        public Builder setTimeout(long durationMs) {
+            mN.mTimeout = durationMs;
             return this;
         }
 
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 9cb3dd6..6585793 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -3346,6 +3346,17 @@
     public static final int KEYGUARD_DISABLE_FEATURES_ALL = 0x7fffffff;
 
     /**
+     * Keyguard features that when set on a managed profile that doesn't have its own challenge will
+     * affect the profile's parent user. These can also be set on the managed profile's parent
+     * {@link DevicePolicyManager} instance.
+     *
+     * @hide
+     */
+    public static final int PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER =
+            DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS
+            | DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT;
+
+    /**
      * Called by an application that is administering the device to request that the storage system
      * be encrypted.
      * <p>
@@ -7697,7 +7708,34 @@
     /**
      * Called by a device owner to control the network logging feature.
      *
-     * <p> Network logs contain DNS lookup and connect() library call events.
+     * <p> Network logs contain DNS lookup and connect() library call events. The following library
+     *     functions are recorded while network logging is active:
+     *     <ul>
+     *       <li>{@code getaddrinfo()}</li>
+     *       <li>{@code gethostbyname()}</li>
+     *       <li>{@code connect()}</li>
+     *     </ul>
+     *
+     * <p> Network logging is a low-overhead tool for forensics but it is not guaranteed to use
+     *     full system call logging; event reporting is enabled by default for all processes but not
+     *     strongly enforced.
+     *     Events from applications using alternative implementations of libc, making direct kernel
+     *     calls, or deliberately obfuscating traffic may not be recorded.
+     *
+     * <p> Some common network events may not be reported. For example:
+     *     <ul>
+     *       <li>Applications may hardcode IP addresses to reduce the number of DNS lookups, or use
+     *           an alternative system for name resolution, and so avoid calling
+     *           {@code getaddrinfo()} or {@code gethostbyname}.</li>
+     *       <li>Applications may use datagram sockets for performance reasons, for example
+     *           for a game client. Calling {@code connect()} is unnecessary for this kind of
+     *           socket, so it will not trigger a network event.</li>
+     *     </ul>
+     *
+     * <p> It is possible to directly intercept layer 3 traffic leaving the device using an
+     *     always-on VPN service.
+     *     See {@link #setAlwaysOnVpnPackage(ComponentName, String, boolean)}
+     *     and {@link android.net.VpnService} for details.
      *
      * <p><strong>Note:</strong> The device owner won't be able to retrieve network logs if there
      * are unaffiliated secondary users or profiles on the device, regardless of whether the
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 4480b41..687d590 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -500,6 +500,7 @@
     public ContentResolver(Context context) {
         mContext = context != null ? context : ActivityThread.currentApplication();
         mPackageName = mContext.getOpPackageName();
+        mTargetSdkVersion = mContext.getApplicationInfo().targetSdkVersion;
     }
 
     /** @hide */
@@ -1868,13 +1869,18 @@
     /**
      * Register an observer class that gets callbacks when data identified by a
      * given content URI changes.
+     * <p>
+     * Starting in {@link android.os.Build.VERSION_CODES#O}, all content
+     * notifications must be backed by a valid {@link ContentProvider}.
      *
-     * @param uri The URI to watch for changes. This can be a specific row URI, or a base URI
-     * for a whole class of content.
-     * @param notifyForDescendants When false, the observer will be notified whenever a
-     * change occurs to the exact URI specified by <code>uri</code> or to one of the
-     * URI's ancestors in the path hierarchy.  When true, the observer will also be notified
-     * whenever a change occurs to the URI's descendants in the path hierarchy.
+     * @param uri The URI to watch for changes. This can be a specific row URI,
+     *            or a base URI for a whole class of content.
+     * @param notifyForDescendants When false, the observer will be notified
+     *            whenever a change occurs to the exact URI specified by
+     *            <code>uri</code> or to one of the URI's ancestors in the path
+     *            hierarchy. When true, the observer will also be notified
+     *            whenever a change occurs to the URI's descendants in the path
+     *            hierarchy.
      * @param observer The object that receives callbacks when changes occur.
      * @see #unregisterContentObserver
      */
@@ -1894,7 +1900,7 @@
             ContentObserver observer, @UserIdInt int userHandle) {
         try {
             getContentService().registerContentObserver(uri, notifyForDescendents,
-                    observer.getContentObserver(), userHandle);
+                    observer.getContentObserver(), userHandle, mTargetSdkVersion);
         } catch (RemoteException e) {
         }
     }
@@ -1918,16 +1924,22 @@
     }
 
     /**
-     * Notify registered observers that a row was updated and attempt to sync changes
-     * to the network.
-     * To register, call {@link #registerContentObserver(android.net.Uri , boolean, android.database.ContentObserver) registerContentObserver()}.
-     * By default, CursorAdapter objects will get this notification.
+     * Notify registered observers that a row was updated and attempt to sync
+     * changes to the network.
+     * <p>
+     * To observe events sent through this call, use
+     * {@link #registerContentObserver(Uri, boolean, ContentObserver)}.
+     * <p>
+     * Starting in {@link android.os.Build.VERSION_CODES#O}, all content
+     * notifications must be backed by a valid {@link ContentProvider}.
      *
      * @param uri The uri of the content that was changed.
-     * @param observer The observer that originated the change, may be <code>null</null>.
-     * The observer that originated the change will only receive the notification if it
-     * has requested to receive self-change notifications by implementing
-     * {@link ContentObserver#deliverSelfNotifications()} to return true.
+     * @param observer The observer that originated the change, may be
+     *            <code>null</null>. The observer that originated the change
+     *            will only receive the notification if it has requested to
+     *            receive self-change notifications by implementing
+     *            {@link ContentObserver#deliverSelfNotifications()} to return
+     *            true.
      */
     public void notifyChange(@NonNull Uri uri, @Nullable ContentObserver observer) {
         notifyChange(uri, observer, true /* sync to network */);
@@ -1935,17 +1947,25 @@
 
     /**
      * Notify registered observers that a row was updated.
-     * To register, call {@link #registerContentObserver(android.net.Uri , boolean, android.database.ContentObserver) registerContentObserver()}.
-     * By default, CursorAdapter objects will get this notification.
-     * If syncToNetwork is true, this will attempt to schedule a local sync using the sync
-     * adapter that's registered for the authority of the provided uri. No account will be
-     * passed to the sync adapter, so all matching accounts will be synchronized.
+     * <p>
+     * To observe events sent through this call, use
+     * {@link #registerContentObserver(Uri, boolean, ContentObserver)}.
+     * <p>
+     * If syncToNetwork is true, this will attempt to schedule a local sync
+     * using the sync adapter that's registered for the authority of the
+     * provided uri. No account will be passed to the sync adapter, so all
+     * matching accounts will be synchronized.
+     * <p>
+     * Starting in {@link android.os.Build.VERSION_CODES#O}, all content
+     * notifications must be backed by a valid {@link ContentProvider}.
      *
      * @param uri The uri of the content that was changed.
-     * @param observer The observer that originated the change, may be <code>null</null>.
-     * The observer that originated the change will only receive the notification if it
-     * has requested to receive self-change notifications by implementing
-     * {@link ContentObserver#deliverSelfNotifications()} to return true.
+     * @param observer The observer that originated the change, may be
+     *            <code>null</null>. The observer that originated the change
+     *            will only receive the notification if it has requested to
+     *            receive self-change notifications by implementing
+     *            {@link ContentObserver#deliverSelfNotifications()} to return
+     *            true.
      * @param syncToNetwork If true, same as {@link #NOTIFY_SYNC_TO_NETWORK}.
      * @see #requestSync(android.accounts.Account, String, android.os.Bundle)
      */
@@ -1961,17 +1981,25 @@
 
     /**
      * Notify registered observers that a row was updated.
-     * To register, call {@link #registerContentObserver(android.net.Uri, boolean, android.database.ContentObserver) registerContentObserver()}.
-     * By default, CursorAdapter objects will get this notification.
-     * If syncToNetwork is true, this will attempt to schedule a local sync using the sync
-     * adapter that's registered for the authority of the provided uri. No account will be
-     * passed to the sync adapter, so all matching accounts will be synchronized.
+     * <p>
+     * To observe events sent through this call, use
+     * {@link #registerContentObserver(Uri, boolean, ContentObserver)}.
+     * <p>
+     * If syncToNetwork is true, this will attempt to schedule a local sync
+     * using the sync adapter that's registered for the authority of the
+     * provided uri. No account will be passed to the sync adapter, so all
+     * matching accounts will be synchronized.
+     * <p>
+     * Starting in {@link android.os.Build.VERSION_CODES#O}, all content
+     * notifications must be backed by a valid {@link ContentProvider}.
      *
      * @param uri The uri of the content that was changed.
-     * @param observer The observer that originated the change, may be <code>null</null>.
-     * The observer that originated the change will only receive the notification if it
-     * has requested to receive self-change notifications by implementing
-     * {@link ContentObserver#deliverSelfNotifications()} to return true.
+     * @param observer The observer that originated the change, may be
+     *            <code>null</null>. The observer that originated the change
+     *            will only receive the notification if it has requested to
+     *            receive self-change notifications by implementing
+     *            {@link ContentObserver#deliverSelfNotifications()} to return
+     *            true.
      * @param flags Additional flags: {@link #NOTIFY_SYNC_TO_NETWORK}.
      * @see #requestSync(android.accounts.Account, String, android.os.Bundle)
      */
@@ -1997,7 +2025,7 @@
                     uri, observer == null ? null : observer.getContentObserver(),
                     observer != null && observer.deliverSelfNotifications(),
                     syncToNetwork ? NOTIFY_SYNC_TO_NETWORK : 0,
-                    userHandle);
+                    userHandle, mTargetSdkVersion);
         } catch (RemoteException e) {
         }
     }
@@ -2013,7 +2041,7 @@
             getContentService().notifyChange(
                     uri, observer == null ? null : observer.getContentObserver(),
                     observer != null && observer.deliverSelfNotifications(), flags,
-                    userHandle);
+                    userHandle, mTargetSdkVersion);
         } catch (RemoteException e) {
         }
     }
@@ -2932,6 +2960,7 @@
     private final Context mContext;
 
     final String mPackageName;
+    final int mTargetSdkVersion;
 
     private static final String TAG = "ContentResolver";
 
diff --git a/core/java/android/content/IContentService.aidl b/core/java/android/content/IContentService.aidl
index 3446e03..c500116 100644
--- a/core/java/android/content/IContentService.aidl
+++ b/core/java/android/content/IContentService.aidl
@@ -42,7 +42,7 @@
      *     USER_CURRENT are properly handled.
      */
     void registerContentObserver(in Uri uri, boolean notifyForDescendants,
-            IContentObserver observer, int userHandle);
+            IContentObserver observer, int userHandle, int targetSdkVersion);
 
     /**
      * Notify observers of a particular user's view of the provider.
@@ -53,7 +53,7 @@
      */
     void notifyChange(in Uri uri, IContentObserver observer,
             boolean observerWantsSelfNotifications, int flags,
-            int userHandle);
+            int userHandle, int targetSdkVersion);
 
     void requestSync(in Account account, String authority, in Bundle extras);
     /**
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 28068c5..870db217 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1115,6 +1115,15 @@
     public static final String ACTION_SIM_ACTIVATION_REQUEST =
             "android.intent.action.SIM_ACTIVATION_REQUEST";
     /**
+     * Activity Action: Main entry point for carrier setup apps.
+     * <p>Carrier apps that provide an implementation for this action may be invoked to configure
+     * carrier service and typically require
+     * {@link android.telephony.TelephonyManager#hasCarrierPrivileges() carrier privileges} to
+     * fulfill their duties.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_CARRIER_SETUP = "android.intent.action.CARRIER_SETUP";
+    /**
      * Activity Action: Send a message to someone specified by the data.
      * <p>Input: {@link #getData} is URI describing the target.
      * <p>Output: nothing.
@@ -9260,6 +9269,13 @@
             mClipData.prepareToLeaveProcess(leavingPackage, getFlags());
         }
 
+        if (mExtras != null && !mExtras.isParcelled()) {
+            final Object intent = mExtras.get(Intent.EXTRA_INTENT);
+            if (intent instanceof Intent) {
+                ((Intent) intent).prepareToLeaveProcess(leavingPackage);
+            }
+        }
+
         if (mAction != null && mData != null && StrictMode.vmFileUriExposureEnabled()
                 && leavingPackage) {
             switch (mAction) {
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 5733982..6646402 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -624,8 +624,10 @@
      * should be installed as forward locked, i.e. only the app itself should
      * have access to its code and non-resource assets.
      *
+     * @deprecated new installs into ASEC containers are no longer supported.
      * @hide
      */
+    @Deprecated
     public static final int INSTALL_FORWARD_LOCK = 0x00000001;
 
     /**
@@ -648,8 +650,11 @@
      * Flag parameter for {@link #installPackage} to indicate that this package
      * must be installed to an ASEC on a {@link VolumeInfo#TYPE_PUBLIC}.
      *
+     * @deprecated new installs into ASEC containers are no longer supported;
+     *             use adoptable storage instead.
      * @hide
      */
+    @Deprecated
     public static final int INSTALL_EXTERNAL = 0x00000008;
 
     /**
diff --git a/core/java/android/net/INetworkScoreService.aidl b/core/java/android/net/INetworkScoreService.aidl
index f249daf..362ea9d 100644
--- a/core/java/android/net/INetworkScoreService.aidl
+++ b/core/java/android/net/INetworkScoreService.aidl
@@ -18,7 +18,7 @@
 
 import android.net.INetworkScoreCache;
 import android.net.NetworkKey;
-import android.net.NetworkScorerAppManager;
+import android.net.NetworkScorerAppData;
 import android.net.RecommendationRequest;
 import android.net.RecommendationResult;
 import android.net.ScoredNetwork;
@@ -135,11 +135,11 @@
     /**
      * Returns metadata about the active scorer or <code>null</code> if there is no active scorer.
      */
-    NetworkScorerAppManager.NetworkScorerAppData getActiveScorer();
+    NetworkScorerAppData getActiveScorer();
 
     /**
      * Returns the list of available scorer apps. The list will be empty if there are
      * no valid scorers.
      */
-    List<NetworkScorerAppManager.NetworkScorerAppData> getAllValidScorers();
+    List<NetworkScorerAppData> getAllValidScorers();
 }
diff --git a/core/java/android/net/NetworkRecommendationProvider.java b/core/java/android/net/NetworkRecommendationProvider.java
index 8395864..271b0a7 100644
--- a/core/java/android/net/NetworkRecommendationProvider.java
+++ b/core/java/android/net/NetworkRecommendationProvider.java
@@ -1,6 +1,8 @@
 package android.net;
 
+import android.Manifest.permission;
 import android.annotation.SystemApi;
+import android.content.Context;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
@@ -10,8 +12,10 @@
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
 
 import java.util.Objects;
+import java.util.concurrent.Executor;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
@@ -32,6 +36,7 @@
     /**
      * Constructs a new instance.
      * @param handler indicates which thread to use when handling requests. Cannot be {@code null}.
+     * @deprecated use {@link #NetworkRecommendationProvider(Context, Executor)}
      */
     public NetworkRecommendationProvider(Handler handler) {
         if (handler == null) {
@@ -41,6 +46,17 @@
     }
 
     /**
+     * Constructs a new instance.
+     * @param context the current context instance. Cannot be {@code null}.
+     * @param executor used to execute the incoming requests. Cannot be {@code null}.
+     */
+    public NetworkRecommendationProvider(Context context, Executor executor) {
+        Preconditions.checkNotNull(context);
+        Preconditions.checkNotNull(executor);
+        mService = new ServiceWrapper(context, executor);
+    }
+
+    /**
      * Invoked when a recommendation has been requested.
      *
      * @param request a {@link RecommendationRequest} instance containing additional
@@ -130,17 +146,28 @@
      * A wrapper around INetworkRecommendationProvider that dispatches to the provided Handler.
      */
     private final class ServiceWrapper extends INetworkRecommendationProvider.Stub {
+        private final Context mContext;
+        private final Executor mExecutor;
         private final Handler mHandler;
 
         ServiceWrapper(Handler handler) {
             mHandler = handler;
+            mExecutor = null;
+            mContext = null;
+        }
+
+        ServiceWrapper(Context context, Executor executor) {
+            mContext = context;
+            mExecutor = executor;
+            mHandler = null;
         }
 
         @Override
         public void requestRecommendation(final RecommendationRequest request,
                 final IRemoteCallback callback, final int sequence) throws RemoteException {
+            enforceCallingPermission();
             if (VERBOSE) Log.v(TAG, "requestRecommendation(seq=" + sequence + ")");
-            mHandler.post(new Runnable() {
+            execute(new Runnable() {
                 @Override
                 public void run() {
                     if (VERBOSE) {
@@ -154,8 +181,9 @@
 
         @Override
         public void requestScores(final NetworkKey[] networks) throws RemoteException {
+            enforceCallingPermission();
             if (networks != null && networks.length > 0) {
-                mHandler.post(new Runnable() {
+                execute(new Runnable() {
                     @Override
                     public void run() {
                         onRequestScores(networks);
@@ -163,5 +191,20 @@
                 });
             }
         }
+
+        private void execute(Runnable command) {
+            if (mExecutor != null) {
+                mExecutor.execute(command);
+            } else {
+                mHandler.post(command);
+            }
+        }
+
+        private void enforceCallingPermission() {
+            if (mContext != null) {
+                mContext.enforceCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES,
+                        "Permission denied.");
+            }
+        }
     }
 }
diff --git a/core/java/android/net/NetworkScoreManager.java b/core/java/android/net/NetworkScoreManager.java
index edfaee4..815d480 100644
--- a/core/java/android/net/NetworkScoreManager.java
+++ b/core/java/android/net/NetworkScoreManager.java
@@ -18,7 +18,6 @@
 
 import static android.net.NetworkRecommendationProvider.EXTRA_RECOMMENDATION_RESULT;
 
-import android.Manifest;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -26,7 +25,6 @@
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemApi;
 import android.content.Context;
-import android.net.NetworkScorerAppManager.NetworkScorerAppData;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.RemoteCallback;
diff --git a/core/java/android/net/NetworkScorerAppManager.aidl b/core/java/android/net/NetworkScorerAppData.aidl
similarity index 91%
rename from core/java/android/net/NetworkScorerAppManager.aidl
rename to core/java/android/net/NetworkScorerAppData.aidl
index d968343..ee7f1d1 100644
--- a/core/java/android/net/NetworkScorerAppManager.aidl
+++ b/core/java/android/net/NetworkScorerAppData.aidl
@@ -16,4 +16,4 @@
 
 package android.net;
 
-parcelable NetworkScorerAppManager.NetworkScorerAppData;
+parcelable NetworkScorerAppData;
diff --git a/core/java/android/net/NetworkScorerAppData.java b/core/java/android/net/NetworkScorerAppData.java
new file mode 100644
index 0000000..fca0a2e
--- /dev/null
+++ b/core/java/android/net/NetworkScorerAppData.java
@@ -0,0 +1,99 @@
+package android.net;
+
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * Holds metadata about a discovered network scorer/recommendation application.
+ *
+ * @hide
+ */
+public final class NetworkScorerAppData implements Parcelable {
+    /** UID of the scorer app. */
+    public final int packageUid;
+    private final ComponentName mRecommendationService;
+    /**
+     * The {@link ComponentName} of the Activity to start before enabling the "connect to open
+     * wifi networks automatically" feature.
+     */
+    private final ComponentName mEnableUseOpenWifiActivity;
+
+    public NetworkScorerAppData(int packageUid, ComponentName recommendationServiceComp,
+            ComponentName enableUseOpenWifiActivity) {
+        this.packageUid = packageUid;
+        this.mRecommendationService = recommendationServiceComp;
+        this.mEnableUseOpenWifiActivity = enableUseOpenWifiActivity;
+    }
+
+    protected NetworkScorerAppData(Parcel in) {
+        packageUid = in.readInt();
+        mRecommendationService = ComponentName.readFromParcel(in);
+        mEnableUseOpenWifiActivity = ComponentName.readFromParcel(in);
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(packageUid);
+        ComponentName.writeToParcel(mRecommendationService, dest);
+        ComponentName.writeToParcel(mEnableUseOpenWifiActivity, dest);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    public static final Creator<NetworkScorerAppData> CREATOR =
+            new Creator<NetworkScorerAppData>() {
+                @Override
+                public NetworkScorerAppData createFromParcel(Parcel in) {
+                    return new NetworkScorerAppData(in);
+                }
+
+                @Override
+                public NetworkScorerAppData[] newArray(int size) {
+                    return new NetworkScorerAppData[size];
+                }
+            };
+
+    public String getRecommendationServicePackageName() {
+        return mRecommendationService.getPackageName();
+    }
+
+    public ComponentName getRecommendationServiceComponent() {
+        return mRecommendationService;
+    }
+
+    @Nullable
+    public ComponentName getEnableUseOpenWifiActivity() {
+        return mEnableUseOpenWifiActivity;
+    }
+
+    @Override
+    public String toString() {
+        return "NetworkScorerAppData{" +
+                "packageUid=" + packageUid +
+                ", mRecommendationService=" + mRecommendationService +
+                ", mEnableUseOpenWifiActivity=" + mEnableUseOpenWifiActivity +
+                '}';
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        NetworkScorerAppData that = (NetworkScorerAppData) o;
+        return packageUid == that.packageUid &&
+                Objects.equals(mRecommendationService, that.mRecommendationService) &&
+                Objects.equals(mEnableUseOpenWifiActivity, that.mEnableUseOpenWifiActivity);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(packageUid, mRecommendationService, mEnableUseOpenWifiActivity);
+    }
+}
diff --git a/core/java/android/net/NetworkScorerAppManager.java b/core/java/android/net/NetworkScorerAppManager.java
deleted file mode 100644
index bbc1c79..0000000
--- a/core/java/android/net/NetworkScorerAppManager.java
+++ /dev/null
@@ -1,332 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package android.net;
-
-import android.Manifest.permission;
-import android.annotation.Nullable;
-import android.content.ComponentName;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.content.pm.ServiceInfo;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.android.internal.R;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * Internal class for discovering and managing the network scorer/recommendation application.
- *
- * @hide
- */
-public class NetworkScorerAppManager {
-    private static final String TAG = "NetworkScorerAppManager";
-    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-    private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
-    private final Context mContext;
-
-    public NetworkScorerAppManager(Context context) {
-      mContext = context;
-    }
-
-    /**
-     * Holds metadata about a discovered network scorer/recommendation application.
-     */
-    public static final class NetworkScorerAppData implements Parcelable {
-        /** UID of the scorer app. */
-        public final int packageUid;
-        private final ComponentName mRecommendationService;
-        /**
-         * The {@link ComponentName} of the Activity to start before enabling the "connect to open
-         * wifi networks automatically" feature.
-         */
-        private final ComponentName mEnableUseOpenWifiActivity;
-
-        public NetworkScorerAppData(int packageUid, ComponentName recommendationServiceComp,
-                ComponentName enableUseOpenWifiActivity) {
-            this.packageUid = packageUid;
-            this.mRecommendationService = recommendationServiceComp;
-            this.mEnableUseOpenWifiActivity = enableUseOpenWifiActivity;
-        }
-
-        protected NetworkScorerAppData(Parcel in) {
-            packageUid = in.readInt();
-            mRecommendationService = ComponentName.readFromParcel(in);
-            mEnableUseOpenWifiActivity = ComponentName.readFromParcel(in);
-        }
-
-        @Override
-        public void writeToParcel(Parcel dest, int flags) {
-            dest.writeInt(packageUid);
-            ComponentName.writeToParcel(mRecommendationService, dest);
-            ComponentName.writeToParcel(mEnableUseOpenWifiActivity, dest);
-        }
-
-        @Override
-        public int describeContents() {
-            return 0;
-        }
-
-        public static final Creator<NetworkScorerAppData> CREATOR =
-                new Creator<NetworkScorerAppData>() {
-                    @Override
-                    public NetworkScorerAppData createFromParcel(Parcel in) {
-                        return new NetworkScorerAppData(in);
-                    }
-
-                    @Override
-                    public NetworkScorerAppData[] newArray(int size) {
-                        return new NetworkScorerAppData[size];
-                    }
-                };
-
-        public String getRecommendationServicePackageName() {
-            return mRecommendationService.getPackageName();
-        }
-
-        public ComponentName getRecommendationServiceComponent() {
-            return mRecommendationService;
-        }
-
-        @Nullable public ComponentName getEnableUseOpenWifiActivity() {
-            return mEnableUseOpenWifiActivity;
-        }
-
-        @Override
-        public String toString() {
-            return "NetworkScorerAppData{" +
-                    "packageUid=" + packageUid +
-                    ", mRecommendationService=" + mRecommendationService +
-                    ", mEnableUseOpenWifiActivity=" + mEnableUseOpenWifiActivity +
-                    '}';
-        }
-
-        @Override
-        public boolean equals(Object o) {
-            if (this == o) return true;
-            if (o == null || getClass() != o.getClass()) return false;
-            NetworkScorerAppData that = (NetworkScorerAppData) o;
-            return packageUid == that.packageUid &&
-                    Objects.equals(mRecommendationService, that.mRecommendationService) &&
-                    Objects.equals(mEnableUseOpenWifiActivity, that.mEnableUseOpenWifiActivity);
-        }
-
-        @Override
-        public int hashCode() {
-            return Objects.hash(packageUid, mRecommendationService, mEnableUseOpenWifiActivity);
-        }
-    }
-
-    /**
-     * Returns the list of available scorer apps. The list will be empty if there are
-     * no valid scorers.
-     */
-    public List<NetworkScorerAppData> getAllValidScorers() {
-        return Collections.emptyList();
-    }
-
-    /**
-     * @return A {@link NetworkScorerAppData} instance containing information about the
-     *         best configured network recommendation provider installed or {@code null}
-     *         if none of the configured packages can recommend networks.
-     *
-     * <p>A network recommendation provider is any application which:
-     * <ul>
-     * <li>Is listed in the <code>config_networkRecommendationPackageNames</code> config.
-     * <li>Declares the {@link android.Manifest.permission#SCORE_NETWORKS} permission.
-     * <li>Includes a Service for {@link NetworkScoreManager#ACTION_RECOMMEND_NETWORKS}.
-     * </ul>
-     */
-    public NetworkScorerAppData getNetworkRecommendationProviderData() {
-        // Network recommendation apps can only run as the primary user right now.
-        // http://b/23422763
-        if (UserHandle.getCallingUserId() != UserHandle.USER_SYSTEM) {
-            return null;
-        }
-
-        final List<String> potentialPkgs = getPotentialRecommendationProviderPackages();
-        if (potentialPkgs.isEmpty()) {
-            if (DEBUG) {
-                Log.d(TAG, "No Network Recommendation Providers specified.");
-            }
-            return null;
-        }
-
-        for (int i = 0; i < potentialPkgs.size(); i++) {
-            final String potentialPkg = potentialPkgs.get(i);
-
-            // Look for the recommendation service class and required receiver.
-            final ServiceInfo serviceInfo = findRecommendationService(potentialPkg);
-            if (serviceInfo != null) {
-                final ComponentName serviceComponentName =
-                    new ComponentName(potentialPkg, serviceInfo.name);
-                final ComponentName useOpenWifiNetworksActivity =
-                        findUseOpenWifiNetworksActivity(serviceInfo);
-                return new NetworkScorerAppData(serviceInfo.applicationInfo.uid,
-                    serviceComponentName, useOpenWifiNetworksActivity);
-            } else {
-                if (DEBUG) {
-                    Log.d(TAG, potentialPkg + " does not have the required components, skipping.");
-                }
-            }
-        }
-
-        // None of the configured packages are valid.
-        return null;
-    }
-
-    @Nullable private ComponentName findUseOpenWifiNetworksActivity(ServiceInfo serviceInfo) {
-        if (serviceInfo.metaData == null) {
-            if (DEBUG) {
-                Log.d(TAG, "No metadata found on recommendation service.");
-            }
-            return null;
-        }
-        final String useOpenWifiPackage = serviceInfo.metaData
-                .getString(NetworkScoreManager.USE_OPEN_WIFI_PACKAGE_META_DATA);
-        if (TextUtils.isEmpty(useOpenWifiPackage)) {
-            if (DEBUG) {
-                Log.d(TAG, "No use_open_wifi_package metadata found.");
-            }
-            return null;
-        }
-        final Intent enableUseOpenWifiIntent = new Intent(NetworkScoreManager.ACTION_CUSTOM_ENABLE)
-                .setPackage(useOpenWifiPackage);
-        final ResolveInfo resolveActivityInfo = mContext.getPackageManager()
-                .resolveActivity(enableUseOpenWifiIntent, 0 /* flags */);
-        if (VERBOSE) {
-            Log.d(TAG, "Resolved " + enableUseOpenWifiIntent + " to " + serviceInfo);
-        }
-
-        if (resolveActivityInfo != null && resolveActivityInfo.activityInfo != null) {
-            return resolveActivityInfo.activityInfo.getComponentName();
-        }
-
-        return null;
-    }
-
-    /**
-     * @return A priority order list of package names that have been granted the
-     *         permission needed for them to act as a network recommendation provider.
-     *         The packages in the returned list may not contain the other required
-     *         network recommendation provider components so additional checks are required
-     *         before making a package the network recommendation provider.
-     */
-    public List<String> getPotentialRecommendationProviderPackages() {
-        final String[] packageArray = mContext.getResources().getStringArray(
-                R.array.config_networkRecommendationPackageNames);
-        if (packageArray == null || packageArray.length == 0) {
-            if (DEBUG) {
-                Log.d(TAG, "No Network Recommendation Providers specified.");
-            }
-            return Collections.emptyList();
-        }
-
-        if (VERBOSE) {
-            Log.d(TAG, "Configured packages: " + TextUtils.join(", ", packageArray));
-        }
-
-        List<String> packages = new ArrayList<>();
-        final PackageManager pm = mContext.getPackageManager();
-        for (String potentialPkg : packageArray) {
-            if (pm.checkPermission(permission.SCORE_NETWORKS, potentialPkg)
-                    == PackageManager.PERMISSION_GRANTED) {
-                packages.add(potentialPkg);
-            } else {
-                if (DEBUG) {
-                    Log.d(TAG, potentialPkg + " has not been granted " + permission.SCORE_NETWORKS
-                            + ", skipping.");
-                }
-            }
-        }
-
-        return packages;
-    }
-
-    @Nullable private ServiceInfo findRecommendationService(String packageName) {
-        final PackageManager pm = mContext.getPackageManager();
-        final int resolveFlags = PackageManager.GET_META_DATA;
-        final Intent serviceIntent = new Intent(NetworkScoreManager.ACTION_RECOMMEND_NETWORKS);
-        serviceIntent.setPackage(packageName);
-        final ResolveInfo resolveServiceInfo =
-                pm.resolveService(serviceIntent, resolveFlags);
-
-        if (VERBOSE) {
-            Log.d(TAG, "Resolved " + serviceIntent + " to " + resolveServiceInfo);
-        }
-
-        if (resolveServiceInfo != null && resolveServiceInfo.serviceInfo != null) {
-            return resolveServiceInfo.serviceInfo;
-        }
-
-        if (VERBOSE) {
-            Log.v(TAG, packageName + " does not have a service for " + serviceIntent);
-        }
-        return null;
-    }
-
-    /**
-     * Get the application to use for scoring networks.
-     *
-     * @return the scorer app info or null if scoring is disabled (including if no scorer was ever
-     *     selected) or if the previously-set scorer is no longer a valid scorer app (e.g. because
-     *     it was disabled or uninstalled).
-     */
-    @Nullable
-    public NetworkScorerAppData getActiveScorer() {
-        if (isNetworkRecommendationsDisabled()) {
-            // If recommendations are disabled then there can't be an active scorer.
-            return null;
-        }
-
-        // Otherwise return the recommendation provider (which may be null).
-        return getNetworkRecommendationProviderData();
-    }
-
-    /**
-     * Set the specified package as the default scorer application.
-     *
-     * <p>The caller must have permission to write to {@link android.provider.Settings.Global}.
-     *
-     * @param packageName the packageName of the new scorer to use. If null, scoring will be
-     *     disabled. Otherwise, the scorer will only be set if it is a valid scorer application.
-     * @return true if the scorer was changed, or false if the package is not a valid scorer or
-     *         a valid network recommendation provider exists.
-     * @deprecated Scorers are now selected from a configured list.
-     */
-    @Deprecated
-    public boolean setActiveScorer(String packageName) {
-        return false;
-    }
-
-    private boolean isNetworkRecommendationsDisabled() {
-        final ContentResolver cr = mContext.getContentResolver();
-        // A value of 1 indicates enabled.
-        return Settings.Global.getInt(cr, Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 0) != 1;
-    }
-}
diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java
index d299672..63d3e7a 100644
--- a/core/java/android/os/Looper.java
+++ b/core/java/android/os/Looper.java
@@ -18,8 +18,10 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.os.LooperProto;
 import android.util.Log;
 import android.util.Printer;
+import android.util.proto.ProtoOutputStream;
 
 /**
   * Class used to run a message loop for a thread.  Threads by default do
@@ -289,6 +291,16 @@
         mQueue.dump(pw, prefix + "  ");
     }
 
+    /** @hide */
+    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+        final long looperToken = proto.start(fieldId);
+        proto.write(LooperProto.THREAD_NAME, mThread.getName());
+        proto.write(LooperProto.THREAD_ID, mThread.getId());
+        proto.write(LooperProto.IDENTITY_HASH_CODE, System.identityHashCode(this));
+        mQueue.writeToProto(proto, LooperProto.QUEUE);
+        proto.end(looperToken);
+    }
+
     @Override
     public String toString() {
         return "Looper (" + mThread.getName() + ", tid " + mThread.getId()
diff --git a/core/java/android/os/Message.java b/core/java/android/os/Message.java
index 8c75847..d066db1 100644
--- a/core/java/android/os/Message.java
+++ b/core/java/android/os/Message.java
@@ -16,13 +16,15 @@
 
 package android.os;
 
+import android.os.MessageProto;
 import android.util.TimeUtils;
+import android.util.proto.ProtoOutputStream;
 
 /**
- * 
+ *
  * Defines a message containing a description and arbitrary data object that can be
  * sent to a {@link Handler}.  This object contains two extra int fields and an
- * extra object field that allow you to not do allocations in many cases.  
+ * extra object field that allow you to not do allocations in many cases.
  *
  * <p class="note">While the constructor of Message is public, the best way to get
  * one of these is to call {@link #obtain Message.obtain()} or one of the
@@ -31,7 +33,7 @@
  */
 public final class Message implements Parcelable {
     /**
-     * User-defined message code so that the recipient can identify 
+     * User-defined message code so that the recipient can identify
      * what this message is about. Each {@link Handler} has its own name-space
      * for message codes, so you do not need to worry about yours conflicting
      * with other handlers.
@@ -43,7 +45,7 @@
      * {@link #setData(Bundle) setData()} if you only need to store a
      * few integer values.
      */
-    public int arg1; 
+    public int arg1;
 
     /**
      * arg1 and arg2 are lower-cost alternatives to using
@@ -58,7 +60,7 @@
      * be non-null if it contains a Parcelable of a framework class (not one
      * implemented by the application).   For other data transfer use
      * {@link #setData}.
-     * 
+     *
      * <p>Note that Parcelable objects here are not supported prior to
      * the {@link android.os.Build.VERSION_CODES#FROYO} release.
      */
@@ -97,13 +99,13 @@
     /*package*/ int flags;
 
     /*package*/ long when;
-    
+
     /*package*/ Bundle data;
-    
+
     /*package*/ Handler target;
-    
+
     /*package*/ Runnable callback;
-    
+
     // sometimes we store linked lists of these things
     /*package*/ Message next;
 
@@ -216,9 +218,9 @@
     }
 
     /**
-     * Same as {@link #obtain()}, but sets the values of the <em>target</em>, <em>what</em>, 
+     * Same as {@link #obtain()}, but sets the values of the <em>target</em>, <em>what</em>,
      * <em>arg1</em>, and <em>arg2</em> members.
-     * 
+     *
      * @param h  The <em>target</em> value to set.
      * @param what  The <em>what</em> value to set.
      * @param arg1  The <em>arg1</em> value to set.
@@ -236,9 +238,9 @@
     }
 
     /**
-     * Same as {@link #obtain()}, but sets the values of the <em>target</em>, <em>what</em>, 
+     * Same as {@link #obtain()}, but sets the values of the <em>target</em>, <em>what</em>,
      * <em>arg1</em>, <em>arg2</em>, and <em>obj</em> members.
-     * 
+     *
      * @param h  The <em>target</em> value to set.
      * @param what  The <em>what</em> value to set.
      * @param arg1  The <em>arg1</em> value to set.
@@ -246,7 +248,7 @@
      * @param obj  The <em>obj</em> value to set.
      * @return  A Message object from the global pool.
      */
-    public static Message obtain(Handler h, int what, 
+    public static Message obtain(Handler h, int what,
             int arg1, int arg2, Object obj) {
         Message m = obtain();
         m.target = h;
@@ -339,7 +341,7 @@
     public long getWhen() {
         return when;
     }
-    
+
     public void setTarget(Handler target) {
         this.target = target;
     }
@@ -367,8 +369,8 @@
     public Runnable getCallback() {
         return callback;
     }
-    
-    /** 
+
+    /**
      * Obtains a Bundle of arbitrary data associated with this
      * event, lazily creating it if necessary. Set this value by calling
      * {@link #setData(Bundle)}.  Note that when transferring data across
@@ -383,11 +385,11 @@
         if (data == null) {
             data = new Bundle();
         }
-        
+
         return data;
     }
 
-    /** 
+    /**
      * Like getData(), but does not lazily create the Bundle.  A null
      * is returned if the Bundle does not already exist.  See
      * {@link #getData} for further information on this.
@@ -401,7 +403,7 @@
     /**
      * Sets a Bundle of arbitrary data values. Use arg1 and arg2 members
      * as a lower cost way to send a few simple integer values, if you can.
-     * @see #getData() 
+     * @see #getData()
      * @see #peekData()
      */
     public void setData(Bundle data) {
@@ -520,6 +522,37 @@
         return b.toString();
     }
 
+    void writeToProto(ProtoOutputStream proto, long fieldId) {
+        final long messageToken = proto.start(fieldId);
+        proto.write(MessageProto.WHEN, when);
+
+        if (target != null) {
+            if (callback != null) {
+                proto.write(MessageProto.CALLBACK, callback.getClass().getName());
+            } else {
+                proto.write(MessageProto.WHAT, what);
+            }
+
+            if (arg1 != 0) {
+                proto.write(MessageProto.ARG1, arg1);
+            }
+
+            if (arg2 != 0) {
+                proto.write(MessageProto.ARG2, arg2);
+            }
+
+            if (obj != null) {
+                proto.write(MessageProto.OBJ, obj.toString());
+            }
+
+            proto.write(MessageProto.TARGET, target.getClass().getName());
+        } else {
+            proto.write(MessageProto.BARRIER, arg1);
+        }
+
+        proto.end(messageToken);
+    }
+
     public static final Parcelable.Creator<Message> CREATOR
             = new Parcelable.Creator<Message>() {
         public Message createFromParcel(Parcel source) {
@@ -527,12 +560,12 @@
             msg.readFromParcel(source);
             return msg;
         }
-        
+
         public Message[] newArray(int size) {
             return new Message[size];
         }
     };
-        
+
     public int describeContents() {
         return 0;
     }
diff --git a/core/java/android/os/MessageQueue.java b/core/java/android/os/MessageQueue.java
index 4f2e968..2a8c52e 100644
--- a/core/java/android/os/MessageQueue.java
+++ b/core/java/android/os/MessageQueue.java
@@ -18,9 +18,11 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.os.MessageQueueProto;
 import android.util.Log;
 import android.util.Printer;
 import android.util.SparseArray;
+import android.util.proto.ProtoOutputStream;
 
 import java.io.FileDescriptor;
 import java.lang.annotation.Retention;
@@ -31,7 +33,7 @@
  * Low-level class holding the list of messages to be dispatched by a
  * {@link Looper}.  Messages are not added directly to a MessageQueue,
  * but rather through {@link Handler} objects associated with the Looper.
- * 
+ *
  * <p>You can retrieve the MessageQueue for the current thread with
  * {@link Looper#myQueue() Looper.myQueue()}.
  */
@@ -770,6 +772,18 @@
         }
     }
 
+    void writeToProto(ProtoOutputStream proto, long fieldId) {
+        final long messageQueueToken = proto.start(fieldId);
+        synchronized (this) {
+            for (Message msg = mMessages; msg != null; msg = msg.next) {
+                msg.writeToProto(proto, MessageQueueProto.MESSAGES);
+            }
+            proto.write(MessageQueueProto.IS_POLLING_LOCKED, isPollingLocked());
+            proto.write(MessageQueueProto.IS_QUITTING, mQuitting);
+        }
+        proto.end(messageQueueToken);
+    }
+
     /**
      * Callback interface for discovering when a thread is going to block
      * waiting for more messages.
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 21c70f9..13a495e 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1097,40 +1097,6 @@
         }
     }
 
-    /** @removed */
-    @Deprecated
-    public boolean isUserRunningAndLocked() {
-        return isUserRunningAndLocked(Process.myUserHandle());
-    }
-
-    /** @removed */
-    @Deprecated
-    public boolean isUserRunningAndLocked(UserHandle user) {
-        try {
-            return ActivityManager.getService().isUserRunning(
-                    user.getIdentifier(), ActivityManager.FLAG_AND_LOCKED);
-        } catch (RemoteException re) {
-            throw re.rethrowFromSystemServer();
-        }
-    }
-
-    /** @removed */
-    @Deprecated
-    public boolean isUserRunningAndUnlocked() {
-        return isUserRunningAndUnlocked(Process.myUserHandle());
-    }
-
-    /** @removed */
-    @Deprecated
-    public boolean isUserRunningAndUnlocked(UserHandle user) {
-        try {
-            return ActivityManager.getService().isUserRunning(
-                    user.getIdentifier(), ActivityManager.FLAG_AND_UNLOCKED);
-        } catch (RemoteException re) {
-            throw re.rethrowFromSystemServer();
-        }
-    }
-
     /**
      * Return whether the calling user is running in an "unlocked" state.
      * <p>
diff --git a/core/java/android/os/WorkSource.java b/core/java/android/os/WorkSource.java
index f8da87a..ecec448 100644
--- a/core/java/android/os/WorkSource.java
+++ b/core/java/android/os/WorkSource.java
@@ -1,6 +1,8 @@
 package android.os;
 
+import android.os.WorkSourceProto;
 import android.util.Log;
+import android.util.proto.ProtoOutputStream;
 
 import java.util.Arrays;
 
@@ -296,7 +298,7 @@
                 break;
             }
             if (mUids[i] == uid) {
-                int diff = mNames[i].compareTo(name); 
+                int diff = mNames[i].compareTo(name);
                 if (diff > 0) {
                     break;
                 }
@@ -692,6 +694,20 @@
         return result.toString();
     }
 
+    /** @hide */
+    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+        final long workSourceToken = proto.start(fieldId);
+        for (int i = 0; i < mNum; i++) {
+            final long contentProto = proto.start(WorkSourceProto.WORK_SOURCE_CONTENTS);
+            proto.write(WorkSourceProto.WorkSourceContentProto.UID, mUids[i]);
+            if (mNames != null) {
+                proto.write(WorkSourceProto.WorkSourceContentProto.NAME, mNames[i]);
+            }
+            proto.end(contentProto);
+        }
+        proto.end(workSourceToken);
+    }
+
     public static final Parcelable.Creator<WorkSource> CREATOR
             = new Parcelable.Creator<WorkSource>() {
         public WorkSource createFromParcel(Parcel in) {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 40de928..b55a349 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6905,6 +6905,12 @@
         public static final String PACKAGE_VERIFIER_STATE = "package_verifier_state";
 
         /**
+         * Specifies additional package name for broadcasting the CMAS messages.
+         * @hide
+         */
+        public static final String CMAS_ADDITIONAL_BROADCAST_PKG = "cmas_additional_broadcast_pkg";
+
+        /**
          * This are the settings to be backed up.
          *
          * NOTE: Settings are backed up and restored in the order they appear
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 5f7ff67..8a83b7a 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -547,20 +547,20 @@
      * Inform the notification manager about snoozing a specific notification.
      * <p>
      * Use this if your listener has a user interface that allows the user to snooze a notification
-     * until a given time. It should be called after the user snoozes a single notification using
+     * for a time. It should be called after the user snoozes a single notification using
      * your UI; upon being informed, the notification manager will actually remove the notification
      * and you will get an {@link #onNotificationRemoved(StatusBarNotification)} callback. When the
      * snoozing period expires, you will get a
      * {@link #onNotificationPosted(StatusBarNotification, RankingMap)} callback for the
      * notification.
      * @param key The key of the notification to snooze
-     * @param snoozeUntil A time in the future, in milliseconds.
+     * @param durationMs A duration to snooze the notification for, in milliseconds.
      */
-    public final void snoozeNotification(String key, long snoozeUntil) {
+    public final void snoozeNotification(String key, long durationMs) {
         if (!isBound()) return;
         try {
             getNotificationInterface().snoozeNotificationUntilFromListener(
-                    mWrapper, key, snoozeUntil);
+                    mWrapper, key, durationMs);
         } catch (android.os.RemoteException ex) {
             Log.v(TAG, "Unable to contact notification manager", ex);
         }
diff --git a/core/java/android/view/FocusFinder.java b/core/java/android/view/FocusFinder.java
index 7fde8a6..ad06141 100644
--- a/core/java/android/view/FocusFinder.java
+++ b/core/java/android/view/FocusFinder.java
@@ -117,7 +117,7 @@
     public View findNextKeyboardNavigationCluster(
             @NonNull View root,
             @Nullable View currentCluster,
-            int direction) {
+            @View.FocusDirection int direction) {
         View next = null;
 
         final ArrayList<View> clusters = mTempList;
@@ -206,7 +206,7 @@
             View root,
             View currentCluster,
             List<View> clusters,
-            int direction) {
+            @View.FocusDirection int direction) {
         final int count = clusters.size();
 
         switch (direction) {
@@ -732,27 +732,17 @@
             getRect(first, mFirstRect);
             getRect(second, mSecondRect);
 
-            if (mFirstRect.top < mSecondRect.top) {
-                return -1;
-            } else if (mFirstRect.top > mSecondRect.top) {
-                return 1;
-            } else if (mFirstRect.left < mSecondRect.left) {
-                return mIsLayoutRtl ? 1 : -1;
-            } else if (mFirstRect.left > mSecondRect.left) {
-                return mIsLayoutRtl ? -1 : 1;
-            } else if (mFirstRect.bottom < mSecondRect.bottom) {
-                return -1;
-            } else if (mFirstRect.bottom > mSecondRect.bottom) {
-                return 1;
-            } else if (mFirstRect.right < mSecondRect.right) {
-                return mIsLayoutRtl ? 1 : -1;
-            } else if (mFirstRect.right > mSecondRect.right) {
-                return mIsLayoutRtl ? -1 : 1;
+            boolean overlapsVertically = (mFirstRect.top < mSecondRect.top
+                    && mFirstRect.bottom > mSecondRect.top)
+                    || (mFirstRect.top > mSecondRect.top
+                    && mFirstRect.top < mSecondRect.bottom);
+            boolean alignedVertically = (mFirstRect.left > mSecondRect.left)
+                    == (mFirstRect.right < mSecondRect.right);
+            if (overlapsVertically && !alignedVertically) {
+                int rtl = mIsLayoutRtl ? -1 : 1;
+                return rtl * (mFirstRect.left - mSecondRect.left);
             } else {
-                // The view are distinct but completely coincident so we consider
-                // them equal for our purposes.  Since the sort is stable, this
-                // means that the views will retain their layout order relative to one another.
-                return 0;
+                return mFirstRect.top - mSecondRect.top;
             }
         }
 
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 66c394f..a880842 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -9433,7 +9433,8 @@
      * @return The nearest keyboard navigation cluster in the specified direction, or null if none
      *         can be found
      */
-    public View keyboardNavigationClusterSearch(View currentCluster, int direction) {
+    public View keyboardNavigationClusterSearch(View currentCluster,
+            @FocusDirection int direction) {
         if (isKeyboardNavigationCluster()) {
             currentCluster = this;
         }
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 595e7a1..b79f22f 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -72,6 +72,7 @@
 import android.util.TypedValue;
 import android.view.Surface.OutOfResourcesException;
 import android.view.View.AttachInfo;
+import android.view.View.FocusDirection;
 import android.view.View.MeasureSpec;
 import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
 import android.view.accessibility.AccessibilityEvent;
@@ -5975,7 +5976,8 @@
      * {@inheritDoc}
      */
     @Override
-    public View keyboardNavigationClusterSearch(View currentCluster, int direction) {
+    public View keyboardNavigationClusterSearch(View currentCluster,
+            @FocusDirection int direction) {
         checkThread();
         return FocusFinder.getInstance().findNextKeyboardNavigationCluster(
                 mView, currentCluster, direction);
diff --git a/core/java/com/android/internal/util/StateMachine.java b/core/java/com/android/internal/util/StateMachine.java
index be10608df..d67cef3 100644
--- a/core/java/com/android/internal/util/StateMachine.java
+++ b/core/java/com/android/internal/util/StateMachine.java
@@ -23,6 +23,8 @@
 import android.text.TextUtils;
 import android.util.Log;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.io.StringWriter;
@@ -1495,7 +1497,7 @@
     }
 
     /**
-     * @return number of log records
+     * @return the number of log records currently readable
      */
     public final int getLogRecSize() {
         // mSmHandler can be null if the state machine has quit.
@@ -1505,6 +1507,17 @@
     }
 
     /**
+     * @return the number of log records we can store
+     */
+    @VisibleForTesting
+    public final int getLogRecMaxSize() {
+        // mSmHandler can be null if the state machine has quit.
+        SmHandler smh = mSmHandler;
+        if (smh == null) return 0;
+        return smh.mLogRecords.mMaxSize;
+    }
+
+    /**
      * @return the total number of records processed
      */
     public final int getLogRecCount() {
diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java
index ae2e0ac..cc1c65e 100644
--- a/core/java/com/android/internal/widget/LockPatternView.java
+++ b/core/java/com/android/internal/widget/LockPatternView.java
@@ -278,7 +278,8 @@
     public LockPatternView(Context context, AttributeSet attrs) {
         super(context, attrs);
 
-        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.LockPatternView);
+        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.LockPatternView,
+                R.attr.lockPatternStyle, R.style.Widget_LockPatternView);
 
         final String aspect = a.getString(R.styleable.LockPatternView_aspect);
 
@@ -298,12 +299,9 @@
         mPathPaint.setAntiAlias(true);
         mPathPaint.setDither(true);
 
-        mRegularColor = context.getColor(R.color.lock_pattern_view_regular_color);
-        mErrorColor = context.getColor(R.color.lock_pattern_view_error_color);
-        mSuccessColor = context.getColor(R.color.lock_pattern_view_success_color);
-        mRegularColor = a.getColor(R.styleable.LockPatternView_regularColor, mRegularColor);
-        mErrorColor = a.getColor(R.styleable.LockPatternView_errorColor, mErrorColor);
-        mSuccessColor = a.getColor(R.styleable.LockPatternView_successColor, mSuccessColor);
+        mRegularColor = a.getColor(R.styleable.LockPatternView_regularColor, 0);
+        mErrorColor = a.getColor(R.styleable.LockPatternView_errorColor, 0);
+        mSuccessColor = a.getColor(R.styleable.LockPatternView_successColor, 0);
 
         int pathColor = a.getColor(R.styleable.LockPatternView_pathColor, mRegularColor);
         mPathPaint.setColor(pathColor);
diff --git a/core/java/com/android/internal/widget/ResolverDrawerLayout.java b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
index e84cc27..e224b17 100644
--- a/core/java/com/android/internal/widget/ResolverDrawerLayout.java
+++ b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
@@ -748,6 +748,10 @@
         final int widthSpec = MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY);
         final int heightSpec = MeasureSpec.makeMeasureSpec(heightSize, MeasureSpec.EXACTLY);
         final int widthPadding = getPaddingLeft() + getPaddingRight();
+
+        // Currently we allot more height than is really needed so that the entirety of the
+        // sheet may be pulled up.
+        // TODO: Restrict the height here to be the right value.
         int heightUsed = getPaddingTop() + getPaddingBottom();
 
         // Measure always-show children first.
@@ -757,7 +761,7 @@
             final LayoutParams lp = (LayoutParams) child.getLayoutParams();
             if (lp.alwaysShow && child.getVisibility() != GONE) {
                 measureChildWithMargins(child, widthSpec, widthPadding, heightSpec, heightUsed);
-                heightUsed += getHeightUsed(child);
+                heightUsed += child.getMeasuredHeight();
             }
         }
 
@@ -769,7 +773,7 @@
             final LayoutParams lp = (LayoutParams) child.getLayoutParams();
             if (!lp.alwaysShow && child.getVisibility() != GONE) {
                 measureChildWithMargins(child, widthSpec, widthPadding, heightSpec, heightUsed);
-                heightUsed += getHeightUsed(child);
+                heightUsed += child.getMeasuredHeight();
             }
         }
 
@@ -785,36 +789,6 @@
         setMeasuredDimension(sourceWidth, heightSize);
     }
 
-    private int getHeightUsed(View child) {
-        // This method exists because we're taking a fast path at measuring ListViews that
-        // lets us get away with not doing the more expensive wrap_content measurement which
-        // imposes double child view measurement costs. If we're looking at a ListView, we can
-        // check against the lowest child view plus padding and margin instead of the actual
-        // measured height of the ListView. This lets the ListView hang off the edge when
-        // all of the content would fit on-screen.
-
-        int heightUsed = child.getMeasuredHeight();
-        if (child instanceof AbsListView) {
-            final AbsListView lv = (AbsListView) child;
-            final int lvPaddingBottom = lv.getPaddingBottom();
-
-            int lowest = 0;
-            for (int i = 0, N = lv.getChildCount(); i < N; i++) {
-                final int bottom = lv.getChildAt(i).getBottom() + lvPaddingBottom;
-                if (bottom > lowest) {
-                    lowest = bottom;
-                }
-            }
-
-            if (lowest < heightUsed) {
-                heightUsed = lowest;
-            }
-        }
-
-        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-        return lp.topMargin + heightUsed + lp.bottomMargin;
-    }
-
     @Override
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
         final int width = getWidth();
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index eaf9e91..4322105 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -1021,17 +1021,13 @@
         env->ReleaseStringCritical(fileName, str);
     }
 
-    int fd = open(fileName8.string(), O_CREAT | O_WRONLY | O_NOFOLLOW, 0666);  /* -rw-rw-rw- */
+    int fd = open(fileName8.string(), O_CREAT | O_WRONLY | O_NOFOLLOW | O_CLOEXEC | O_APPEND, 0666);
     if (fd < 0) {
         fprintf(stderr, "Can't open %s: %s\n", fileName8.string(), strerror(errno));
         return;
     }
 
-    if (lseek(fd, 0, SEEK_END) < 0) {
-        fprintf(stderr, "lseek: %s\n", strerror(errno));
-    } else {
-        dump_backtrace_to_file_timeout(pid, fd, timeoutSecs);
-    }
+    dump_backtrace_to_file_timeout(pid, fd, timeoutSecs);
 
     close(fd);
 }
diff --git a/core/proto/android/os/looper.proto b/core/proto/android/os/looper.proto
new file mode 100644
index 0000000..9fcc781
--- /dev/null
+++ b/core/proto/android/os/looper.proto
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto3";
+
+package android.os;
+
+option java_multiple_files = true;
+
+import "frameworks/base/core/proto/android/os/messagequeue.proto";
+
+message LooperProto {
+    string thread_name = 1;
+    int64 thread_id = 2;
+    int32 identity_hash_code = 3;
+    android.os.MessageQueueProto queue = 4;
+}
diff --git a/core/proto/android/os/message.proto b/core/proto/android/os/message.proto
new file mode 100644
index 0000000..604935d
--- /dev/null
+++ b/core/proto/android/os/message.proto
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto3";
+
+package android.os;
+
+option java_multiple_files = true;
+
+message MessageProto {
+    int64 when = 1;
+    // Name of callback class.
+    string callback = 2;
+    // User-defined message code so that the recipient can identify what this
+    // message is about.
+    int32 what = 3;
+    int32 arg1 = 4;
+    int32 arg2 = 5;
+    // String representation of an arbitrary object to send to the recipient.
+    string obj = 6;
+    // Name of target class.
+    string target = 7;
+    int32 barrier = 8;
+}
diff --git a/core/proto/android/os/messagequeue.proto b/core/proto/android/os/messagequeue.proto
new file mode 100644
index 0000000..9bff13e
--- /dev/null
+++ b/core/proto/android/os/messagequeue.proto
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto3";
+
+package android.os;
+
+option java_multiple_files = true;
+
+import "frameworks/base/core/proto/android/os/message.proto";
+
+message MessageQueueProto {
+    repeated android.os.MessageProto messages = 1;
+    bool is_polling_locked = 2;
+    bool is_quitting = 3;
+}
diff --git a/core/proto/android/os/worksource.proto b/core/proto/android/os/worksource.proto
new file mode 100644
index 0000000..c2aa5cb
--- /dev/null
+++ b/core/proto/android/os/worksource.proto
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto3";
+
+package android.os;
+
+option java_multiple_files = true;
+
+message WorkSourceProto {
+    message WorkSourceContentProto {
+        int32 uid = 1;
+        string name = 2;
+    }
+
+    repeated WorkSourceContentProto work_source_contents = 1;
+}
\ No newline at end of file
diff --git a/core/proto/android/service/package.proto b/core/proto/android/service/package.proto
new file mode 100644
index 0000000..326b0eb
--- /dev/null
+++ b/core/proto/android/service/package.proto
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto3";
+
+package android.service.pm;
+
+option java_multiple_files = true;
+option java_outer_classname = "PackageServiceProto";
+
+message PackageServiceDumpProto {
+    message PackageShortProto {
+        // Name of package. e.g. "com.android.providers.telephony".
+        string name = 1;
+        // UID for this package as assigned by Android OS.
+        int32 uid = 2;
+    }
+    message SharedLibraryProto {
+        string name = 1;
+        // True if library path is not null (jar), false otherwise (apk)
+        bool is_jar = 2;
+        // Should be filled if is_jar is true
+        string path = 3;
+        // Should be filled if is_jar is false
+        string apk = 4;
+    }
+    message FeatureProto {
+        string name = 1;
+        int32 version = 2;
+    }
+    message SharedUserProto {
+        int32 user_id = 1;
+        string name = 2;
+    }
+
+    // Installed packages.
+    PackageShortProto required_verifier_package = 1;
+    PackageShortProto verifier_package = 2;
+    repeated SharedLibraryProto shared_libraries = 3;
+    repeated FeatureProto features = 4;
+    repeated PackageProto packages = 5;
+    repeated SharedUserProto shared_users = 6;
+    // Messages from the settings problem file
+    repeated string messages = 7;
+}
+
+message PackageProto {
+    message SplitProto {
+        string name = 1;
+        int32 revision_code = 2;
+    }
+    message UserInfoProto {
+        enum InstallType {
+            NOT_INSTALLED_FOR_USER = 0;
+            FULL_APP_INSTALL = 1;
+            INSTANT_APP_INSTALL = 2;
+        }
+        // Enum values gotten from PackageManger.java
+        enum EnabledState {
+            // This component or application is in its default enabled state
+            // (as specified in its manifest).
+            COMPONENT_ENABLED_STATE_DEFAULT = 0;
+            // This component or application has been explictily enabled, regardless
+            // of what it has specified in its manifest.
+            COMPONENT_ENABLED_STATE_ENABLED = 1;
+            // This component or application has been explicitly disabled, regardless of
+            // what it has specified in its manifest.
+            COMPONENT_ENABLED_STATE_DISABLED = 2;
+            // The user has explicitly disabled the application, regardless of what it has
+            // specified in its manifest.
+            COMPONENT_ENABLED_STATE_DISABLED_USER = 3;
+            // This application should be considered, until the point where the user actually
+            // wants to use it.
+            COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED = 4;
+        }
+
+        int32 id = 1;
+        InstallType install_type = 2;
+        // Is the app restricted by owner / admin
+        bool is_hidden = 3;
+        bool is_suspended = 4;
+        bool is_stopped = 5;
+        bool is_launched = 6;
+        EnabledState enabled_state = 7;
+        string last_disabled_app_caller = 8;
+    }
+
+    // Name of package. e.g. "com.android.providers.telephony".
+    string name = 1;
+    // UID for this package as assigned by Android OS.
+    int32 uid = 2;
+    // Package's reported version.
+    int32 version_code = 3;
+    // Package's reported version string (what's displayed to the user).
+    string version_string = 4;
+    // UTC timestamp of install
+    int64 install_time_ms = 5;
+    // Millisecond UTC timestamp of latest update adjusted to Google's server clock.
+    int64 update_time_ms = 6;
+    // From "dumpsys package" - name of package which installed this one.
+    // Typically "" if system app or "com.android.vending" if Play Store.
+    string installer_name = 7;
+    // Split APKs.
+    repeated SplitProto splits = 8;
+    // Per-user package info.
+    repeated UserInfoProto users = 9;
+}
diff --git a/core/proto/android/service/power.proto b/core/proto/android/service/power.proto
new file mode 100644
index 0000000..1830dbf
--- /dev/null
+++ b/core/proto/android/service/power.proto
@@ -0,0 +1,408 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto3";
+
+package android.service.power;
+
+option java_multiple_files = true;
+option java_outer_classname = "PowerServiceProto";
+
+import "frameworks/base/core/proto/android/os/looper.proto";
+import "frameworks/base/core/proto/android/os/worksource.proto";
+import "frameworks/base/core/proto/android/service/wirelesschargerdetector.proto";
+
+message PowerServiceDumpProto {
+    message ConstantsProto {
+        bool is_no_cached_wake_locks = 1;
+    }
+    message ActiveWakeLocksProto {
+        bool is_cpu = 1;
+        bool is_screen_bright = 2;
+        bool is_screen_dim = 3;
+        bool is_button_bright = 4;
+        bool is_proximity_screen_off = 5;
+        // only set if already awake
+        bool is_stay_awake = 6;
+        bool is_doze = 7;
+        bool is_draw = 8;
+    }
+    message UserActivityProto {
+        bool is_screen_bright = 1;
+        bool is_screen_dim = 2;
+        bool is_screen_dream = 3;
+    }
+    message UidProto {
+        // Enum values gotten from ActivityManager.java
+        enum ProcessState {
+            // Process is a persistent system process.
+            PROCESS_STATE_PERSISTENT = 0;
+            // Process is a persistent system process and is doing UI.
+            PROCESS_STATE_PERSISTENT_UI = 1;
+            // Process is hosting the current top activities. Note that this
+            // covers all activities that are visible to the user.
+            PROCESS_STATE_TOP = 2;
+            // Process is hosting a foreground service due to a system binding.
+            PROCESS_STATE_BOUND_FOREGROUND_SERVICE = 3;
+            // Process is hosting a foreground service.
+            PROCESS_STATE_FOREGROUND_SERVICE = 4;
+            // Same as {@link #PROCESS_STATE_TOP} but while device is sleeping.
+            PROCESS_STATE_TOP_SLEEPING = 5;
+            // Process is important to the user, and something they are aware of.
+            PROCESS_STATE_IMPORTANT_FOREGROUND = 6;
+            // Process is important to the user, but not something they are aware of.
+            PROCESS_STATE_IMPORTANT_BACKGROUND = 7;
+            // Process is in the background running a backup/restore operation.
+            PROCESS_STATE_BACKUP = 8;
+            // Process is in the background, but it can't restore its state so
+            // we want to try to avoid killing it.
+            PROCESS_STATE_HEAVY_WEIGHT = 9;
+            // Process is in the background running a service.
+            PROCESS_STATE_SERVICE = 10;
+            // Process is in the background running a receiver.
+            PROCESS_STATE_RECEIVER = 11;
+            // Process is in the background but hosts the home activity.
+            PROCESS_STATE_HOME = 12;
+            // Process is in the background but hosts the last shown activity.
+            PROCESS_STATE_LAST_ACTIVITY = 13;
+            // Process is being cached for later use and contains activities.
+            PROCESS_STATE_CACHED_ACTIVITY = 14;
+            // Process is being cached for later use and is a client of another
+            // cached process that contains activities.
+            PROCESS_STATE_CACHED_ACTIVITY_CLIENT = 15;
+            // Process is being cached for later use and is empty.
+            PROCESS_STATE_CACHED_EMPTY = 16;
+            // Process does not exist.
+            PROCESS_STATE_NONEXISTENT = 17;
+        }
+        int32 uid = 1;
+        string uid_string = 2;
+        bool is_active = 3;
+        int32 num_wake_locks = 4;
+        bool is_process_state_unknown = 5;
+        ProcessState process_state = 6;
+    }
+
+    // Enum values gotten from PowerManagerInternal.java
+    enum Wakefulness {
+        WAKEFULNESS_ASLEEP = 0;
+        WAKEFULNESS_AWAKE = 1;
+        WAKEFULNESS_DREAMING = 2;
+        WAKEFULNESS_DOZING = 3;
+        WAKEFULNESS_UNKNOWN = 4;
+    }
+    // Enum values gotten from BatteryManager.java
+    enum PlugType {
+        PLUG_TYPE_NONE = 0;
+        PLUG_TYPE_PLUGGED_AC = 1;
+        PLUG_TYPE_PLUGGED_USB = 2;
+        PLUG_TYPE_PLUGGED_WIRELESS = 4;
+    }
+    // Enum values gotten from Intent.java
+    enum DockState {
+        DOCK_STATE_UNDOCKED = 0;
+        DOCK_STATE_DESK = 1;
+        DOCK_STATE_CAR = 2;
+        DOCK_STATE_LE_DESK = 3;
+        DOCK_STATE_HE_DESK = 4;
+    }
+
+    ConstantsProto constants = 1;
+    // A bitfield that indicates what parts of the power state have
+    // changed and need to be recalculated.
+    int32 dirty = 2;
+    // Indicates whether the device is awake or asleep or somewhere in between.
+    Wakefulness wakefulness = 3;
+    bool is_wakefulness_changing = 4;
+    // True if the device is plugged into a power source.
+    bool is_powered = 5;
+    // The current plug type
+    PlugType plug_type = 6;
+    // The current battery level percentage.
+    int32 battery_level = 7;
+    // The battery level percentage at the time the dream started.
+    int32 battery_level_when_dream_started = 8;
+    // The current dock state.
+    DockState dock_state = 9;
+    // True if the device should stay on.
+    bool is_stay_on = 10;
+    // True if the proximity sensor reads a positive result.
+    bool is_proximity_positive = 11;
+    // True if boot completed occurred.  We keep the screen on until this happens.
+    bool is_boot_completed = 12;
+    // True if systemReady() has been called.
+    bool is_system_ready = 13;
+    // True if auto-suspend mode is enabled.
+    bool is_hal_auto_suspend_mode_enabled = 14;
+    // True if interactive mode is enabled.
+    bool is_hal_auto_interactive_mode_enabled = 15;
+    // Summarizes the state of all active wakelocks.
+    ActiveWakeLocksProto active_wake_locks = 16;
+    // Have we scheduled a message to check for long wake locks?  This is when
+    // we will check. (In milliseconds timestamp)
+    int64 notify_long_scheduled_ms = 17;
+    // Last time we checked for long wake locks. (In milliseconds timestamp)
+    int64 notify_long_dispatched_ms = 18;
+    // The time we decided to do next long check. (In milliseconds timestamp)
+    int64 notify_long_next_check_ms = 19;
+    // Summarizes the effect of the user activity timer.
+    UserActivityProto user_activity = 20;
+    // If true, instructs the display controller to wait for the proximity
+    // sensor to go negative before turning the screen on.
+    bool is_request_wait_for_negative_proximity = 21;
+    // True if MSG_SANDMAN has been scheduled.
+    bool is_sandman_scheduled = 22;
+    // True if the sandman has just been summoned for the first time since entering
+    // the dreaming or dozing state.  Indicates whether a new dream should begin.
+    bool is_sandman_summoned = 23;
+    // If true, the device is in low power mode.
+    bool is_low_power_mode_enabled = 24;
+    // True if the battery level is currently considered low.
+    bool is_battery_level_low = 25;
+    // True if we are currently in light device idle mode.
+    bool is_light_device_idle_mode = 26;
+    // True if we are currently in device idle mode.
+    bool is_device_idle_mode = 27;
+    // Set of app ids that we will always respect the wake locks for.
+    repeated int32 device_idle_whitelist = 28;
+    // Set of app ids that are temporarily allowed to acquire wakelocks due to
+    // high-pri message
+    repeated int32 device_idle_temp_whitelist = 29;
+    // Timestamp of the last time the device was awoken.
+    int64 last_wake_time_ms = 30;
+    // Timestamp of the last time the device was put to sleep.
+    int64 last_sleep_time_ms = 31;
+    // Timestamp of the last call to user activity.
+    int64 last_user_activity_time_ms = 32;
+    int64 last_user_activity_time_no_change_lights_ms = 33;
+    // Timestamp of last interactive power hint.
+    int64 last_interactive_power_hint_time_ms = 34;
+    // Timestamp of the last screen brightness boost.
+    int64 last_screen_brightness_boost_time_ms = 35;
+    // True if screen brightness boost is in progress.
+    bool is_screen_brightness_boost_in_progress = 36;
+    // True if the display power state has been fully applied, which means the
+    // display is actually on or actually off or whatever was requested.
+    bool is_display_ready = 37;
+    // True if the wake lock suspend blocker has been acquired.
+    bool is_holding_wake_lock_suspend_blocker = 38;
+    // The suspend blocker used to keep the CPU alive when the display is on, the
+    // display is getting ready or there is user activity (in which case the
+    // display must be on).
+    bool is_holding_display_suspend_blocker = 39;
+    // Settings and configuration
+    PowerServiceSettingsAndConfigurationDumpProto settings_and_configuration = 40;
+    // Sleep timeout in ms
+    sint32 sleep_timeout_ms = 41;
+    // Screen off timeout in ms
+    int32 screen_off_timeout_ms = 42;
+    // Screen dim duration in ms
+    int32 screen_dim_duration_ms = 43;
+    // We are currently in the middle of a batch change of uids.
+    bool are_uids_changing = 44;
+    // Some uids have actually changed while mUidsChanging was true.
+    bool are_uids_changed = 45;
+    // List of UIDs and their states
+    repeated UidProto uids = 46;
+    android.os.LooperProto looper = 47;
+    // List of all wake locks acquired by applications.
+    repeated WakeLockProto wake_locks = 48;
+    // List of all suspend blockers.
+    repeated SuspendBlockerProto suspend_blockers = 49;
+    WirelessChargerDetectorProto wireless_charger_detector = 50;
+}
+
+message SuspendBlockerProto {
+    string name = 1;
+    int32 reference_count = 2;
+}
+
+message WakeLockProto {
+    message WakeLockFlagsProto {
+        // Turn the screen on when the wake lock is acquired.
+        bool is_acquire_causes_wakeup = 1;
+        // When this wake lock is released, poke the user activity timer
+        // so the screen stays on for a little longer.
+        bool is_on_after_release = 2;
+    }
+
+    // Enum values gotten from PowerManager.java
+    enum LockLevel {
+        WAKE_LOCK_INVALID = 0;
+        // Ensures that the CPU is running.
+        PARTIAL_WAKE_LOCK = 1;
+        // Ensures that the screen is on (but may be dimmed).
+        SCREEN_DIM_WAKE_LOCK = 6;
+        // Ensures that the screen is on at full brightness.
+        SCREEN_BRIGHT_WAKE_LOCK = 10;
+        // Ensures that the screen and keyboard backlight are on at full brightness.
+        FULL_WAKE_LOCK = 26;
+        // Turns the screen off when the proximity sensor activates.
+        PROXIMITY_SCREEN_OFF_WAKE_LOCK = 32;
+        // Put the screen in a low power state and allow the CPU to suspend
+        // if no other wake locks are held.
+        DOZE_WAKE_LOCK = 64;
+        // Keep the device awake enough to allow drawing to occur.
+        DRAW_WAKE_LOCK = 128;
+    }
+
+    LockLevel lock_level = 1;
+    string tag = 2;
+    WakeLockFlagsProto flags = 3;
+    bool is_disabled = 4;
+    // Acquire time in ms
+    int64 acq_ms = 5;
+    bool is_notified_long = 6;
+    // Owner UID
+    int32 uid = 7;
+    // Owner PID
+    int32 pid = 8;
+    android.os.WorkSourceProto work_source = 9;
+}
+
+message PowerServiceSettingsAndConfigurationDumpProto {
+    message StayOnWhilePluggedInProto {
+        bool is_stay_on_while_plugged_in_ac = 1;
+        bool is_stay_on_while_plugged_in_usb = 2;
+        bool is_stay_on_while_plugged_in_wireless = 3;
+    }
+    message ScreenBrightnessSettingLimitsProto {
+        int32 setting_minimum = 1;
+        int32 setting_maximum = 2;
+        int32 setting_default = 3;
+        int32 setting_for_vr_default = 4;
+    }
+
+    // Enum values gotten from Settings.java
+    enum ScreenBrightnessMode {
+        SCREEN_BRIGHTNESS_MODE_MANUAL = 0;
+        SCREEN_BRIGHTNESS_MODE_AUTOMATIC = 1;
+    }
+    // Enum values gotten from Display.java
+    enum DisplayState {
+        DISPLAY_STATE_UNKNOWN = 0;
+        DISPLAY_STATE_OFF = 1;
+        DISPLAY_STATE_ON = 2;
+        DISPLAY_STATE_DOZE = 3;
+        DISPLAY_STATE_DOZE_SUSPEND = 4;
+        DISPLAY_STATE_VR = 5;
+    }
+
+
+    // True to decouple auto-suspend mode from the display state.
+    bool is_decouple_hal_auto_suspend_mode_from_display_config = 1;
+    // True to decouple interactive mode from the display state.
+    bool is_decouple_hal_interactive_mode_from_display_config = 2;
+    // True if the device should wake up when plugged or unplugged.
+    bool is_wake_up_when_plugged_or_unplugged_config = 3;
+    // True if the device should wake up when plugged or unplugged in theater mode.
+    bool is_wake_up_when_plugged_or_unplugged_in_theater_mode_config = 4;
+    // True if theater mode is enabled
+    bool is_theater_mode_enabled = 5;
+    // True if the device should suspend when the screen is off due to proximity.
+    bool is_suspend_when_screen_off_due_to_proximity_config = 6;
+    // True if dreams are supported on this device.
+    bool are_dreams_supported_config = 7;
+    // Default value for dreams enabled
+    bool are_dreams_enabled_by_default_config = 8;
+    // Default value for dreams activate-on-sleep
+    bool are_dreams_activated_on_sleep_by_default_config = 9;
+    // Default value for dreams activate-on-dock
+    bool are_dreams_activated_on_dock_by_default_config = 10;
+    // True if dreams can run while not plugged in.
+    bool are_dreams_enabled_on_battery_config = 11;
+    // Minimum battery level to allow dreaming when powered.
+    // Use -1 to disable this safety feature.
+    sint32 dreams_battery_level_minimum_when_powered_config = 12;
+    // Minimum battery level to allow dreaming when not powered.
+    // Use -1 to disable this safety feature.
+    sint32 dreams_battery_level_minimum_when_not_powered_config = 13;
+    // If the battery level drops by this percentage and the user activity
+    // timeout has expired, then assume the device is receiving insufficient
+    // current to charge effectively and terminate the dream.  Use -1 to disable
+    // this safety feature.
+    sint32 dreams_battery_level_drain_cutoff_config = 14;
+    // True if dreams are enabled by the user.
+    bool are_dreams_enabled_setting = 15;
+    // True if dreams should be activated on sleep.
+    bool are_dreams_activate_on_sleep_setting = 16;
+    // True if dreams should be activated on dock.
+    bool are_dreams_activate_on_dock_setting = 17;
+    // True if doze should not be started until after the screen off transition.
+    bool is_doze_after_screen_off_config = 18;
+    // If true, the device is in low power mode.
+    bool is_low_power_mode_setting = 19;
+    // Current state of whether the settings are allowing auto low power mode.
+    bool is_auto_low_power_mode_configured = 20;
+    // The user turned off low power mode below the trigger level
+    bool is_auto_low_power_mode_snoozing = 21;
+    // The minimum screen off timeout, in milliseconds.
+    int32 minimum_screen_off_timeout_config_ms = 22;
+    // The screen dim duration, in milliseconds.
+    int32 maximum_screen_dim_duration_config_ms = 23;
+    // The maximum screen dim time expressed as a ratio relative to the screen off timeout.
+    float maximum_screen_dim_ratio_config = 24;
+    // The screen off timeout setting value in milliseconds.
+    int32 screen_off_timeout_setting_ms = 25;
+    // The sleep timeout setting value in milliseconds.
+    sint32 sleep_timeout_setting_ms = 26;
+    // The maximum allowable screen off timeout according to the device administration policy.
+    int32 maximum_screen_off_timeout_from_device_admin_ms = 27;
+    bool is_maximum_screen_off_timeout_from_device_admin_enforced_locked = 28;
+    // The stay on while plugged in setting.
+    // A set of battery conditions under which to make the screen stay on.
+    StayOnWhilePluggedInProto stay_on_while_plugged_in = 29;
+    // The screen brightness setting, from 0 to 255.
+    // Use -1 if no value has been set.
+    sint32 screen_brightness_setting = 30;
+    // The screen auto-brightness adjustment setting, from -1 to 1.
+    // Use 0 if there is no adjustment.
+    float screen_auto_brightness_adjustment_setting = 31;
+    // The screen brightness mode.
+    ScreenBrightnessMode screen_brightness_mode_setting = 32;
+    // The screen brightness setting override from the window manager
+    // to allow the current foreground activity to override the brightness.
+    // Use -1 to disable.
+    sint32 screen_brightness_override_from_window_manager = 33;
+    // The user activity timeout override from the window manager
+    // to allow the current foreground activity to override the user activity
+    // timeout. Use -1 to disable.
+    sint64 user_activity_timeout_override_from_window_manager_ms = 34;
+    // The window manager has determined the user to be inactive via other means.
+    // Set this to false to disable.
+    bool is_user_inactive_override_from_window_manager = 35;
+    // The screen brightness setting override from the settings application
+    // to temporarily adjust the brightness until next updated,
+    // Use -1 to disable.
+    sint32 temporary_screen_brightness_setting_override = 36;
+    // The screen brightness adjustment setting override from the settings
+    // application to temporarily adjust the auto-brightness adjustment factor
+    // until next updated, in the range -1..1.
+    // Use NaN to disable.
+    float temporary_screen_auto_brightness_adjustment_setting_override = 37;
+    // The screen state to use while dozing.
+    DisplayState doze_screen_state_override_from_dream_manager = 38;
+    // The screen brightness to use while dozing.
+    float dozed_screen_brightness_override_from_dream_manager = 39;
+    // Screen brightness settings limits.
+    ScreenBrightnessSettingLimitsProto screen_brightness_setting_limits = 40;
+    // The screen brightness setting, from 0 to 255, to be used while in VR Mode.
+    int32 screen_brightness_for_vr_setting = 41;
+    // True if double tap to wake is enabled
+    bool is_double_tap_wake_enabled = 42;
+    // True if we are currently in VR Mode.
+    bool is_vr_mode_enabled = 43;
+}
diff --git a/core/proto/android/service/wirelesschargerdetector.proto b/core/proto/android/service/wirelesschargerdetector.proto
new file mode 100644
index 0000000..7ba7c17
--- /dev/null
+++ b/core/proto/android/service/wirelesschargerdetector.proto
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto3";
+
+package android.service.power;
+
+option java_multiple_files = true;
+
+message WirelessChargerDetectorProto {
+    message VectorProto {
+        float x = 1;
+        float y = 2;
+        float z = 3;
+    }
+
+    // Previously observed wireless power state.
+    bool is_powered_wirelessly = 1;
+    // True if the device is thought to be at rest on a wireless charger.
+    bool is_at_rest = 2;
+    // The gravity vector most recently observed while at rest.
+    VectorProto rest = 3;
+    // True if detection is in progress.
+    bool is_detection_in_progress = 4;
+    // The time when detection was last performed.
+    int64 detection_start_time_ms = 5;
+    // True if the rest position should be updated if at rest.
+    bool is_must_update_rest_position = 6;
+    // The total number of samples collected.
+    int32 total_samples = 7;
+    // The number of samples collected that showed evidence of not being at rest.
+    int32 moving_samples = 8;
+    // The value of the first sample that was collected.
+    VectorProto first_sample = 9;
+    // The value of the last sample that was collected.
+    VectorProto last_sample = 10;
+}
\ No newline at end of file
diff --git a/core/res/res/layout/app_permission_item_money.xml b/core/res/res/layout/app_permission_item_money.xml
index 2056285..764c883 100644
--- a/core/res/res/layout/app_permission_item_money.xml
+++ b/core/res/res/layout/app_permission_item_money.xml
@@ -57,14 +57,14 @@
             android:layout_alignParentStart="true"
             android:layout_alignBottom="@+id/perm_money_label"
             android:scaleType="fitCenter"
-            android:tint="@color/perms_costs_money"
+            android:tint="?android:attr/colorError"
             android:tintMode="src_in"
             android:src="@android:drawable/ic_coins_s" />
         <TextView
             android:id="@+id/perm_money_label"
             android:textAppearance="?android:attr/textAppearanceSmall"
             android:textSize="16sp"
-            android:textColor="@color/perms_costs_money"
+            android:textColor="?android:attr/colorError"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_toEndOf="@id/perm_money_icon"
diff --git a/core/res/res/layout/time_picker_text_input_material.xml b/core/res/res/layout/time_picker_text_input_material.xml
index f17b80e..632a4c1 100644
--- a/core/res/res/layout/time_picker_text_input_material.xml
+++ b/core/res/res/layout/time_picker_text_input_material.xml
@@ -77,7 +77,7 @@
             android:layout_height="wrap_content"
             android:layout_below="@id/input_hour"
             android:layout_alignStart="@id/input_hour"
-            android:textColor="?attr/textColorError"
+            android:textColor="?attr/colorError"
             android:text="@string/time_picker_input_error" />
     </RelativeLayout>
     <Spinner
@@ -87,4 +87,4 @@
         android:layout_alignBaseline="@id/input_block"
         android:layout_alignParentEnd="true"/>
 
-</merge>
\ No newline at end of file
+</merge>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 8031f19..f55538f 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -66,6 +66,9 @@
         <attr name="primaryContentAlpha" format="float" />
         <!-- The alpha applied to the foreground color to create the secondary text color. -->
         <attr name="secondaryContentAlpha" format="float" />
+        <!-- Color used for error states and things that need to be drawn to
+             the users attention.. -->
+        <attr name="colorError" format="reference|color" />
         <!-- Default background dim amount when a menu, dialog, or something similar pops up. -->
         <attr name="backgroundDimAmount" format="float" />
         <!-- Control whether dimming behind the window is enabled.  The default
@@ -135,9 +138,6 @@
         <!-- Color of list item text in alert dialogs. -->
         <attr name="textColorAlertDialogListItem" format="reference|color" />
 
-        <!-- Text color for errors. -->
-        <attr name="textColorError" format="reference|color" />
-
         <!-- Search widget more corpus result item background. -->
         <attr name="searchWidgetCorpusItemBackground" format="reference|color" />
 
@@ -8531,4 +8531,6 @@
         <attr name="reverseLayout" format="boolean" />
         <attr name="stackFromEnd" format="boolean" />
     </declare-styleable>
+
+    <attr name="lockPatternStyle" format="reference" />
 </resources>
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index b28c6f2..6015ed5 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -75,8 +75,6 @@
     <drawable name="input_method_fullscreen_background">#fff9f9f9</drawable>
     <color name="input_method_navigation_guard">#ff000000</color>
 
-    <color name="system_error">#fff4511e</color> <!-- deep orange 600 -->
-
     <!-- For date picker widget -->
     <drawable name="selected_day_background">#ff0092f4</drawable>
 
@@ -88,7 +86,6 @@
     <color name="perms_dangerous_grp_color">#33b5e5</color>
     <color name="perms_dangerous_perm_color">#33b5e5</color>
     <color name="shadow">#cc222222</color>
-    <color name="perms_costs_money">#fff4511e</color>
 
     <!-- For search-related UIs -->
     <color name="search_url_text_normal">#7fa87f</color>
@@ -121,7 +118,6 @@
     <!-- LockPatternView -->
     <color name="lock_pattern_view_regular_color">#ffffffff</color>
     <color name="lock_pattern_view_success_color">#ffffffff</color>
-    <color name="lock_pattern_view_error_color">@color/system_error</color>
 
     <!-- FaceLock -->
     <color name="facelock_spotlight_mask">#CC000000</color>
@@ -156,7 +152,6 @@
     <color name="accessibility_focus_highlight">#bf39b500</color>
 
     <color name="system_notification_accent_color">#ff607D8B</color>
-    <color name="battery_saver_mode_color">#fff4511e</color><!-- deep orange 600 -->
 
     <!-- Default user icon colors -->
     <color name="user_icon_1">#ff00bcd4</color><!-- cyan 500 -->
diff --git a/core/res/res/values/colors_material.xml b/core/res/res/values/colors_material.xml
index 0a24565..e0cc5b5 100644
--- a/core/res/res/values/colors_material.xml
+++ b/core/res/res/values/colors_material.xml
@@ -46,6 +46,7 @@
 
     <color name="button_material_dark">#ff5a595b</color>
     <color name="button_material_light">#ffd6d7d7</color>
+    <color name="error_color_material">#F4511E</color>
 
     <color name="switch_thumb_normal_material_dark">#ffbdbdbd</color>
     <color name="switch_thumb_normal_material_light">#fff1f1f1</color>
@@ -65,9 +66,6 @@
     <!-- 70% white -->
     <color name="secondary_text_default_material_dark">#b3ffffff</color>
 
-    <color name="error_text_material_light">@color/material_red_A700</color>
-    <color name="error_text_material_dark">@color/material_red_A100</color>
-
     <item name="hint_alpha_material_dark" format="float" type="dimen">0.50</item>
     <item name="hint_alpha_material_light" format="float" type="dimen">0.38</item>
 
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index d233e24..35aff80 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2748,8 +2748,8 @@
     <!-- Flag indicates that whether non-system apps can be installed on internal storage. -->
     <bool name="config_allow3rdPartyAppOnInternal">true</bool>
 
-    <!-- Component name of the default cell broadcast receiver -->
-    <string name="config_defaultCellBroadcastReceiverComponent" translatable="false">com.android.cellbroadcastreceiver/.PrivilegedCellBroadcastReceiver</string>
+    <!-- Package name of the default cell broadcast receiver -->
+    <string name="config_defaultCellBroadcastReceiverPkg" translatable="false">com.android.cellbroadcastreceiver</string>
 
     <!-- Specifies the path that is used by AdaptiveIconDrawable class to crop launcher icons. -->
     <string name="config_icon_mask" translatable="false">"M50,0L100,0 100,100 0,100 0,0z"</string>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 78549b5..e5660b5 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2780,7 +2780,7 @@
         <public name="targetProcess" />
         <public name="nextClusterForward" />
         <public name="__removed1" />
-        <public name="textColorError" />
+        <public name="colorError" />
         <public name="focusedByDefault" />
         <public name="appCategory" />
         <public name="autoSizeMaxTextSize" />
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index faf451b..25873d2 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -1475,4 +1475,10 @@
         <item name="padding">16dp</item>
     </style>
 
+    <style name="Widget.LockPatternView">
+        <item name="regularColor">@color/lock_pattern_view_regular_color</item>
+        <item name="errorColor">?attr/colorError</item>
+        <item name="successColor">@color/lock_pattern_view_success_color</item>
+    </style>
+
 </resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index e7d3ec9..49216d9 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1195,7 +1195,6 @@
   <java-symbol type="drawable" name="btn_check_off" />
   <java-symbol type="color" name="lock_pattern_view_regular_color" />
   <java-symbol type="color" name="lock_pattern_view_success_color" />
-  <java-symbol type="color" name="lock_pattern_view_error_color" />
   <java-symbol type="dimen" name="lock_pattern_dot_line_width" />
   <java-symbol type="dimen" name="lock_pattern_dot_size" />
   <java-symbol type="dimen" name="lock_pattern_dot_size_activated" />
@@ -2310,7 +2309,6 @@
   <java-symbol type="layout" name="select_dialog_singlechoice_material" />
   <java-symbol type="layout" name="select_dialog_multichoice_material" />
   <java-symbol type="array" name="no_ems_support_sim_operators" />
-  <java-symbol type="color" name="battery_saver_mode_color" />
   <java-symbol type="color" name="system_notification_accent_color" />
   <java-symbol type="dimen" name="text_handle_min_size" />
   <java-symbol type="id" name="transitionTransform" />
@@ -2798,7 +2796,7 @@
   <java-symbol type="drawable" name="lockscreen_selected" />
 
   <java-symbol type="string" name="notification_header_divider_symbol_with_spaces" />
-  <java-symbol type="string" name="config_defaultCellBroadcastReceiverComponent" />
+  <java-symbol type="string" name="config_defaultCellBroadcastReceiverPkg" />
 
   <java-symbol type="color" name="notification_primary_text_color_light" />
   <java-symbol type="color" name="notification_primary_text_color_dark" />
@@ -2853,7 +2851,7 @@
 
   <!-- android.service.trust -->
   <java-symbol type="bool" name="config_allowEscrowTokenForTrustAgent"/>
-  
+
   <!-- Time picker -->
   <java-symbol type="id" name="toggle_mode"/>
   <java-symbol type="id" name="input_mode"/>
@@ -2880,6 +2878,8 @@
   <java-symbol type="string" name="alert_windows_notification_message" />
   <java-symbol type="string" name="alert_windows_notification_turn_off_action" />
   <java-symbol type="drawable" name="alert_window_layer" />
+  <java-symbol type="style" name="Widget.LockPatternView" />
+  <java-symbol type="attr" name="lockPatternStyle" />
 
   <!-- Colon separated list of package names that should be granted Notification Listener access -->
   <java-symbol type="string" name="config_defaultListenerAccessPackages" />
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index e357678..d100c63 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -63,6 +63,7 @@
         <item name="colorControlHighlight">@color/legacy_button_pressed</item>
         <item name="colorButtonNormal">@color/legacy_button_normal</item>
         <item name="colorEdgeEffect">?attr/colorPrimary</item>
+        <item name="colorError">@color/red</item>
 
         <item name="disabledAlpha">0.5</item>
         <item name="backgroundDimAmount">0.6</item>
@@ -93,7 +94,6 @@
         <item name="textColorLink">@color/link_text_dark</item>
         <item name="textColorLinkInverse">@color/link_text_light</item>
         <item name="textColorAlertDialogListItem">@color/primary_text_light_disable_only</item>
-        <item name="textColorError">@color/red</item>
 
         <item name="textAppearanceLarge">@style/TextAppearance.Large</item>
         <item name="textAppearanceMedium">@style/TextAppearance.Medium</item>
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index 400fb47..008c817 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -51,6 +51,7 @@
         <item name="primaryContentAlpha">@dimen/primary_content_alpha_material_dark</item>
         <item name="secondaryContentAlpha">@dimen/secondary_content_alpha_material_dark</item>
         <item name="backgroundDimAmount">0.6</item>
+        <item name="colorError">@color/error_color_material</item>
 
         <!-- Text styles -->
         <item name="textAppearance">@style/TextAppearance.Material</item>
@@ -73,7 +74,6 @@
         <item name="textColorLinkInverse">?attr/colorAccent</item>
         <item name="textColorSearchUrl">@color/search_url_text_material_dark</item>
         <item name="textColorAlertDialogListItem">@color/primary_text_material_dark</item>
-        <item name="textColorError">@color/error_text_material_dark</item>
 
         <item name="textAppearanceLarge">@style/TextAppearance.Material.Large</item>
         <item name="textAppearanceLargeInverse">@style/TextAppearance.Material.Large.Inverse</item>
@@ -441,7 +441,6 @@
         <item name="textColorLinkInverse">?attr/colorAccent</item>
         <item name="textColorSearchUrl">@color/search_url_text_material_light</item>
         <item name="textColorAlertDialogListItem">@color/primary_text_material_light</item>
-        <item name="textColorError">@color/error_text_material_light</item>
 
         <item name="textAppearanceLarge">@style/TextAppearance.Material.Large</item>
         <item name="textAppearanceLargeInverse">@style/TextAppearance.Material.Large.Inverse</item>
@@ -823,7 +822,6 @@
         <item name="textColorHighlightInverse">@color/highlighted_text_material</item>
         <item name="textColorSearchUrl">@color/search_url_text_material_light</item>
         <item name="textColorAlertDialogListItem">@color/primary_text_material_light</item>
-        <item name="textColorError">@color/error_text_material_light</item>
 
         <item name="textCheckMark">@drawable/indicator_check_mark_light</item>
         <item name="textCheckMarkInverse">@drawable/indicator_check_mark_dark</item>
@@ -856,7 +854,6 @@
         <item name="textColorHighlightInverse">@color/highlighted_text_material</item>
         <item name="textColorSearchUrl">@color/search_url_text_material_dark</item>
         <item name="textColorAlertDialogListItem">@color/primary_text_material_dark</item>
-        <item name="textColorError">@color/error_text_material_dark</item>
 
         <item name="textCheckMark">@drawable/indicator_check_mark_dark</item>
         <item name="textCheckMarkInverse">@drawable/indicator_check_mark_light</item>
diff --git a/core/tests/coretests/src/android/net/NetworkRecommendationProviderTest.java b/core/tests/coretests/src/android/net/NetworkRecommendationProviderTest.java
index bdc0200..497bc5c 100644
--- a/core/tests/coretests/src/android/net/NetworkRecommendationProviderTest.java
+++ b/core/tests/coretests/src/android/net/NetworkRecommendationProviderTest.java
@@ -3,61 +3,62 @@
 import static android.net.NetworkRecommendationProvider.EXTRA_RECOMMENDATION_RESULT;
 import static android.net.NetworkRecommendationProvider.EXTRA_SEQUENCE;
 
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertSame;
+import static junit.framework.Assert.fail;
+import static junit.framework.TestCase.assertEquals;
+
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+
+import android.Manifest.permission;
 import android.content.Context;
 import android.os.Bundle;
-import android.os.Handler;
-import android.os.HandlerThread;
 import android.os.IRemoteCallback;
-import android.test.InstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
 
 /**
  * Unit test for the {@link NetworkRecommendationProvider}.
  */
-public class NetworkRecommendationProviderTest extends InstrumentationTestCase {
+@RunWith(AndroidJUnit4.class)
+public class NetworkRecommendationProviderTest {
     @Mock private IRemoteCallback mMockRemoteCallback;
+    @Mock private Context mContext;
     private NetworkRecProvider mRecProvider;
-    private Handler mHandler;
     private INetworkRecommendationProvider mStub;
     private CountDownLatch mRecRequestLatch;
     private CountDownLatch mScoreRequestLatch;
     private NetworkKey[] mTestNetworkKeys;
 
-    @Override
+    @Before
     public void setUp() throws Exception {
-        super.setUp();
-
-        // Configuration needed to make mockito/dexcache work.
-        final Context context = getInstrumentation().getTargetContext();
-        System.setProperty("dexmaker.dexcache",
-                context.getCacheDir().getPath());
-        ClassLoader newClassLoader = getInstrumentation().getClass().getClassLoader();
-        Thread.currentThread().setContextClassLoader(newClassLoader);
-
         MockitoAnnotations.initMocks(this);
 
-        HandlerThread thread = new HandlerThread("NetworkRecommendationProviderTest");
-        thread.start();
+        Executor executor = Executors.newSingleThreadExecutor();
         mRecRequestLatch = new CountDownLatch(1);
         mScoreRequestLatch = new CountDownLatch(1);
-        mHandler = new Handler(thread.getLooper());
-        mRecProvider = new NetworkRecProvider(mHandler, mRecRequestLatch, mScoreRequestLatch);
+        mRecProvider = new NetworkRecProvider(mContext, executor, mRecRequestLatch,
+                mScoreRequestLatch);
         mStub = INetworkRecommendationProvider.Stub.asInterface(mRecProvider.getBinder());
         mTestNetworkKeys = new NetworkKey[2];
         mTestNetworkKeys[0] = new NetworkKey(new WifiKey("\"ssid_01\"", "00:00:00:00:00:11"));
         mTestNetworkKeys[1] = new NetworkKey(new WifiKey("\"ssid_02\"", "00:00:00:00:00:22"));
     }
 
-    @MediumTest
+    @Test
     public void testRecommendationRequestReceived() throws Exception {
         final RecommendationRequest request = new RecommendationRequest.Builder().build();
         final int sequence = 100;
@@ -71,7 +72,23 @@
         assertEquals(expectedResultCallback, mRecProvider.mCapturedCallback);
     }
 
-    @SmallTest
+    @Test
+    public void testRecommendationRequest_permissionsEnforced() throws Exception {
+        final RecommendationRequest request = new RecommendationRequest.Builder().build();
+        final int sequence = 100;
+        Mockito.doThrow(new SecurityException())
+                .when(mContext)
+                .enforceCallingOrSelfPermission(eq(permission.REQUEST_NETWORK_SCORES), anyString());
+
+        try {
+            mStub.requestRecommendation(request, mMockRemoteCallback, sequence);
+            fail("SecurityException expected.");
+        } catch (SecurityException e) {
+            // expected
+        }
+    }
+
+    @Test
     public void testResultCallbackOnResult() throws Exception {
         final int sequence = 100;
         final NetworkRecommendationProvider.ResultCallback callback =
@@ -87,7 +104,7 @@
         assertSame(result, capturedBundle.getParcelable(EXTRA_RECOMMENDATION_RESULT));
     }
 
-    @SmallTest
+    @Test
     public void testResultCallbackOnResult_runTwice_throwsException() throws Exception {
         final int sequence = 100;
         final NetworkRecommendationProvider.ResultCallback callback =
@@ -104,7 +121,7 @@
         }
     }
 
-    @MediumTest
+    @Test
     public void testScoreRequestReceived() throws Exception {
         mStub.requestScores(mTestNetworkKeys);
 
@@ -114,7 +131,7 @@
         assertSame(mTestNetworkKeys, mRecProvider.mCapturedNetworks);
     }
 
-    @MediumTest
+    @Test
     public void testScoreRequest_nullInput() throws Exception {
         mStub.requestScores(null);
 
@@ -122,7 +139,7 @@
         assertFalse(mScoreRequestLatch.await(200, TimeUnit.MILLISECONDS));
     }
 
-    @MediumTest
+    @Test
     public void testScoreRequest_emptyInput() throws Exception {
         mStub.requestScores(new NetworkKey[0]);
 
@@ -130,6 +147,20 @@
         assertFalse(mScoreRequestLatch.await(200, TimeUnit.MILLISECONDS));
     }
 
+    @Test
+    public void testScoreRequest_permissionsEnforced() throws Exception {
+        Mockito.doThrow(new SecurityException())
+                .when(mContext)
+                .enforceCallingOrSelfPermission(eq(permission.REQUEST_NETWORK_SCORES), anyString());
+
+        try {
+            mStub.requestScores(mTestNetworkKeys);
+            fail("SecurityException expected.");
+        } catch (SecurityException e) {
+            // expected
+        }
+    }
+
     private static class NetworkRecProvider extends NetworkRecommendationProvider {
         private final CountDownLatch mRecRequestLatch;
         private final CountDownLatch mScoreRequestLatch;
@@ -137,9 +168,9 @@
         ResultCallback mCapturedCallback;
         NetworkKey[] mCapturedNetworks;
 
-        NetworkRecProvider(Handler handler, CountDownLatch recRequestLatch,
+        NetworkRecProvider(Context context, Executor executor, CountDownLatch recRequestLatch,
             CountDownLatch networkRequestLatch) {
-            super(handler);
+            super(context, executor);
             mRecRequestLatch = recRequestLatch;
             mScoreRequestLatch = networkRequestLatch;
         }
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index da6a294..b718263 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -393,6 +393,7 @@
                  Settings.Secure.BACKUP_TRANSPORT,
                  Settings.Secure.BLUETOOTH_HCI_LOG,
                  Settings.Secure.CARRIER_APPS_HANDLED,
+                 Settings.Secure.CMAS_ADDITIONAL_BROADCAST_PKG,
                  Settings.Secure.COMPLETED_CATEGORY_PREFIX,
                  Settings.Secure.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS,
                  Settings.Secure.DEFAULT_INPUT_METHOD,
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index fc31f32..8f341a8 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -113,5 +113,6 @@
     // for reporting callback completion
     void locationCallbackFinished(ILocationListener listener);
 
-
+    // used by gts tests to verify throttling whitelist
+    String[] getBackgroundThrottlingWhitelist();
 }
diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java
index 6d8296a..1b53d72 100644
--- a/media/java/android/media/tv/TvContract.java
+++ b/media/java/android/media/tv/TvContract.java
@@ -25,6 +25,7 @@
 import android.content.ContentUris;
 import android.content.Intent;
 import android.net.Uri;
+import android.os.Bundle;
 import android.os.IBinder;
 import android.provider.BaseColumns;
 import android.text.TextUtils;
@@ -72,6 +73,98 @@
     private static final String PATH_PASSTHROUGH = "passthrough";
 
     /**
+     * The method name to get existing columns in the given table of the specified content provider.
+     *
+     * <p>The method caller must provide the following parameter:
+     * <ul>
+     *     <li>{@code arg}: The content URI of the target table as a {@link String}.</li>
+     * </ul>
+
+     * <p>On success, the returned {@link android.os.Bundle} will include existing column names
+     * with the key {@link #EXTRA_EXISTING_COLUMN_NAMES}. Otherwise, the return value will be {@code null}.
+     *
+     * @see ContentResolver#call(Uri, String, String, Bundle)
+     * @see #EXTRA_EXISTING_COLUMN_NAMES
+     * @hide
+     */
+    @SystemApi
+    public static final String METHOD_GET_COLUMNS = "get_columns";
+
+    /**
+     * The method name to add a new column in the given table of the specified content provider.
+     *
+     * <p>The method caller must provide the following parameter:
+     * <ul>
+     *     <li>{@code arg}: The content URI of the target table as a {@link String}.</li>
+     *     <li>{@code extra}: Name, data type, and default value of the new column in a Bundle:
+     *         <ul>
+     *             <li>{@link #EXTRA_COLUMN_NAME} the column name as a {@link String}.</li>
+     *             <li>{@link #EXTRA_DATA_TYPE} the data type as a {@link String}.</li>
+     *             <li>{@link #EXTRA_DEFAULT_VALUE} the default value as a {@link String}.
+     *                 (optional)</li>
+     *         </ul>
+     *     </li>
+     * </ul>
+     *
+     * <p>On success, the returned {@link android.os.Bundle} will include current colum names after
+     * the addition operation with the key {@link #EXTRA_EXISTING_COLUMN_NAMES}. Otherwise, the
+     * return value will be {@code null}.
+     *
+     * @see ContentResolver#call(Uri, String, String, Bundle)
+     * @see #EXTRA_COLUMN_NAME
+     * @see #EXTRA_DATA_TYPE
+     * @see #EXTRA_DEFAULT_VALUE
+     * @see #EXTRA_EXISTING_COLUMN_NAMES
+     * @hide
+     */
+    @SystemApi
+    public static final String METHOD_ADD_COLUMN = "add_column";
+
+    /**
+     * The key for a returned {@link Bundle} value containing existing column names in the given
+     * table as an {@link ArrayList} of {@link String}.
+     *
+     * @see #METHOD_GET_COLUMNS
+     * @see #METHOD_ADD_COLUMN
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_EXISTING_COLUMN_NAMES =
+            "android.media.tv.extra.EXISTING_COLUMN_NAMES";
+
+    /**
+     * The key for a {@link Bundle} parameter containing the new column name to be added in the
+     * given table as a non-empty {@link CharSequence}.
+     *
+     * @see #METHOD_ADD_COLUMN
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_COLUMN_NAME = "android.media.tv.extra.COLUMN_NAME";
+
+    /**
+     * The key for a {@link Bundle} parameter containing the data type of the new column to be added
+     * in the given table as a non-empty {@link CharSequence}, which should be one of the following
+     * values: {@code "TEXT"}, {@code "INTEGER"}, {@code "REAL"}, or {@code "BLOB"}.
+     *
+     * @see #METHOD_ADD_COLUMN
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_DATA_TYPE = "android.media.tv.extra.DATA_TYPE";
+
+    /**
+     * The key for a {@link Bundle} parameter containing the default value of the new column to be
+     * added in the given table as a {@link CharSequence}, which represents a valid default value
+     * according to the data type provided with {@link #EXTRA_DATA_TYPE}.
+     *
+     * @see #METHOD_ADD_COLUMN
+     * @hide
+     */
+    @SystemApi
+    public static final String EXTRA_DEFAULT_VALUE = "android.media.tv.extra.DEFAULT_VALUE";
+
+    /**
      * An optional query, update or delete URI parameter that allows the caller to specify TV input
      * ID to filter channels.
      * @hide
diff --git a/packages/SettingsLib/res/values/arrays.xml b/packages/SettingsLib/res/values/arrays.xml
index d207c35..9ff22c7 100644
--- a/packages/SettingsLib/res/values/arrays.xml
+++ b/packages/SettingsLib/res/values/arrays.xml
@@ -538,7 +538,7 @@
         <item>100</item>
     </array>
     <array name="batterymeter_color_values">
-        <item>@*android:color/battery_saver_mode_color</item>
+        <item>?android:attr/colorError</item>
         <item>@android:color/white</item>
     </array>
     <array name="batterymeter_bolt_points">
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
index 99d7f1e..49fc2ea 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
@@ -16,6 +16,11 @@
 
 package com.android.settingslib;
 
+import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE;
+import static android.app.admin.DevicePolicyManager.PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.app.AppGlobals;
 import android.app.admin.DevicePolicyManager;
@@ -29,6 +34,7 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
+import android.support.annotation.VisibleForTesting;
 import android.text.Spanned;
 import android.text.SpannableStringBuilder;
 import android.text.style.ForegroundColorSpan;
@@ -108,47 +114,68 @@
     }
 
     /**
-     * Checks if keyguard features are disabled by policy.
+     * Checks whether keyguard features are disabled by policy.
      *
-     * @param keyguardFeatures Could be any of keyguard features that can be
+     * @param context {@link Context} for the calling user.
+     *
+     * @param keyguardFeatures Any one of keyguard features that can be
      * disabled by {@link android.app.admin.DevicePolicyManager#setKeyguardDisabledFeatures}.
+     *
+     * @param userId User to check enforced admin status for.
+     *
      * @return EnforcedAdmin Object containing the enforced admin component and admin user details,
      * or {@code null} If the notification features are not disabled. If the restriction is set by
      * multiple admins, then the admin component will be set to {@code null} and userId to
      * {@link UserHandle#USER_NULL}.
      */
     public static EnforcedAdmin checkIfKeyguardFeaturesDisabled(Context context,
-            int keyguardFeatures, int userId) {
-        final LockSettingCheck check =
-                (DevicePolicyManager dpm, ComponentName admin, @UserIdInt int checkUser) ->
-                        (dpm.getKeyguardDisabledFeatures(admin, checkUser) & keyguardFeatures) != 0;
+            int keyguardFeatures, final @UserIdInt int userId) {
+        final LockSettingCheck check = (dpm, admin, checkUser) -> {
+            int effectiveFeatures = dpm.getKeyguardDisabledFeatures(admin, checkUser);
+            if (checkUser != userId) {
+                effectiveFeatures &= PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER;
+            }
+            return (effectiveFeatures & keyguardFeatures) != KEYGUARD_DISABLE_FEATURES_NONE;
+        };
+        if (UserManager.get(context).getUserInfo(userId).isManagedProfile()) {
+            DevicePolicyManager dpm =
+                    (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
+            return findEnforcedAdmin(dpm.getActiveAdminsAsUser(userId), dpm, userId, check);
+        }
+        return checkForLockSetting(context, userId, check);
+    }
 
-        final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
-                Context.DEVICE_POLICY_SERVICE);
-        if (dpm == null) {
+    /**
+     * Filter a set of device admins based on a predicate {@code check}. This is equivalent to
+     * {@code admins.stream().filter(check).map(x → new EnforcedAdmin(admin, userId)} except it's
+     * returning a zero/one/many-type thing.
+     *
+     * @param admins set of candidate device admins identified by {@link ComponentName}.
+     * @param userId user to create the resultant {@link EnforcedAdmin} as.
+     * @param check filter predicate.
+     *
+     * @return {@code null} if none of the {@param admins} match.
+     *         An {@link EnforcedAdmin} if exactly one of the admins matches.
+     *         Otherwise, {@link EnforcedAdmin#MULTIPLE_ENFORCED_ADMIN} for multiple matches.
+     */
+    @Nullable
+    private static EnforcedAdmin findEnforcedAdmin(@Nullable List<ComponentName> admins,
+            @NonNull DevicePolicyManager dpm, @UserIdInt int userId,
+            @NonNull LockSettingCheck check) {
+        if (admins == null) {
             return null;
         }
-
-        final UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
-        if (um.getUserInfo(userId).isManagedProfile()) {
-            final List<ComponentName> admins = dpm.getActiveAdminsAsUser(userId);
-            if (admins == null) {
-                return null;
-            }
-            EnforcedAdmin enforcedAdmin = null;
-            for (ComponentName admin : admins) {
-                if (check.isEnforcing(dpm, admin, userId)) {
-                    if (enforcedAdmin == null) {
-                        enforcedAdmin = new EnforcedAdmin(admin, userId);
-                    } else {
-                        return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
-                    }
+        EnforcedAdmin enforcedAdmin = null;
+        for (ComponentName admin : admins) {
+            if (check.isEnforcing(dpm, admin, userId)) {
+                if (enforcedAdmin == null) {
+                    enforcedAdmin = new EnforcedAdmin(admin, userId);
+                } else {
+                    return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
                 }
             }
-            return enforcedAdmin;
-        } else {
-            return checkForLockSetting(context, userId, check);
         }
+        return enforcedAdmin;
     }
 
     public static EnforcedAdmin checkIfUninstallBlocked(Context context,
@@ -361,7 +388,7 @@
         }
 
         LockPatternUtils lockPatternUtils = new LockPatternUtils(context);
-        if (lockPatternUtils.isSeparateProfileChallengeEnabled(userId)) {
+        if (sProxy.isSeparateProfileChallengeEnabled(lockPatternUtils, userId)) {
             // userId is managed profile and has a separate challenge, only consider
             // the admins in that user.
             final List<ComponentName> admins = dpm.getActiveAdminsAsUser(userId);
@@ -428,7 +455,7 @@
                 if (userInfo.isManagedProfile()) {
                     // If userInfo.id is a managed profile, we also need to look at
                     // the policies set on the parent.
-                    final DevicePolicyManager parentDpm = dpm.getParentProfileInstance(userInfo);
+                    DevicePolicyManager parentDpm = sProxy.getParentProfileInstance(dpm, userInfo);
                     if (parentDpm.getMaximumTimeToLock(admin, userInfo.id) > 0) {
                         if (enforcedAdmin == null) {
                             enforcedAdmin = new EnforcedAdmin(admin, userInfo.id);
@@ -448,8 +475,9 @@
 
     /**
      * Checks whether any of the user's profiles enforce the lock setting. A managed profile is only
-     * included if it does not have a separate challenege but the settings for it's parent (i.e. the
-     * user being checked) are always included.
+     * included if it does not have a separate challenge.
+     *
+     * The user identified by {@param userId} is always included.
      */
     private static EnforcedAdmin checkForLockSetting(
             Context context, @UserIdInt int userId, LockSettingCheck check) {
@@ -468,7 +496,7 @@
                 continue;
             }
             final boolean isSeparateProfileChallengeEnabled =
-                    lockPatternUtils.isSeparateProfileChallengeEnabled(userInfo.id);
+                    sProxy.isSeparateProfileChallengeEnabled(lockPatternUtils, userInfo.id);
             for (ComponentName admin : admins) {
                 if (!isSeparateProfileChallengeEnabled) {
                     if (check.isEnforcing(dpm, admin, userInfo.id)) {
@@ -487,7 +515,7 @@
                 if (userInfo.isManagedProfile()) {
                     // If userInfo.id is a managed profile, we also need to look at
                     // the policies set on the parent.
-                    final DevicePolicyManager parentDpm = dpm.getParentProfileInstance(userInfo);
+                    DevicePolicyManager parentDpm = sProxy.getParentProfileInstance(dpm, userInfo);
                     if (check.isEnforcing(parentDpm, admin, userInfo.id)) {
                         if (enforcedAdmin == null) {
                             enforcedAdmin = new EnforcedAdmin(admin, userInfo.id);
@@ -733,4 +761,23 @@
             other.userId = userId;
         }
     }
+
+    /**
+     * Static {@link LockPatternUtils} and {@link DevicePolicyManager} wrapper for testing purposes.
+     * {@link LockPatternUtils} is an internal API not supported by robolectric.
+     * {@link DevicePolicyManager} has a {@code getProfileParent} not yet suppored by robolectric.
+     */
+    @VisibleForTesting
+    static Proxy sProxy = new Proxy();
+
+    @VisibleForTesting
+    static class Proxy {
+        public boolean isSeparateProfileChallengeEnabled(LockPatternUtils utils, int userHandle) {
+            return utils.isSeparateProfileChallengeEnabled(userHandle);
+        }
+
+        public DevicePolicyManager getParentProfileInstance(DevicePolicyManager dpm, UserInfo ui) {
+            return dpm.getParentProfileInstance(ui);
+        }
+    }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index 7a4514a..7e7b391 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -184,10 +184,7 @@
 
     @ColorInt
     public static int getColorError(Context context) {
-        TypedArray ta = context.obtainStyledAttributes(new int[]{android.R.attr.textColorError});
-        @ColorInt int colorError = ta.getColor(0, 0);
-        ta.recycle();
-        return colorError;
+        return getColorAttr(context, android.R.attr.colorError);
     }
 
     @ColorInt
diff --git a/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java b/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
index fd2e7ca..6764a6b 100755
--- a/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
+++ b/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
@@ -29,7 +29,8 @@
 import android.graphics.RectF;
 import android.graphics.Typeface;
 import android.graphics.drawable.Drawable;
-import android.provider.Settings;
+import android.util.TypedValue;
+
 import com.android.settingslib.R;
 import com.android.settingslib.Utils;
 
@@ -97,9 +98,13 @@
 
         final int N = levels.length();
         mColors = new int[2 * N];
-        for (int i = 0; i < N; i++) {
+        for (int i=0; i < N; i++) {
             mColors[2 * i] = levels.getInt(i, 0);
-            mColors[2 * i + 1] = colors.getColor(i, 0);
+            if (colors.getType(i) == TypedValue.TYPE_ATTRIBUTE) {
+                mColors[2 * i + 1] = Utils.getColorAttr(context, colors.getResourceId(i, 0));
+            } else {
+                mColors[2 * i + 1] = colors.getColor(i, 0);
+            }
         }
         levels.recycle();
         colors.recycle();
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java
index 2958740..c506358 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java
@@ -16,6 +16,17 @@
 
 package com.android.settingslib;
 
+import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE;
+import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT;
+import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_REMOTE_INPUT;
+import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS;
+import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.when;
+
 import android.app.admin.DevicePolicyManager;
 import android.content.ComponentName;
 import android.content.Context;
@@ -25,18 +36,13 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Answers;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.annotation.Config;
 
 import java.util.Arrays;
 
-import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT;
-import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_REMOTE_INPUT;
-import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
-import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Mockito.when;
-
 @RunWith(SettingLibRobolectricTestRunner.class)
 @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
 public class RestrictedLockUtilsTest {
@@ -47,8 +53,11 @@
     private DevicePolicyManager mDevicePolicyManager;
     @Mock
     private UserManager mUserManager;
+    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+    private RestrictedLockUtils.Proxy mProxy;
 
     private static final int mUserId = 194;
+    private static final int mProfileId = 160;
     private static final ComponentName mAdmin1 = new ComponentName("admin1", "admin1class");
     private static final ComponentName mAdmin2 = new ComponentName("admin2", "admin2class");
 
@@ -60,12 +69,13 @@
                 .thenReturn(mDevicePolicyManager);
         when(mContext.getSystemService(Context.USER_SERVICE))
                 .thenReturn(mUserManager);
+
+        RestrictedLockUtils.sProxy = mProxy;
     }
 
     @Test
     public void checkIfKeyguardFeaturesDisabled_noEnforcedAdminForManagedProfile() {
-        setUpManagedProfile(mUserId);
-        setUpActiveAdmins(mUserId, new ComponentName[] {mAdmin1, mAdmin2});
+        setUpManagedProfile(mUserId, new ComponentName[] {mAdmin1, mAdmin2});
 
         final EnforcedAdmin enforcedAdmin = RestrictedLockUtils.checkIfKeyguardFeaturesDisabled(
                 mContext, KEYGUARD_DISABLE_FINGERPRINT, mUserId);
@@ -75,8 +85,7 @@
 
     @Test
     public void checkIfKeyguardFeaturesDisabled_oneEnforcedAdminForManagedProfile() {
-        setUpManagedProfile(mUserId);
-        setUpActiveAdmins(mUserId, new ComponentName[] {mAdmin1, mAdmin2});
+        setUpManagedProfile(mUserId, new ComponentName[] {mAdmin1, mAdmin2});
 
         when(mDevicePolicyManager.getKeyguardDisabledFeatures(mAdmin1, mUserId))
                 .thenReturn(KEYGUARD_DISABLE_FINGERPRINT);
@@ -89,8 +98,7 @@
 
     @Test
     public void checkIfKeyguardFeaturesDisabled_multipleEnforcedAdminForManagedProfile() {
-        setUpManagedProfile(mUserId);
-        setUpActiveAdmins(mUserId, new ComponentName[] {mAdmin1, mAdmin2});
+        setUpManagedProfile(mUserId, new ComponentName[] {mAdmin1, mAdmin2});
 
         when(mDevicePolicyManager.getKeyguardDisabledFeatures(mAdmin1, mUserId))
                 .thenReturn(KEYGUARD_DISABLE_REMOTE_INPUT);
@@ -103,9 +111,129 @@
         assertThat(enforcedAdmin).isEqualTo(EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN);
     }
 
-    private UserInfo setUpManagedProfile(int userId) {
-        final UserInfo userInfo = new UserInfo(userId, "myuser", UserInfo.FLAG_MANAGED_PROFILE);
+    @Test
+    public void checkIfKeyguardFeaturesAreDisabled_doesMatchAllowedFeature_unifiedManagedProfile() {
+        UserInfo userInfo = setUpUser(mUserId, new ComponentName[] {mAdmin1});
+        UserInfo profileInfo = setUpManagedProfile(mProfileId, new ComponentName[] {mAdmin2});
+        when(mUserManager.getProfiles(mUserId)).thenReturn(Arrays.asList(new UserInfo[] {
+                userInfo, profileInfo}));
+
+        when(mDevicePolicyManager.getKeyguardDisabledFeatures(mAdmin1, mUserId))
+                .thenReturn(KEYGUARD_DISABLE_FEATURES_NONE);
+        when(mDevicePolicyManager.getKeyguardDisabledFeatures(mAdmin2, mProfileId))
+                .thenReturn(KEYGUARD_DISABLE_FINGERPRINT);
+
+        // Querying the parent should return the policy, since it affects the parent.
+        EnforcedAdmin parent = RestrictedLockUtils.checkIfKeyguardFeaturesDisabled(
+                mContext, KEYGUARD_DISABLE_FINGERPRINT, mUserId);
+        assertThat(parent).isEqualTo(new EnforcedAdmin(mAdmin2, mProfileId));
+
+        // Querying the child should return that too.
+        EnforcedAdmin profile = RestrictedLockUtils.checkIfKeyguardFeaturesDisabled(
+                mContext, KEYGUARD_DISABLE_FINGERPRINT, mProfileId);
+        assertThat(profile).isEqualTo(new EnforcedAdmin(mAdmin2, mProfileId));
+
+        // Querying for some unrelated feature should return nothing. Nothing!
+        assertThat(RestrictedLockUtils.checkIfKeyguardFeaturesDisabled(
+                mContext, KEYGUARD_DISABLE_REMOTE_INPUT, mUserId)).isNull();
+        assertThat(RestrictedLockUtils.checkIfKeyguardFeaturesDisabled(
+                mContext, KEYGUARD_DISABLE_REMOTE_INPUT, mProfileId)).isNull();
+    }
+
+    @Test
+    public void checkIfKeyguardFeaturesAreDisabled_notMatchOtherFeatures_unifiedManagedProfile() {
+        UserInfo userInfo = setUpUser(mUserId, new ComponentName[] {mAdmin1});
+        UserInfo profileInfo = setUpManagedProfile(mProfileId, new ComponentName[] {mAdmin2});
+        when(mUserManager.getProfiles(mUserId)).thenReturn(Arrays.asList(new UserInfo[] {
+                userInfo, profileInfo}));
+
+        when(mDevicePolicyManager.getKeyguardDisabledFeatures(mAdmin1, mUserId))
+                .thenReturn(KEYGUARD_DISABLE_FEATURES_NONE);
+        when(mDevicePolicyManager.getKeyguardDisabledFeatures(mAdmin2, mProfileId))
+                .thenReturn(KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS);
+
+        // Querying the parent should not return the policy, because it's not a policy that should
+        // affect parents even when the lock screen is unified.
+        EnforcedAdmin primary = RestrictedLockUtils.checkIfKeyguardFeaturesDisabled(
+                mContext, KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS, mUserId);
+        assertThat(primary).isNull();
+
+        // Querying the child should still return the policy.
+        EnforcedAdmin profile = RestrictedLockUtils.checkIfKeyguardFeaturesDisabled(
+                mContext, KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS, mProfileId);
+        assertThat(profile).isEqualTo(new EnforcedAdmin(mAdmin2, mProfileId));
+    }
+
+    @Test
+    public void checkIfKeyguardFeaturesAreDisabled_onlyMatchesProfile_separateManagedProfile() {
+        UserInfo userInfo = setUpUser(mUserId, new ComponentName[] {mAdmin1});
+        UserInfo profileInfo = setUpManagedProfile(mProfileId, new ComponentName[] {mAdmin2});
+        when(mUserManager.getProfiles(mUserId)).thenReturn(Arrays.asList(new UserInfo[] {
+                userInfo, profileInfo}));
+
+        when(mDevicePolicyManager.getKeyguardDisabledFeatures(mAdmin1, mUserId))
+                .thenReturn(KEYGUARD_DISABLE_FEATURES_NONE);
+        when(mDevicePolicyManager.getKeyguardDisabledFeatures(mAdmin2, mProfileId))
+                .thenReturn(KEYGUARD_DISABLE_FINGERPRINT);
+
+        // Crucially for this test, isSeparateWorkChallengeEnabled => true.
+        doReturn(true).when(mProxy).isSeparateProfileChallengeEnabled(any(), eq(mProfileId));
+
+        // Querying the parent should not return the policy, even though it's shared by default,
+        // because the parent doesn't share a lock screen with the profile any more.
+        EnforcedAdmin parent = RestrictedLockUtils.checkIfKeyguardFeaturesDisabled(
+                mContext, KEYGUARD_DISABLE_FINGERPRINT, mUserId);
+        assertThat(parent).isNull();
+
+        // Querying the child should still return the policy.
+        EnforcedAdmin profile = RestrictedLockUtils.checkIfKeyguardFeaturesDisabled(
+                mContext, KEYGUARD_DISABLE_FINGERPRINT, mProfileId);
+        assertThat(profile).isEqualTo(new EnforcedAdmin(mAdmin2, mProfileId));
+    }
+
+    /**
+     * This test works great. The real world implementation is sketchy though.
+     * <p>
+     * DevicePolicyManager.getParentProfileInstance(UserInfo) does not do what it looks like it does
+     * (which would be to get an instance for the parent of the user that's passed in to it.)
+     * <p>
+     * Instead it just always returns a parent instance for the current user.
+     * <p>
+     * Still, the test works.
+     */
+    @Test
+    public void checkIfKeyguardFeaturesAreDisabled_onlyMatchesParent_profileParentPolicy() {
+        UserInfo userInfo = setUpUser(mUserId, new ComponentName[] {mAdmin1});
+        UserInfo profileInfo = setUpManagedProfile(mProfileId, new ComponentName[] {mAdmin2});
+        when(mUserManager.getProfiles(mUserId)).thenReturn(Arrays.asList(new UserInfo[] {
+                userInfo, profileInfo}));
+
+        when(mProxy.getParentProfileInstance(any(DevicePolicyManager.class), any())
+                .getKeyguardDisabledFeatures(mAdmin2, mProfileId))
+                .thenReturn(KEYGUARD_DISABLE_FINGERPRINT);
+
+        // Parent should get the policy.
+        EnforcedAdmin parent = RestrictedLockUtils.checkIfKeyguardFeaturesDisabled(
+                mContext, KEYGUARD_DISABLE_FINGERPRINT, mUserId);
+        assertThat(parent).isEqualTo(new EnforcedAdmin(mAdmin2, mProfileId));
+
+        // Profile should not get the policy.
+        EnforcedAdmin profile = RestrictedLockUtils.checkIfKeyguardFeaturesDisabled(
+                mContext, KEYGUARD_DISABLE_FINGERPRINT, mProfileId);
+        assertThat(profile).isNull();
+    }
+
+    private UserInfo setUpUser(int userId, ComponentName[] admins) {
+        UserInfo userInfo = new UserInfo(userId, "primary", 0);
         when(mUserManager.getUserInfo(userId)).thenReturn(userInfo);
+        setUpActiveAdmins(userId, admins);
+        return userInfo;
+    }
+
+    private UserInfo setUpManagedProfile(int userId, ComponentName[] admins) {
+        UserInfo userInfo = new UserInfo(userId, "profile", UserInfo.FLAG_MANAGED_PROFILE);
+        when(mUserManager.getUserInfo(userId)).thenReturn(userInfo);
+        setUpActiveAdmins(userId, admins);
         return userInfo;
     }
 
diff --git a/packages/SystemUI/res/drawable/ic_fingerprint_error.xml b/packages/SystemUI/res/drawable/ic_fingerprint_error.xml
index 11e83a1..a7fb1a1 100644
--- a/packages/SystemUI/res/drawable/ic_fingerprint_error.xml
+++ b/packages/SystemUI/res/drawable/ic_fingerprint_error.xml
@@ -19,12 +19,12 @@
         android:viewportWidth="32.0"
         android:viewportHeight="32.0">
     <path
-        android:fillColor="@color/system_warning_color"
+        android:fillColor="?android:attr/colorError"
         android:pathData="M15.99,2.5C8.53,2.5 2.5,8.54 2.5,16.0s6.03,13.5 13.49,13.5S29.5,23.46 29.5,16.0S23.45,2.5 15.99,2.5zM16.0,26.8c-5.97,0.0 -10.8,-4.83 -10.8,-10.8S10.03,5.2 16.0,5.2S26.8,10.03 26.8,16.0S21.97,26.8 16.0,26.8z"/>
     <path
-        android:fillColor="@color/system_warning_color"
+        android:fillColor="?android:attr/colorError"
         android:pathData="M14.65,20.05l2.7,0.0l0.0,2.7l-2.7,0.0z"/>
     <path
-        android:fillColor="@color/system_warning_color"
+        android:fillColor="?android:attr/colorError"
         android:pathData="M14.65,9.25l2.7,0.0l0.0,8.1l-2.7,0.0z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/lockscreen_fingerprint_error_state_to_fp.xml b/packages/SystemUI/res/drawable/lockscreen_fingerprint_error_state_to_fp.xml
index e207cb3..3af2f7f 100644
--- a/packages/SystemUI/res/drawable/lockscreen_fingerprint_error_state_to_fp.xml
+++ b/packages/SystemUI/res/drawable/lockscreen_fingerprint_error_state_to_fp.xml
@@ -98,11 +98,11 @@
             <path
                 android:name="path_2"
                 android:pathData="M 1.35900878906,6.76104736328 c 0.0,0.0 -2.69998168945,0.0 -2.69998168945,0.0 c 0.0,0.0 0.0,-2.69995117188 0.0,-2.69995117188 c 0.0,0.0 2.69998168945,0.0 2.69998168945,0.0 c 0.0,0.0 0.0,2.69995117188 0.0,2.69995117188 Z"
-                android:fillColor="@*android:color/system_error" />
+                android:fillColor="?android:attr/colorError" />
             <path
                 android:name="path_1"
                 android:pathData="M 1.35363769531,1.36633300781 c 0.0,0.0 -2.69998168945,0.0 -2.69998168945,0.0 c 0.0,0.0 0.0,-8.09997558594 0.0,-8.09997558594 c 0.0,0.0 2.69998168945,0.0 2.69998168945,0.0 c 0.0,0.0 0.0,8.09997558594 0.0,8.09997558594 Z"
-                android:fillColor="@*android:color/system_error" />
+                android:fillColor="?android:attr/colorError" />
         </group>
     </group>
     <group
@@ -117,7 +117,7 @@
             <path
                 android:name="path_3"
                 android:pathData="M 0.0101470947266,10.8087768555 c -5.96701049805,0.0 -10.8000183105,-4.8330078125 -10.8000183105,-10.8000488281 c 0.0,-5.96691894531 4.8330078125,-10.7999267578 10.8000183105,-10.7999267578 c 5.96697998047,0.0 10.799987793,4.8330078125 10.799987793,10.7999267578 c 0.0,5.96704101562 -4.8330078125,10.8000488281 -10.799987793,10.8000488281 Z"
-                android:strokeColor="@*android:color/system_error"
+                android:strokeColor="?android:attr/colorError"
                 android:strokeWidth="2"
                 android:trimPathStart="0"
                 android:trimPathEnd="1" />
diff --git a/packages/SystemUI/res/drawable/lockscreen_fingerprint_fp_to_error_state.xml b/packages/SystemUI/res/drawable/lockscreen_fingerprint_fp_to_error_state.xml
index 2b4babc..a577afc 100644
--- a/packages/SystemUI/res/drawable/lockscreen_fingerprint_fp_to_error_state.xml
+++ b/packages/SystemUI/res/drawable/lockscreen_fingerprint_fp_to_error_state.xml
@@ -96,7 +96,7 @@
                 <path
                     android:name="ridge_5_path_0"
                     android:pathData="M -25.3591003418,-24.4138946533 c -0.569000244141,0.106399536133 -1.12660217285,0.140594482422 -1.45460510254,0.140594482422 c -1.29689025879,0.0 -2.53239440918,-0.343307495117 -3.62019348145,-1.12400817871 c -1.67700195312,-1.20349121094 -2.76950073242,-3.17008972168 -2.76950073242,-5.39189147949"
-                    android:strokeColor="@*android:color/system_error"
+                    android:strokeColor="?android:attr/colorError"
                     android:strokeWidth="1.45"
                     android:strokeLineCap="round"
                     android:trimPathEnd="0" />
@@ -106,7 +106,7 @@
                 <path
                     android:name="ridge_7_path_0"
                     android:pathData="M -36.1409912109,-21.7843475342 c -1.00540161133,-1.19300842285 -1.57499694824,-1.9181060791 -2.36520385742,-3.50170898438 c -0.827560424805,-1.65869140625 -1.31352233887,-3.49159240723 -1.31352233887,-5.48489379883 c 0.0,-3.66279602051 2.96932983398,-6.63220214844 6.63221740723,-6.63220214844 c 3.6628112793,0.0 6.63220214844,2.96940612793 6.63220214844,6.63220214844"
-                    android:strokeColor="@*android:color/system_error"
+                    android:strokeColor="?android:attr/colorError"
                     android:strokeWidth="1.45"
                     android:strokeLineCap="round"
                     android:trimPathEnd="0" />
@@ -116,7 +116,7 @@
                 <path
                     android:name="ridge_6_path_0"
                     android:pathData="M -42.1907958984,-25.6756896973 c -0.758117675781,-2.14370727539 -0.896545410156,-3.86891174316 -0.896545410156,-5.12921142578 c 0.0,-1.46069335938 0.249176025391,-2.84799194336 0.814682006836,-4.09748840332 c 1.56153869629,-3.45030212402 5.03434753418,-5.85076904297 9.0679473877,-5.85076904297 c 5.49430847168,0.0 9.94830322266,4.4539642334 9.94830322266,9.94825744629 c 0.0,1.83151245117 -1.48460388184,3.31610107422 -3.31610107422,3.31610107422 c -1.83149719238,0.0 -3.31610107422,-1.48469543457 -3.31610107422,-3.31610107422 c 0.0,-1.83139038086 -1.48458862305,-3.31610107422 -3.31610107422,-3.31610107422 c -1.83149719238,0.0 -3.31610107422,1.48471069336 -3.31610107422,3.31610107422 c 0.0,2.57020568848 0.989517211914,4.88710021973 2.60510253906,6.5865020752 c 1.22210693359,1.28550720215 2.43139648438,2.09950256348 4.47590637207,2.69030761719"
-                    android:strokeColor="@*android:color/system_error"
+                    android:strokeColor="?android:attr/colorError"
                     android:strokeWidth="1.45"
                     android:strokeLineCap="round"
                     android:trimPathEnd="0" />
@@ -126,7 +126,7 @@
                 <path
                     android:name="ridge_2_path_0"
                     android:pathData="M -44.0646514893,-38.1672973633 c 1.19026184082,-1.77430725098 2.67503356934,-3.24531555176 4.55902099609,-4.27278137207 c 1.88395690918,-1.0274810791 4.04466247559,-1.61137390137 6.34175109863,-1.61137390137 c 2.28761291504,0.0 4.43991088867,0.579071044922 6.31831359863,1.59861755371 c 1.8784942627,1.01954650879 3.36059570312,2.4796295166 4.55279541016,4.24153137207"
-                    android:strokeColor="@*android:color/system_error"
+                    android:strokeColor="?android:attr/colorError"
                     android:strokeWidth="1.45"
                     android:strokeLineCap="round"
                     android:trimPathStart="1" />
@@ -138,7 +138,7 @@
                 <path
                     android:name="ridge_1_path_0"
                     android:pathData="M 71.7812347412,97.0507202148 c -2.27149963379,-1.31344604492 -4.71360778809,-2.07006835938 -7.56221008301,-2.07006835938 c -2.84869384766,0.0 -5.23320007324,0.779556274414 -7.34411621094,2.07006835938"
-                    android:strokeColor="@*android:color/system_error"
+                    android:strokeColor="?android:attr/colorError"
                     android:strokeWidth="1.45"
                     android:strokeLineCap="round"
                     android:trimPathEnd="0" />
@@ -157,11 +157,11 @@
             <path
                 android:name="path_2"
                 android:pathData="M -1.3705291748,4.06730651855 c 0.0,0.0 0.036376953125,-0.0102386474609 0.036376953125,-0.0102386474609 c 0.0,0.0 -0.00682067871094,0.0040283203125 -0.00682067871093,0.0040283203125 c 0.0,0.0 -0.0161437988281,0.00479125976562 -0.0161437988281,0.00479125976563 c 0.0,0.0 -0.0134124755859,0.00141906738281 -0.0134124755859,0.00141906738281 Z"
-                android:fillColor="@*android:color/system_error" />
+                android:fillColor="?android:attr/colorError" />
             <path
                 android:name="path_1"
                 android:pathData="M -1.3737487793,-6.77532958984 c 0.0,0.0 0.00604248046875,0.0166625976562 0.00604248046876,0.0166625976562 c 0.0,0.0 0.0213623046875,0.0250244140625 0.0213623046875,0.0250244140625 c 0.0,0.0 -0.00604248046875,-0.0166625976562 -0.00604248046876,-0.0166625976562 c 0.0,0.0 -0.0213623046875,-0.0250244140625 -0.0213623046875,-0.0250244140625 Z"
-                android:fillColor="@*android:color/system_error" />
+                android:fillColor="?android:attr/colorError" />
         </group>
     </group>
     <group
@@ -176,7 +176,7 @@
             <path
                 android:name="path_3"
                 android:pathData="M 0.0101470947266,10.8087768555 c -5.96701049805,0.0 -10.8000183105,-4.8330078125 -10.8000183105,-10.8000488281 c 0.0,-5.96691894531 4.8330078125,-10.7999267578 10.8000183105,-10.7999267578 c 5.96697998047,0.0 10.799987793,4.8330078125 10.799987793,10.7999267578 c 0.0,5.96704101562 -4.8330078125,10.8000488281 -10.799987793,10.8000488281 Z"
-                android:strokeColor="@*android:color/system_error"
+                android:strokeColor="?android:attr/colorError"
                 android:strokeWidth="2"
                 android:trimPathStart="1" />
         </group>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 407cddf..f461bb3 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -27,7 +27,6 @@
     <color name="notification_list_shadow_top">#80000000</color>
     <drawable name="heads_up_notification_bg_pressed">#ff33B5E5</drawable>
     <color name="qs_batterymeter_frame_color">#FF404040</color>
-    <color name="system_warning_color">@*android:color/system_error</color>
     <color name="qs_tile_divider">#29ffffff</color><!-- 16% white -->
     <color name="qs_subhead">#99FFFFFF</color><!-- 60% white -->
     <color name="qs_detail_button">@*android:color/quaternary_device_default_settings</color>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 48b7664..9168256 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -30,7 +30,7 @@
 
     <!-- Recents theme -->
     <style name="RecentsTheme.Wallpaper">
-        <item name="android:windowBackground">@color/transparent</item>
+        <item name="android:windowBackground">@*android:color/transparent</item>
         <item name="android:colorBackgroundCacheHint">@null</item>
         <item name="android:windowShowWallpaper">true</item>
         <item name="android:windowDisablePreview">true</item>
@@ -52,7 +52,7 @@
     <!-- Theme used for the activity that shows when the system forced an app to be resizable -->
     <style name="ForcedResizableTheme" parent="@android:style/Theme.Translucent.NoTitleBar">
         <item name="android:windowBackground">@drawable/forced_resizable_background</item>
-        <item name="android:statusBarColor">@color/transparent</item>
+        <item name="android:statusBarColor">@*android:color/transparent</item>
         <item name="android:windowAnimationStyle">@style/Animation.ForcedResizable</item>
     </style>
 
@@ -70,7 +70,7 @@
         <item name="android:windowContentOverlay">@null</item>
         <item name="android:windowBackground">@null</item>
         <item name="android:colorBackgroundCacheHint">@null</item>
-        <item name="android:statusBarColor">@color/transparent</item>
+        <item name="android:statusBarColor">@*android:color/transparent</item>
         <item name="android:windowAnimationStyle">@style/Animation.PipPhoneOverlayControl</item>
     </style>
 
@@ -164,7 +164,7 @@
 
     <style name="TextAppearance.QS.Warning">
         <item name="android:textSize">14sp</item>
-        <item name="android:textColor">@color/system_warning_color</item>
+        <item name="android:textColor">?android:attr/colorError</item>
     </style>
 
     <style name="TextAppearance.QS.DetailButton">
@@ -366,7 +366,7 @@
     </style>
 
     <style name="TextAppearance.NotificationGuts.SecondaryWarning">
-        <item name="android:textColor">@color/system_warning_color</item>
+        <item name="android:textColor">?android:attr/colorError</item>
         <item name="android:textSize">12sp</item>
     </style>
 
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index f1e7d53..ac7ab9d 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -47,6 +47,8 @@
 import com.android.systemui.statusbar.policy.DataSaverController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedControllerImpl;
+import com.android.systemui.statusbar.policy.ExtensionController;
+import com.android.systemui.statusbar.policy.ExtensionControllerImpl;
 import com.android.systemui.statusbar.policy.FlashlightController;
 import com.android.systemui.statusbar.policy.FlashlightControllerImpl;
 import com.android.systemui.statusbar.policy.HotspotController;
@@ -233,6 +235,9 @@
         mProviders.put(FragmentService.class, () ->
                 new FragmentService(mContext));
 
+        mProviders.put(ExtensionController.class, () ->
+                new ExtensionControllerImpl());
+
         // Put all dependencies above here so the factory can override them if it wants.
         SystemUIFactory.getInstance().injectDependencies(mProviders, mContext);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginManager.java b/packages/SystemUI/src/com/android/systemui/plugins/PluginManager.java
index 8b4bd7b..0c3e40c 100644
--- a/packages/SystemUI/src/com/android/systemui/plugins/PluginManager.java
+++ b/packages/SystemUI/src/com/android/systemui/plugins/PluginManager.java
@@ -133,14 +133,7 @@
 
     public <T extends Plugin> void addPluginListener(PluginListener<T> listener, Class<?> cls,
             boolean allowMultiple) {
-        ProvidesInterface info = cls.getDeclaredAnnotation(ProvidesInterface.class);
-        if (info == null) {
-            throw new RuntimeException(cls + " doesn't provide an interface");
-        }
-        if (TextUtils.isEmpty(info.action())) {
-            throw new RuntimeException(cls + " doesn't provide an action");
-        }
-        addPluginListener(info.action(), listener, cls, allowMultiple);
+        addPluginListener(getAction(cls), listener, cls, allowMultiple);
     }
 
     public <T extends Plugin> void addPluginListener(String action, PluginListener<T> listener,
@@ -285,6 +278,17 @@
         return new PluginContextWrapper(mContext.createApplicationContext(info, 0), classLoader);
     }
 
+    public static <P> String getAction(Class<P> cls) {
+        ProvidesInterface info = cls.getDeclaredAnnotation(ProvidesInterface.class);
+        if (info == null) {
+            throw new RuntimeException(cls + " doesn't provide an interface");
+        }
+        if (TextUtils.isEmpty(info.action())) {
+            throw new RuntimeException(cls + " doesn't provide an action");
+        }
+        return info.action();
+    }
+
     private class AllPluginClassLoader extends ClassLoader {
         public AllPluginClassLoader(ClassLoader classLoader) {
             super(classLoader);
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index 09ce2ad..daf0622 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -39,6 +39,7 @@
 import android.util.Slog;
 
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
+import com.android.settingslib.Utils;
 import com.android.systemui.R;
 import com.android.systemui.SystemUI;
 import com.android.systemui.statusbar.phone.StatusBar;
@@ -175,8 +176,7 @@
                         .setOnlyAlertOnce(true)
                         .setDeleteIntent(pendingBroadcast(ACTION_DISMISSED_WARNING))
                         .setVisibility(Notification.VISIBILITY_PUBLIC)
-                        .setColor(mContext.getColor(
-                                com.android.internal.R.color.battery_saver_mode_color));
+                        .setColor(Utils.getColorAttr(mContext, android.R.attr.colorError));
         if (hasBatterySettings()) {
             nb.setContentIntent(pendingBroadcast(ACTION_SHOW_BATTERY_SETTINGS));
         }
@@ -245,8 +245,7 @@
                         .setVisibility(Notification.VISIBILITY_PUBLIC)
                         .setContentIntent(pendingBroadcast(ACTION_CLICKED_TEMP_WARNING))
                         .setDeleteIntent(pendingBroadcast(ACTION_DISMISSED_TEMP_WARNING))
-                        .setColor(mContext.getColor(
-                                com.android.internal.R.color.battery_saver_mode_color));
+                        .setColor(Utils.getColorAttr(mContext, android.R.attr.colorError));
         SystemUI.overrideNotificationAppName(mContext, nb);
         final Notification n = nb.build();
         mNoMan.notifyAsUser(TAG_TEMPERATURE, SystemMessage.NOTE_HIGH_TEMP, n, UserHandle.ALL);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataUsageDetailView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataUsageDetailView.java
index c7b6aea..9cd79f8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataUsageDetailView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataUsageDetailView.java
@@ -91,7 +91,7 @@
                     formatBytes(info.usageLevel));
             bottom = res.getString(R.string.quick_settings_cellular_detail_data_limit,
                     formatBytes(info.limitLevel));
-            usageColor = mContext.getColor(R.color.system_warning_color);
+            usageColor = Utils.getDefaultColor(mContext, android.R.attr.colorError);
         }
 
         if (usageColor == 0) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index bc992d8..fb92a67 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -42,6 +42,7 @@
 import com.android.internal.app.IBatteryStats;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.settingslib.Utils;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.phone.KeyguardIndicationTextView;
@@ -365,7 +366,7 @@
             if (!updateMonitor.isUnlockingWithFingerprintAllowed()) {
                 return;
             }
-            int errorColor = mContext.getResources().getColor(R.color.system_warning_color, null);
+            int errorColor = Utils.getColorError(mContext);
             if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
                 mStatusBarKeyguardViewManager.showBouncerMessage(helpString, errorColor);
             } else if (updateMonitor.isDeviceInteractive()
@@ -388,7 +389,7 @@
                     || msgId == FingerprintManager.FINGERPRINT_ERROR_CANCELED) {
                 return;
             }
-            int errorColor = mContext.getResources().getColor(R.color.system_warning_color, null);
+            int errorColor = Utils.getColorError(mContext);
             if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
                 // When swiping up right after receiving a fingerprint error, the bouncer calls
                 // authenticate leading to the same message being shown again on the bouncer.
@@ -411,8 +412,7 @@
         @Override
         public void onScreenTurnedOn() {
             if (mMessageToShowOnScreenOn != null) {
-                int errorColor = mContext.getResources().getColor(R.color.system_warning_color,
-                        null);
+                int errorColor = Utils.getColorError(mContext);
                 showTransientIndication(mMessageToShowOnScreenOn, errorColor);
                 // We want to keep this message around in case the screen was off
                 mHandler.removeMessages(MSG_HIDE_TRANSIENT);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
index ed71e57..f3c2bc5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
@@ -33,6 +33,7 @@
 import android.util.Log;
 import android.view.View;
 
+import com.android.settingslib.Utils;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 
@@ -167,7 +168,7 @@
                 mSemiTransparent = context.getColor(
                         com.android.internal.R.color.system_bar_background_semi_transparent);
                 mTransparent = context.getColor(R.color.system_bar_background_transparent);
-                mWarning = context.getColor(com.android.internal.R.color.battery_saver_mode_color);
+                mWarning = Utils.getColorAttr(context, android.R.attr.colorError);
             }
             mGradient = context.getDrawable(gradientResourceId);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 8f63d45..2538bdd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -19,9 +19,10 @@
 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
 import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
 
+import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_LEFT_BUTTON;
 import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_LEFT_UNLOCK;
+import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_RIGHT_BUTTON;
 import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_RIGHT_UNLOCK;
-import static com.android.systemui.tuner.LockscreenFragment.getIntentButton;
 
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
@@ -79,9 +80,12 @@
 import com.android.systemui.statusbar.KeyguardAffordanceView;
 import com.android.systemui.statusbar.KeyguardIndicationController;
 import com.android.systemui.statusbar.policy.AccessibilityController;
+import com.android.systemui.statusbar.policy.ExtensionController;
+import com.android.systemui.statusbar.policy.ExtensionController.Extension;
 import com.android.systemui.statusbar.policy.FlashlightController;
 import com.android.systemui.statusbar.policy.PreviewInflater;
 import com.android.systemui.tuner.LockscreenFragment;
+import com.android.systemui.tuner.LockscreenFragment.LockButtonFactory;
 import com.android.systemui.tuner.TunerService;
 import com.android.systemui.tuner.TunerService.Tunable;
 
@@ -91,8 +95,7 @@
  */
 public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickListener,
         UnlockMethodCache.OnUnlockMethodChangedListener,
-        AccessibilityController.AccessibilityStateChangedCallback, View.OnLongClickListener,
-        Tunable {
+        AccessibilityController.AccessibilityStateChangedCallback, View.OnLongClickListener {
 
     final static String TAG = "StatusBar/KeyguardBottomAreaView";
 
@@ -159,12 +162,10 @@
     private Drawable mLeftAssistIcon;
 
     private IntentButton mRightButton = new DefaultRightButton();
-    private IntentButton mRightDefault = mRightButton;
-    private IntentButton mRightPlugin;
+    private Extension<IntentButton> mRightExtension;
     private String mRightButtonStr;
     private IntentButton mLeftButton = new DefaultLeftButton();
-    private IntentButton mLeftDefault = mLeftButton;
-    private IntentButton mLeftPlugin;
+    private Extension<IntentButton> mLeftExtension;
     private String mLeftButtonStr;
     private LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger();
     private boolean mDozing;
@@ -261,21 +262,28 @@
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
         mAccessibilityController.addStateChangedCallback(this);
-        Dependency.get(PluginManager.class).addPluginListener(RIGHT_BUTTON_PLUGIN,
-                mRightListener, IntentButtonProvider.class, false /* Only allow one */);
-        Dependency.get(PluginManager.class).addPluginListener(LEFT_BUTTON_PLUGIN,
-                mLeftListener, IntentButtonProvider.class, false /* Only allow one */);
-        Dependency.get(TunerService.class).addTunable(this, LockscreenFragment.LOCKSCREEN_LEFT_BUTTON,
-                LockscreenFragment.LOCKSCREEN_RIGHT_BUTTON);
+        mRightExtension = Dependency.get(ExtensionController.class).newExtension(IntentButton.class)
+                .withPlugin(IntentButtonProvider.class, RIGHT_BUTTON_PLUGIN,
+                        p -> p.getIntentButton())
+                .withTunerFactory(new LockButtonFactory(mContext, LOCKSCREEN_RIGHT_BUTTON))
+                .withDefault(() -> new DefaultRightButton())
+                .withCallback(button -> setRightButton(button))
+                .build();
+        mLeftExtension = Dependency.get(ExtensionController.class).newExtension(IntentButton.class)
+                .withPlugin(IntentButtonProvider.class, LEFT_BUTTON_PLUGIN,
+                        p -> p.getIntentButton())
+                .withTunerFactory(new LockButtonFactory(mContext, LOCKSCREEN_LEFT_BUTTON))
+                .withDefault(() -> new DefaultLeftButton())
+                .withCallback(button -> setLeftButton(button))
+                .build();
     }
 
     @Override
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
         mAccessibilityController.removeStateChangedCallback(this);
-        Dependency.get(PluginManager.class).removePluginListener(mRightListener);
-        Dependency.get(PluginManager.class).removePluginListener(mLeftListener);
-        Dependency.get(TunerService.class).removeTunable(this);
+        mRightExtension.destroy();
+        mLeftExtension.destroy();
     }
 
     private void initAccessibility() {
@@ -790,63 +798,21 @@
         inflateCameraPreview();
     }
 
-    @Override
-    public void onTuningChanged(String key, String newValue) {
-        if (LockscreenFragment.LOCKSCREEN_LEFT_BUTTON.equals(key)) {
-            mLeftButtonStr = newValue;
-            mLeftIsVoiceAssist = TextUtils.isEmpty(mLeftButtonStr) && mLeftPlugin == null;
-            mLeftButton = getIntentButton(mContext, mLeftButtonStr, mLeftPlugin, mLeftDefault);
-            updateLeftAffordance();
-        } else {
-            mRightButtonStr = newValue;
-            mRightButton = getIntentButton(mContext, mRightButtonStr, mRightPlugin, mRightDefault);
-            updateRightAffordanceIcon();
-            updateCameraVisibility();
-            inflateCameraPreview();
-        }
-    }
-
     private void setRightButton(IntentButton button) {
-        mRightPlugin = button;
-        mRightButton = getIntentButton(mContext, mRightButtonStr, mRightPlugin, mRightDefault);
+        mRightButton = button;
         updateRightAffordanceIcon();
         updateCameraVisibility();
         inflateCameraPreview();
     }
 
     private void setLeftButton(IntentButton button) {
-        mLeftPlugin = button;
-        mLeftButton = getIntentButton(mContext, mLeftButtonStr, mLeftPlugin, mLeftDefault);
-        mLeftIsVoiceAssist = false;
+        mLeftButton = button;
+        if (!(mLeftButton instanceof DefaultLeftButton)) {
+            mLeftIsVoiceAssist = false;
+        }
         updateLeftAffordance();
     }
 
-    private final PluginListener<IntentButtonProvider> mRightListener =
-            new PluginListener<IntentButtonProvider>() {
-        @Override
-        public void onPluginConnected(IntentButtonProvider plugin, Context pluginContext) {
-            setRightButton(plugin.getIntentButton());
-        }
-
-        @Override
-        public void onPluginDisconnected(IntentButtonProvider plugin) {
-            setRightButton(null);
-        }
-    };
-
-    private final PluginListener<IntentButtonProvider> mLeftListener =
-            new PluginListener<IntentButtonProvider>() {
-        @Override
-        public void onPluginConnected(IntentButtonProvider plugin, Context pluginContext) {
-            setLeftButton(plugin.getIntentButton());
-        }
-
-        @Override
-        public void onPluginDisconnected(IntentButtonProvider plugin) {
-            setLeftButton(null);
-        }
-    };
-
     public void setDozing(boolean dozing, boolean animate) {
         mDozing = dozing;
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 213b0aa..a6b145e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -5742,9 +5742,8 @@
         if (snoozeOption.criterion != null) {
             mNotificationListener.snoozeNotification(sbn.getKey(), snoozeOption.criterion.getId());
         } else {
-            GregorianCalendar snoozeUntil = new GregorianCalendar();
-            snoozeUntil.add(Calendar.MINUTE, snoozeOption.snoozeForMinutes);
-            mNotificationListener.snoozeNotification(sbn.getKey(), snoozeUntil.getTimeInMillis());
+            mNotificationListener.snoozeNotification(sbn.getKey(),
+                    snoozeOption.snoozeForMinutes * 60 * 1000);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionController.java
new file mode 100644
index 0000000..eaf8925
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionController.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.plugins.Plugin;
+
+import java.util.Map;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+/**
+ * Utility class used to select between a plugin, tuner settings, and a default implementation
+ * of an interface.
+ */
+public interface ExtensionController {
+
+    <T> ExtensionBuilder<T> newExtension(Class<T> cls);
+
+    interface Extension<T> {
+        T get();
+        void destroy();
+    }
+
+    interface ExtensionBuilder<T> {
+        ExtensionBuilder<T> withTunerFactory(TunerFactory<T> factory);
+        <P extends T> ExtensionBuilder<T> withPlugin(Class<P> cls);
+        <P extends T> ExtensionBuilder<T> withPlugin(Class<P> cls, String action);
+        <P> ExtensionBuilder<T> withPlugin(Class<P> cls, String action,
+                PluginConverter<T, P> converter);
+        ExtensionBuilder<T> withDefault(Supplier<T> def);
+        ExtensionBuilder<T> withCallback(Consumer<T> callback);
+        Extension build();
+    }
+
+    public interface PluginConverter<T, P> {
+        T getInterfaceFromPlugin(P plugin);
+    }
+
+    public interface TunerFactory<T> {
+        String[] keys();
+        T create(Map<String, String> settings);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionControllerImpl.java
new file mode 100644
index 0000000..fefbaa3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ExtensionControllerImpl.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.plugins.Plugin;
+import com.android.systemui.plugins.PluginListener;
+import com.android.systemui.plugins.PluginManager;
+import com.android.systemui.tuner.TunerService;
+import com.android.systemui.tuner.TunerService.Tunable;
+
+import android.content.Context;
+import android.util.ArrayMap;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+public class ExtensionControllerImpl implements ExtensionController {
+
+    @Override
+    public <T> ExtensionBuilder<T> newExtension(Class<T> cls) {
+        return new ExtensionBuilder<>();
+    }
+
+    private interface Producer<T> {
+        T get();
+        void destroy();
+    }
+
+    private class ExtensionBuilder<T> implements ExtensionController.ExtensionBuilder<T> {
+
+        private ExtensionImpl<T> mExtension = new ExtensionImpl<>();
+
+        @Override
+        public ExtensionController.ExtensionBuilder<T> withTunerFactory(TunerFactory<T> factory) {
+            mExtension.addTunerFactory(factory, factory.keys());
+            return this;
+        }
+
+        @Override
+        public <P extends T> ExtensionController.ExtensionBuilder<T> withPlugin(Class<P> cls) {
+            return withPlugin(cls, PluginManager.getAction(cls));
+        }
+
+        @Override
+        public <P extends T> ExtensionController.ExtensionBuilder<T> withPlugin(Class<P> cls,
+                String action) {
+            return withPlugin(cls, action, null);
+        }
+
+        @Override
+        public <P> ExtensionController.ExtensionBuilder<T> withPlugin(Class<P> cls,
+                String action, PluginConverter<T, P> converter) {
+            mExtension.addPlugin(action, cls, converter);
+            return this;
+        }
+
+        @Override
+        public ExtensionController.ExtensionBuilder<T> withDefault(Supplier<T> def) {
+            mExtension.addDefault(def);
+            return this;
+        }
+
+        @Override
+        public ExtensionController.ExtensionBuilder<T> withCallback(
+                Consumer<T> callback) {
+            mExtension.mCallbacks.add(callback);
+            return this;
+        }
+
+        @Override
+        public ExtensionController.Extension build() {
+            // Manually sort, plugins first, tuners second, defaults last.
+            Collections.sort(mExtension.mProducers, (o1, o2) -> {
+                if (o1 instanceof ExtensionImpl.PluginItem) {
+                    if (o2 instanceof ExtensionImpl.PluginItem) {
+                        return 0;
+                    } else {
+                        return -1;
+                    }
+                }
+                if (o1 instanceof ExtensionImpl.TunerItem) {
+                    if (o2 instanceof ExtensionImpl.PluginItem) {
+                        return 1;
+                    } else if (o2 instanceof ExtensionImpl.TunerItem) {
+                        return 0;
+                    } else {
+                        return -1;
+                    }
+                }
+                return 0;
+            });
+            mExtension.notifyChanged();
+            return mExtension;
+        }
+    }
+
+    private class ExtensionImpl<T> implements ExtensionController.Extension<T> {
+        private final ArrayList<Producer<T>> mProducers = new ArrayList<>();
+        private final ArrayList<Consumer<T>> mCallbacks = new ArrayList<>();
+        private T mItem;
+
+        @Override
+        public T get() {
+            return mItem;
+        }
+
+        @Override
+        public void destroy() {
+            for (int i = 0; i < mProducers.size(); i++) {
+                mProducers.get(i).destroy();
+            }
+        }
+
+        private void notifyChanged() {
+            for (int i = 0; i < mProducers.size(); i++) {
+                final T item = mProducers.get(i).get();
+                if (item != null) {
+                    mItem = item;
+                    break;
+                }
+            }
+            for (int i = 0; i < mCallbacks.size(); i++) {
+                mCallbacks.get(i).accept(mItem);
+            }
+        }
+
+        public void addDefault(Supplier<T> def) {
+            mProducers.add(new Default(def));
+        }
+
+        public <P> void addPlugin(String action, Class<P> cls, PluginConverter<T, P> converter) {
+            mProducers.add(new PluginItem(action, cls, converter));
+        }
+
+        public void addTunerFactory(TunerFactory<T> factory, String[] keys) {
+            mProducers.add(new TunerItem(factory, factory.keys()));
+        }
+
+        private class PluginItem<P extends Plugin> implements Producer<T>, PluginListener<P> {
+            private final PluginConverter<T, P> mConverter;
+            private T mItem;
+
+            public PluginItem(String action, Class<P> cls, PluginConverter<T, P> converter) {
+                mConverter = converter;
+                Dependency.get(PluginManager.class).addPluginListener(action, this, cls);
+            }
+
+            @Override
+            public void onPluginConnected(P plugin, Context pluginContext) {
+                if (mConverter != null) {
+                    mItem = mConverter.getInterfaceFromPlugin(plugin);
+                } else {
+                    mItem = (T) plugin;
+                }
+                notifyChanged();
+            }
+
+            @Override
+            public void onPluginDisconnected(P plugin) {
+                mItem = null;
+                notifyChanged();
+            }
+
+            @Override
+            public T get() {
+                return mItem;
+            }
+
+            @Override
+            public void destroy() {
+                Dependency.get(PluginManager.class).removePluginListener(this);
+            }
+        }
+
+        private class TunerItem<T> implements Producer<T>, Tunable {
+            private final TunerFactory<T> mFactory;
+            private final ArrayMap<String, String> mSettings = new ArrayMap<>();
+            private T mItem;
+
+            public TunerItem(TunerFactory<T> factory, String... setting) {
+                mFactory = factory;
+                Dependency.get(TunerService.class).addTunable(this, setting);
+            }
+
+            @Override
+            public T get() {
+                return mItem;
+            }
+
+            @Override
+            public void destroy() {
+                Dependency.get(TunerService.class).removeTunable(this);
+            }
+
+            @Override
+            public void onTuningChanged(String key, String newValue) {
+                mSettings.put(key, newValue);
+                mItem = mFactory.create(mSettings);
+                notifyChanged();
+            }
+        }
+
+        private class Default<T> implements Producer<T> {
+            private final Supplier<T> mSupplier;
+
+            public Default(Supplier<T> supplier) {
+                mSupplier = supplier;
+            }
+
+            @Override
+            public T get() {
+                return mSupplier.get();
+            }
+
+            @Override
+            public void destroy() {
+
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/LockscreenFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/LockscreenFragment.java
index 410d3d2..2df1793 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/LockscreenFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/LockscreenFragment.java
@@ -52,11 +52,13 @@
 import com.android.systemui.plugins.IntentButtonProvider.IntentButton;
 import com.android.systemui.statusbar.ScalingDrawableWrapper;
 import com.android.systemui.statusbar.phone.ExpandableIndicator;
+import com.android.systemui.statusbar.policy.ExtensionController.TunerFactory;
 import com.android.systemui.tuner.ShortcutParser.Shortcut;
 import com.android.systemui.tuner.TunerService.Tunable;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 import java.util.function.Consumer;
 
 public class LockscreenFragment extends PreferenceFragment {
@@ -313,26 +315,39 @@
         }
     }
 
-    public static IntentButton getIntentButton(Context context, String buttonStr,
-            IntentButton plugin, IntentButton def) {
-        // Plugin wins.
-        if (plugin != null) return plugin;
-        // Then tuner options.
-        if (!TextUtils.isEmpty(buttonStr)) {
-            if (buttonStr.contains("::")) {
-                Shortcut shortcut = getShortcutInfo(context, buttonStr);
-                if (shortcut != null) {
-                    return new ShortcutButton(context, shortcut);
-                }
-            } else if (buttonStr.contains("/")) {
-                ActivityInfo info = getActivityinfo(context, buttonStr);
-                if (info != null) {
-                    return new ActivityButton(context, info);
+    public static class LockButtonFactory implements TunerFactory<IntentButton> {
+
+        private final String mKey;
+        private final Context mContext;
+
+        public LockButtonFactory(Context context, String key) {
+            mContext = context;
+            mKey = key;
+        }
+
+        @Override
+        public String[] keys() {
+            return new String[]{mKey};
+        }
+
+        @Override
+        public IntentButton create(Map<String, String> settings) {
+            String buttonStr = settings.get(mKey);
+            if (!TextUtils.isEmpty(buttonStr)) {
+                if (buttonStr.contains("::")) {
+                    Shortcut shortcut = getShortcutInfo(mContext, buttonStr);
+                    if (shortcut != null) {
+                        return new ShortcutButton(mContext, shortcut);
+                    }
+                } else if (buttonStr.contains("/")) {
+                    ActivityInfo info = getActivityinfo(mContext, buttonStr);
+                    if (info != null) {
+                        return new ActivityButton(mContext, info);
+                    }
                 }
             }
+            return null;
         }
-        // Then default.
-        return def;
     }
 
     private static class ShortcutButton implements IntentButton {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
index 6c454e1..c0e7e80 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
@@ -23,7 +23,6 @@
 import android.os.MessageQueue;
 import android.support.test.InstrumentationRegistry;
 import android.util.ArrayMap;
-import android.util.Log;
 
 import com.android.systemui.Dependency.DependencyKey;
 import com.android.systemui.utils.TestableContext;
@@ -32,8 +31,6 @@
 import org.junit.After;
 import org.junit.Before;
 
-import java.lang.Thread.UncaughtExceptionHandler;
-
 /**
  * Base class that does System UI specific setup.
  */
@@ -92,8 +89,10 @@
         return null;
     }
 
-    public <T> void injectMockDependency(Class<T> cls) {
-        injectTestDependency(cls, mock(cls));
+    public <T> T injectMockDependency(Class<T> cls) {
+        final T mock = mock(cls);
+        mDependency.injectTestDependency(cls, mock);
+        return mock;
     }
 
     public <T> void injectTestDependency(Class<T> cls, T obj) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ExtensionControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ExtensionControllerTest.java
new file mode 100644
index 0000000..e3a5ef0
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ExtensionControllerTest.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.OverlayPlugin;
+import com.android.systemui.plugins.PluginManager;
+import com.android.systemui.statusbar.policy.ExtensionController.Extension;
+import com.android.systemui.statusbar.policy.ExtensionController.TunerFactory;
+import com.android.systemui.tuner.TunerService;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Map;
+import java.util.function.Consumer;
+
+public class ExtensionControllerTest extends SysuiTestCase {
+
+    private PluginManager mPluginManager;
+    private TunerService mTunerService;
+    private ExtensionController mExtensionController;
+
+    @Before
+    public void setup() {
+        mPluginManager = injectMockDependency(PluginManager.class);
+        mTunerService = injectMockDependency(TunerService.class);
+        mExtensionController = Dependency.get(ExtensionController.class);
+    }
+
+    @Test
+    public void testPlugin() {
+        Extension ext = mExtensionController.newExtension(OverlayPlugin.class)
+                .withPlugin(OverlayPlugin.class)
+                .build();
+        verify(mPluginManager).addPluginListener(eq(OverlayPlugin.ACTION), any(),
+                eq(OverlayPlugin.class));
+
+        ext.destroy();
+        verify(mPluginManager).removePluginListener(any());
+    }
+
+    @Test
+    public void testTuner() {
+        String[] keys = new String[] { "key1", "key2" };
+        TunerFactory<Object> factory = new ExtensionController.TunerFactory() {
+            @Override
+            public String[] keys() {
+                return keys;
+            }
+
+            @Override
+            public Object create(Map settings) {
+                return null;
+            }
+        };
+        Extension ext = mExtensionController.newExtension(Object.class)
+                .withTunerFactory(factory)
+                .build();
+        verify(mTunerService).addTunable(any(), eq(keys[0]), eq(keys[1]));
+
+        ext.destroy();
+        verify(mTunerService).removeTunable(any());
+    }
+
+    @Test
+    public void testDefault() {
+        Object o = new Object();
+        Extension ext = mExtensionController.newExtension(Object.class)
+                .withDefault(() -> o)
+                .build();
+        assertEquals(o, ext.get());
+    }
+
+    @Test
+    public void testCallback() {
+        Consumer<Object> callback = mock(Consumer.class);
+        final Object o = new Object();
+        mExtensionController.newExtension(Object.class)
+                .withDefault(() -> o)
+                .withCallback(callback)
+                .build();
+        verify(callback).accept(eq(o));
+    }
+
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeExtensionController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeExtensionController.java
new file mode 100644
index 0000000..c0f5783
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeExtensionController.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.utils.leaks;
+
+import static org.mockito.Mockito.mock;
+
+import com.android.systemui.statusbar.policy.ExtensionController;
+
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+public class FakeExtensionController implements ExtensionController {
+
+    private final Tracker mTracker;
+
+    public FakeExtensionController(LeakCheckedTest test) {
+        mTracker = test.getTracker("extension");
+    }
+
+    @Override
+    public <T> ExtensionBuilder<T> newExtension(Class<T> cls) {
+        final Object o = new Object();
+        mTracker.getLeakInfo(o).addAllocation(new Throwable());
+        return new FakeExtensionBuilder(o);
+    }
+
+    private class FakeExtensionBuilder<T> implements ExtensionBuilder<T> {
+        private final Object mAllocation;
+
+        public FakeExtensionBuilder(Object o) {
+            mAllocation = o;
+        }
+
+        @Override
+        public ExtensionBuilder<T> withTunerFactory(TunerFactory<T> factory) {
+            return this;
+        }
+
+        @Override
+        public <P extends T> ExtensionBuilder<T> withPlugin(Class<P> cls) {
+            return this;
+        }
+
+        @Override
+        public <P extends T> ExtensionBuilder<T> withPlugin(Class<P> cls, String action) {
+            return this;
+        }
+
+        @Override
+        public <P> ExtensionBuilder<T> withPlugin(Class<P> cls, String action, PluginConverter<T, P> converter) {
+            return this;
+        }
+
+        @Override
+        public ExtensionBuilder<T> withDefault(Supplier<T> def) {
+            return this;
+        }
+
+        @Override
+        public ExtensionBuilder<T> withCallback(Consumer<T> callback) {
+            return this;
+        }
+
+        @Override
+        public Extension build() {
+            return new FakeExtension(mAllocation);
+        }
+    }
+
+    private class FakeExtension<T> implements Extension<T> {
+        private final Object mAllocation;
+
+        public FakeExtension(Object allocation) {
+            mAllocation = allocation;
+        }
+
+        @Override
+        public T get() {
+            // TODO: Support defaults or things.
+            return null;
+        }
+
+        @Override
+        public void destroy() {
+            mTracker.getLeakInfo(mAllocation).clearAllocations();
+        }
+    }
+}
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 4d2b106..c50623e 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -709,7 +709,7 @@
     }
 
     private boolean isUserRunningAndUnlocked(@UserIdInt int userId) {
-        return mUserManager.isUserRunning(userId) && StorageManager.isUserKeyUnlocked(userId);
+        return mUserManager.isUserUnlockingOrUnlocked(userId);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index ef7780c..979096e 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -19,6 +19,7 @@
 import android.app.ActivityManager;
 import android.annotation.NonNull;
 import android.content.pm.PackageManagerInternal;
+import android.util.ArrayMap;
 import android.util.ArraySet;
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.location.ProviderProperties;
@@ -104,6 +105,7 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.NoSuchElementException;
 import java.util.Set;
 
@@ -225,6 +227,12 @@
 
     private final ArraySet<String> mBackgroundThrottlePackageWhitelist = new ArraySet<>();
 
+    private final ArrayMap<IGnssMeasurementsListener, Identity> mGnssMeasurementsListeners =
+            new ArrayMap<>();
+
+    private final ArrayMap<IGnssNavigationMessageListener, Identity>
+            mGnssNavigationMessageListeners = new ArrayMap<>();
+
     // current active user on the device - other users are denied location data
     private int mCurrentUserId = UserHandle.USER_SYSTEM;
     private int[] mCurrentUserProfiles = new int[] { UserHandle.USER_SYSTEM };
@@ -315,17 +323,17 @@
                     boolean foreground = isImportanceForeground(importance);
                     HashSet<String> affectedProviders = new HashSet<>(mRecordsByProvider.size());
                     synchronized (mLock) {
-                        for (Map.Entry<String, ArrayList<UpdateRecord>> entry
+                        for (Entry<String, ArrayList<UpdateRecord>> entry
                                 : mRecordsByProvider.entrySet()) {
                             String provider = entry.getKey();
                             for (UpdateRecord record : entry.getValue()) {
-                                if (record.mReceiver.mUid == uid
+                                if (record.mReceiver.mIdentity.mUid == uid
                                         && record.mIsForegroundUid != foreground) {
                                     if (D) Log.d(TAG, "request from uid " + uid + " is now "
                                             + (foreground ? "foreground" : "background)"));
                                     record.mIsForegroundUid = foreground;
 
-                                    if (!isThrottlingExemptLocked(record.mReceiver)) {
+                                    if (!isThrottlingExemptLocked(record.mReceiver.mIdentity)) {
                                         affectedProviders.add(provider);
                                     }
                                 }
@@ -334,6 +342,33 @@
                         for (String provider : affectedProviders) {
                             applyRequirementsLocked(provider);
                         }
+
+                        for (Entry<IGnssMeasurementsListener, Identity> entry
+                                : mGnssMeasurementsListeners.entrySet()) {
+                            if (entry.getValue().mUid == uid) {
+                                if (D) Log.d(TAG, "gnss measurements listener from uid " + uid
+                                    + " is now " + (foreground ? "foreground" : "background)"));
+                                if (foreground || isThrottlingExemptLocked(entry.getValue())) {
+                                    mGnssMeasurementsProvider.addListener(entry.getKey());
+                                } else {
+                                    mGnssMeasurementsProvider.removeListener(entry.getKey());
+                                }
+                            }
+                        }
+
+                        for (Entry<IGnssNavigationMessageListener, Identity> entry
+                            : mGnssNavigationMessageListeners.entrySet()) {
+                            if (entry.getValue().mUid == uid) {
+                                if (D) Log.d(TAG, "gnss navigation message listener from uid "
+                                    + uid + " is now "
+                                    + (foreground ? "foreground" : "background)"));
+                                if (foreground || isThrottlingExemptLocked(entry.getValue())) {
+                                    mGnssNavigationMessageProvider.addListener(entry.getKey());
+                                } else {
+                                    mGnssNavigationMessageProvider.removeListener(entry.getKey());
+                                }
+                            }
+                        }
                     }
 
                 }
@@ -344,7 +379,7 @@
             mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
             updateUserProfiles(mCurrentUserId);
 
-            updateThrottlingWhitelistLocked();
+            updateBackgroundThrottlingWhitelistLocked();
 
             // prepare providers
             loadProvidersLocked();
@@ -381,7 +416,7 @@
                 @Override
                 public void onChange(boolean selfChange) {
                     synchronized (mLock) {
-                        updateThrottlingWhitelistLocked();
+                        updateBackgroundThrottlingWhitelistLocked();
                         updateProvidersLocked();
                     }
                 }
@@ -721,14 +756,24 @@
         }
     }
 
+    private static final class Identity {
+        final int mUid;
+        final int mPid;
+        final String mPackageName;
+
+        Identity(int uid, int pid, String packageName) {
+            mUid = uid;
+            mPid = pid;
+            mPackageName = packageName;
+        }
+    }
+
     /**
      * A wrapper class holding either an ILocationListener or a PendingIntent to receive
      * location updates.
      */
     private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
-        final int mUid;  // uid of receiver
-        final int mPid;  // pid of receiver
-        final String mPackageName;  // package name of receiver
+        final Identity mIdentity;
         final int mAllowedResolutionLevel;  // resolution level allowed to receiver
 
         final ILocationListener mListener;
@@ -756,9 +801,7 @@
                 mKey = intent;
             }
             mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid);
-            mUid = uid;
-            mPid = pid;
-            mPackageName = packageName;
+            mIdentity = new Identity(uid, pid, packageName);
             if (workSource != null && workSource.size() <= 0) {
                 workSource = null;
             }
@@ -770,7 +813,7 @@
             // construct/configure wakelock
             mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
             if (workSource == null) {
-                workSource = new WorkSource(mUid, mPackageName);
+                workSource = new WorkSource(mIdentity.mUid, mIdentity.mPackageName);
             }
             mWakeLock.setWorkSource(workSource);
         }
@@ -865,13 +908,14 @@
                 int op) {
             if (!currentlyMonitoring) {
                 if (allowMonitoring) {
-                    return mAppOps.startOpNoThrow(op, mUid, mPackageName)
+                    return mAppOps.startOpNoThrow(op, mIdentity.mUid, mIdentity.mPackageName)
                             == AppOpsManager.MODE_ALLOWED;
                 }
             } else {
-                if (!allowMonitoring || mAppOps.checkOpNoThrow(op, mUid, mPackageName)
+                if (!allowMonitoring
+                        || mAppOps.checkOpNoThrow(op, mIdentity.mUid, mIdentity.mPackageName)
                         != AppOpsManager.MODE_ALLOWED) {
-                    mAppOps.finishOp(op, mUid, mPackageName);
+                    mAppOps.finishOp(op, mIdentity.mUid, mIdentity.mPackageName);
                     return false;
                 }
             }
@@ -1628,7 +1672,7 @@
         ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
         if (records != null) {
             for (UpdateRecord record : records) {
-                if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) {
+                if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
                     // Sends a notification message to the receiver
                     if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
                         if (deadReceivers == null) {
@@ -1673,16 +1717,16 @@
 
         if (records != null) {
             for (UpdateRecord record : records) {
-                if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) {
+                if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
                     if (checkLocationAccess(
-                            record.mReceiver.mPid,
-                            record.mReceiver.mUid,
-                            record.mReceiver.mPackageName,
+                            record.mReceiver.mIdentity.mPid,
+                            record.mReceiver.mIdentity.mUid,
+                            record.mReceiver.mIdentity.mPackageName,
                             record.mReceiver.mAllowedResolutionLevel)) {
                         LocationRequest locationRequest = record.mRequest;
                         long interval = locationRequest.getInterval();
 
-                        if (!isThrottlingExemptLocked(record.mReceiver)) {
+                        if (!isThrottlingExemptLocked(record.mReceiver.mIdentity)) {
                             if (!record.mIsForegroundUid) {
                                 interval = Math.max(interval, backgroundThrottleInterval);
                             }
@@ -1709,7 +1753,7 @@
                 // under that threshold.
                 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
                 for (UpdateRecord record : records) {
-                    if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) {
+                    if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mIdentity.mUid))) {
                         LocationRequest locationRequest = record.mRequest;
 
                         // Don't assign battery blame for update records whose
@@ -1728,8 +1772,8 @@
                             } else {
                                 // Assign blame to caller.
                                 worksource.add(
-                                        record.mReceiver.mUid,
-                                        record.mReceiver.mPackageName);
+                                        record.mReceiver.mIdentity.mUid,
+                                        record.mReceiver.mIdentity.mPackageName);
                             }
                         }
                     }
@@ -1741,7 +1785,15 @@
         p.setRequest(providerRequest, worksource);
     }
 
-    private void updateThrottlingWhitelistLocked() {
+    @Override
+    public String[] getBackgroundThrottlingWhitelist() {
+        synchronized (mLock) {
+            return mBackgroundThrottlePackageWhitelist.toArray(
+                new String[mBackgroundThrottlePackageWhitelist.size()]);
+        }
+    }
+
+    private void updateBackgroundThrottlingWhitelistLocked() {
         String setting = Settings.Global.getString(
             mContext.getContentResolver(),
             Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST);
@@ -1756,17 +1808,17 @@
             Arrays.asList(setting.split(",")));
     }
 
-    private boolean isThrottlingExemptLocked(Receiver receiver) {
-        if (receiver.mUid == Process.SYSTEM_UID) {
+    private boolean isThrottlingExemptLocked(Identity identity) {
+        if (identity.mUid == Process.SYSTEM_UID) {
             return true;
         }
 
-        if (mBackgroundThrottlePackageWhitelist.contains(receiver.mPackageName)) {
+        if (mBackgroundThrottlePackageWhitelist.contains(identity.mPackageName)) {
             return true;
         }
 
         for (LocationProviderProxy provider : mProxyProviders) {
-            if (receiver.mPackageName.equals(provider.getConnectedPackageName())) {
+            if (identity.mPackageName.equals(provider.getConnectedPackageName())) {
                 return true;
             }
         }
@@ -1790,7 +1842,7 @@
             mRequest = request;
             mReceiver = receiver;
             mIsForegroundUid = isImportanceForeground(
-                    mActivityManager.getPackageImportance(mReceiver.mPackageName));
+                    mActivityManager.getPackageImportance(mReceiver.mIdentity.mPackageName));
 
             ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
             if (records == null) {
@@ -1803,14 +1855,14 @@
 
             // Update statistics for historical location requests by package/provider
             mRequestStatistics.startRequesting(
-                    mReceiver.mPackageName, provider, request.getInterval());
+                    mReceiver.mIdentity.mPackageName, provider, request.getInterval());
         }
 
         /**
          * Method to be called when a record will no longer be used.
          */
         void disposeLocked(boolean removeReceiver) {
-            mRequestStatistics.stopRequesting(mReceiver.mPackageName, mProvider);
+            mRequestStatistics.stopRequesting(mReceiver.mIdentity.mPackageName, mProvider);
 
             // remove from mRecordsByProvider
             ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
@@ -1834,8 +1886,8 @@
 
         @Override
         public String toString() {
-            return "UpdateRecord[" + mProvider + " " + mReceiver.mPackageName
-                    + "(" + mReceiver.mUid + (mIsForegroundUid ? " foreground" : " background")
+            return "UpdateRecord[" + mProvider + " " + mReceiver.mIdentity.mPackageName
+                    + "(" + mReceiver.mIdentity.mUid + (mIsForegroundUid ? " foreground" : " background")
                     + ")" + " " + mRequest + "]";
         }
     }
@@ -1994,7 +2046,8 @@
         if (D) Log.d(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver))
                 + " " + name + " " + request + " from " + packageName + "(" + uid + " "
                 + (record.mIsForegroundUid ? "foreground" : "background")
-                + (isThrottlingExemptLocked(receiver) ? " [whitelisted]" : "") + ")");
+                + (isThrottlingExemptLocked(receiver.mIdentity)
+                    ? " [whitelisted]" : "") + ")");
 
         UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
         if (oldRecord != null) {
@@ -2227,13 +2280,33 @@
         if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) {
             return false;
         }
-        return mGnssMeasurementsProvider.addListener(listener);
+
+        synchronized (mLock) {
+            Identity callerIdentity
+                    = new Identity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
+            mGnssMeasurementsListeners.put(listener, callerIdentity);
+            long identity = Binder.clearCallingIdentity();
+            try {
+                if (isThrottlingExemptLocked(callerIdentity)
+                        || isImportanceForeground(
+                                mActivityManager.getPackageImportance(packageName))) {
+                    return mGnssMeasurementsProvider.addListener(listener);
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+
+            return true;
+        }
     }
 
     @Override
     public void removeGnssMeasurementsListener(IGnssMeasurementsListener listener) {
         if (mGnssMeasurementsProvider != null) {
-            mGnssMeasurementsProvider.removeListener(listener);
+            synchronized (mLock) {
+                mGnssMeasurementsListeners.remove(listener);
+                mGnssMeasurementsProvider.removeListener(listener);
+            }
         }
     }
 
@@ -2244,13 +2317,33 @@
         if (!hasGnssPermissions(packageName) || mGnssNavigationMessageProvider == null) {
             return false;
         }
-        return mGnssNavigationMessageProvider.addListener(listener);
+
+        synchronized (mLock) {
+            Identity callerIdentity
+                = new Identity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
+            mGnssNavigationMessageListeners.put(listener, callerIdentity);
+            long identity = Binder.clearCallingIdentity();
+            try {
+                if (isThrottlingExemptLocked(callerIdentity)
+                        || isImportanceForeground(
+                                mActivityManager.getPackageImportance(packageName))) {
+                    return mGnssNavigationMessageProvider.addListener(listener);
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+
+            return true;
+        }
     }
 
     @Override
     public void removeGnssNavigationMessageListener(IGnssNavigationMessageListener listener) {
         if (mGnssNavigationMessageProvider != null) {
-            mGnssNavigationMessageProvider.removeListener(listener);
+            synchronized (mLock) {
+                mGnssNavigationMessageListeners.remove(listener);
+                mGnssNavigationMessageProvider.removeListener(listener);
+            }
         }
     }
 
@@ -2529,26 +2622,30 @@
             Receiver receiver = r.mReceiver;
             boolean receiverDead = false;
 
-            int receiverUserId = UserHandle.getUserId(receiver.mUid);
-            if (!isCurrentProfile(receiverUserId) && !isUidALocationProvider(receiver.mUid)) {
+            int receiverUserId = UserHandle.getUserId(receiver.mIdentity.mUid);
+            if (!isCurrentProfile(receiverUserId)
+                    && !isUidALocationProvider(receiver.mIdentity.mUid)) {
                 if (D) {
                     Log.d(TAG, "skipping loc update for background user " + receiverUserId +
                             " (current user: " + mCurrentUserId + ", app: " +
-                            receiver.mPackageName + ")");
+                            receiver.mIdentity.mPackageName + ")");
                 }
                 continue;
             }
 
-            if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
+            if (mBlacklist.isBlacklisted(receiver.mIdentity.mPackageName)) {
                 if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
-                        receiver.mPackageName);
+                        receiver.mIdentity.mPackageName);
                 continue;
             }
 
-            if (!reportLocationAccessNoThrow(receiver.mPid, receiver.mUid, receiver.mPackageName,
+            if (!reportLocationAccessNoThrow(
+                    receiver.mIdentity.mPid,
+                    receiver.mIdentity.mUid,
+                    receiver.mIdentity.mPackageName,
                     receiver.mAllowedResolutionLevel)) {
                 if (D) Log.d(TAG, "skipping loc update for no op app: " +
-                        receiver.mPackageName);
+                        receiver.mIdentity.mPackageName);
                 continue;
             }
 
@@ -2671,7 +2768,7 @@
                 ArrayList<Receiver> deadReceivers = null;
 
                 for (Receiver receiver : mReceivers.values()) {
-                    if (receiver.mPackageName.equals(packageName)) {
+                    if (receiver.mIdentity.mPackageName.equals(packageName)) {
                         if (deadReceivers == null) {
                             deadReceivers = new ArrayList<>();
                         }
diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java
index b33538cb..d54ebaa 100644
--- a/services/core/java/com/android/server/NetworkScoreService.java
+++ b/services/core/java/com/android/server/NetworkScoreService.java
@@ -35,8 +35,7 @@
 import android.net.INetworkScoreService;
 import android.net.NetworkKey;
 import android.net.NetworkScoreManager;
-import android.net.NetworkScorerAppManager;
-import android.net.NetworkScorerAppManager.NetworkScorerAppData;
+import android.net.NetworkScorerAppData;
 import android.net.RecommendationRequest;
 import android.net.RecommendationResult;
 import android.net.ScoredNetwork;
@@ -132,10 +131,10 @@
      * manages the service connection.
      */
     private class NetworkScorerPackageMonitor extends PackageMonitor {
-        final List<String> mPackagesToWatch;
+        final String mPackageToWatch;
 
-        private NetworkScorerPackageMonitor(List<String> packagesToWatch) {
-            mPackagesToWatch = packagesToWatch;
+        private NetworkScorerPackageMonitor(String packageToWatch) {
+            mPackageToWatch = packageToWatch;
         }
 
         @Override
@@ -168,37 +167,27 @@
             evaluateBinding(packageName, true /* forceUnbind */);
         }
 
-        private void evaluateBinding(String scorerPackageName, boolean forceUnbind) {
-            if (!mPackagesToWatch.contains(scorerPackageName)) {
+        private void evaluateBinding(String changedPackageName, boolean forceUnbind) {
+            if (!mPackageToWatch.equals(changedPackageName)) {
                 // Early exit when we don't care about the package that has changed.
                 return;
             }
 
             if (DBG) {
-                Log.d(TAG, "Evaluating binding for: " + scorerPackageName
+                Log.d(TAG, "Evaluating binding for: " + changedPackageName
                         + ", forceUnbind=" + forceUnbind);
             }
+
             final NetworkScorerAppData activeScorer = mNetworkScorerAppManager.getActiveScorer();
             if (activeScorer == null) {
                 // Package change has invalidated a scorer, this will also unbind any service
                 // connection.
                 if (DBG) Log.d(TAG, "No active scorers available.");
-                unbindFromScoringServiceIfNeeded();
-            } else if (activeScorer.getRecommendationServicePackageName().equals(scorerPackageName))
-            {
-                // The active scoring service changed in some way.
-                if (DBG) {
-                    Log.d(TAG, "Possible change to the active scorer: "
-                            + activeScorer.getRecommendationServicePackageName());
-                }
+                refreshBinding();
+            } else { // The scoring service changed in some way.
                 if (forceUnbind) {
                     unbindFromScoringServiceIfNeeded();
                 }
-                bindToScoringServiceIfNeeded(activeScorer);
-            } else {
-                // One of the scoring apps on the device has changed and we may no longer be
-                // bound to the correct scoring app. The logic in bindToScoringServiceIfNeeded()
-                // will sort that out to leave us bound to the most recent active scorer.
                 if (DBG) {
                     Log.d(TAG, "Binding to " + activeScorer.getRecommendationServiceComponent()
                             + " if needed.");
@@ -272,60 +261,71 @@
     /** Called when the system is ready to run third-party code but before it actually does so. */
     void systemReady() {
         if (DBG) Log.d(TAG, "systemReady");
-        registerPackageMonitorIfNeeded();
         registerRecommendationSettingsObserver();
-        refreshRecommendationRequestTimeoutMs();
     }
 
     /** Called when the system is ready for us to start third-party code. */
     void systemRunning() {
         if (DBG) Log.d(TAG, "systemRunning");
-        bindToScoringServiceIfNeeded();
     }
 
-    private void onUserUnlocked(int userId) {
+    @VisibleForTesting
+    void onUserUnlocked(int userId) {
+        if (DBG) Log.d(TAG, "onUserUnlocked(" + userId + ")");
+        refreshBinding();
+    }
+
+    private void refreshBinding() {
+        if (DBG) Log.d(TAG, "refreshBinding()");
+        // Apply the default package name if the Setting isn't set.
+        mNetworkScorerAppManager.revertToDefaultIfNoActive();
         registerPackageMonitorIfNeeded();
         bindToScoringServiceIfNeeded();
     }
 
     private void registerRecommendationSettingsObserver() {
-        final List<String> providerPackages =
-            mNetworkScorerAppManager.getPotentialRecommendationProviderPackages();
-        if (!providerPackages.isEmpty()) {
-            final Uri enabledUri = Global.getUriFor(Global.NETWORK_RECOMMENDATIONS_ENABLED);
-            mContentObserver.observe(enabledUri,
-                    ServiceHandler.MSG_RECOMMENDATIONS_ENABLED_CHANGED);
-        }
+        final Uri packageNameUri = Global.getUriFor(Global.NETWORK_RECOMMENDATIONS_PACKAGE);
+        mContentObserver.observe(packageNameUri,
+                ServiceHandler.MSG_RECOMMENDATIONS_PACKAGE_CHANGED);
 
         final Uri timeoutUri = Global.getUriFor(Global.NETWORK_RECOMMENDATION_REQUEST_TIMEOUT_MS);
         mContentObserver.observe(timeoutUri,
                 ServiceHandler.MSG_RECOMMENDATION_REQUEST_TIMEOUT_CHANGED);
     }
 
+    /**
+     * Ensures the package manager is registered to monitor the current active scorer.
+     * If a discrepancy is found any previous monitor will be cleaned up
+     * and a new monitor will be created.
+     *
+     * This method is idempotent.
+     */
     private void registerPackageMonitorIfNeeded() {
-        if (DBG) Log.d(TAG, "registerPackageMonitorIfNeeded");
-        final List<String> providerPackages =
-            mNetworkScorerAppManager.getPotentialRecommendationProviderPackages();
+        if (DBG) Log.d(TAG, "registerPackageMonitorIfNeeded()");
+        final NetworkScorerAppData appData = mNetworkScorerAppManager.getActiveScorer();
         synchronized (mPackageMonitorLock) {
             // Unregister the current monitor if needed.
-            if (mPackageMonitor != null) {
+            if (mPackageMonitor != null && (appData == null
+                    || !appData.getRecommendationServicePackageName().equals(
+                            mPackageMonitor.mPackageToWatch))) {
                 if (DBG) {
                     Log.d(TAG, "Unregistering package monitor for "
-                            + mPackageMonitor.mPackagesToWatch);
+                            + mPackageMonitor.mPackageToWatch);
                 }
                 mPackageMonitor.unregister();
                 mPackageMonitor = null;
             }
 
-            // Create and register the monitor if there are packages that could be providers.
-            if (!providerPackages.isEmpty()) {
-                mPackageMonitor = new NetworkScorerPackageMonitor(providerPackages);
+            // Create and register the monitor if a scorer is active.
+            if (appData != null && mPackageMonitor == null) {
+                mPackageMonitor = new NetworkScorerPackageMonitor(
+                        appData.getRecommendationServicePackageName());
                 // TODO: Need to update when we support per-user scorers. http://b/23422763
                 mPackageMonitor.register(mContext, null /* thread */, UserHandle.SYSTEM,
                         false /* externalStorage */);
                 if (DBG) {
                     Log.d(TAG, "Registered package monitor for "
-                            + mPackageMonitor.mPackagesToWatch);
+                            + mPackageMonitor.mPackageToWatch);
                 }
             }
         }
@@ -337,6 +337,13 @@
         bindToScoringServiceIfNeeded(scorerData);
     }
 
+    /**
+     * Ensures the service connection is bound to the current active scorer.
+     * If a discrepancy is found any previous connection will be cleaned up
+     * and a new connection will be created.
+     *
+     * This method is idempotent.
+     */
     private void bindToScoringServiceIfNeeded(NetworkScorerAppData appData) {
         if (DBG) Log.d(TAG, "bindToScoringServiceIfNeeded(" + appData + ")");
         if (appData != null) {
@@ -365,6 +372,8 @@
         synchronized (mServiceConnectionLock) {
             if (mServiceConnection != null) {
                 mServiceConnection.disconnect(mContext);
+                if (DBG) Log.d(TAG, "Disconnected from: "
+                        + mServiceConnection.mAppData.getRecommendationServiceComponent());
             }
             mServiceConnection = null;
         }
@@ -653,17 +662,13 @@
 
     @Override
     public boolean setActiveScorer(String packageName) {
-        // TODO: For now, since SCORE_NETWORKS requires an app to be privileged, we allow such apps
-        // to directly set the scorer app rather than having to use the consent dialog. The
-        // assumption is that anyone bundling a scorer app with the system is trusted by the OEM to
-        // do the right thing and not enable this feature without explaining it to the user.
-        // In the future, should this API be opened to 3p apps, we will need to lock this down and
-        // figure out another way to streamline the UX.
-
-        mContext.enforceCallingOrSelfPermission(permission.SCORE_NETWORKS, TAG);
-
-        // Scorers (recommendation providers) are selected and no longer set.
-        return false;
+        // Only the system can set the active scorer
+        if (isCallerSystemProcess(getCallingUid()) || callerCanRequestScores()) {
+            return mNetworkScorerAppManager.setActiveScorer(packageName);
+        } else {
+            throw new SecurityException(
+                    "Caller is neither the system process nor a score requester.");
+        }
     }
 
     /**
@@ -700,7 +705,6 @@
         return null;
     }
 
-
     /**
      * Returns metadata about the active scorer or <code>null</code> if there is no active scorer.
      */
@@ -727,7 +731,13 @@
      */
     @Override
     public List<NetworkScorerAppData> getAllValidScorers() {
-        return mNetworkScorerAppManager.getAllValidScorers();
+        // Only the system can access this data.
+        if (isCallerSystemProcess(getCallingUid()) || callerCanRequestScores()) {
+            return mNetworkScorerAppManager.getAllValidScorers();
+        } else {
+            throw new SecurityException(
+                    "Caller is neither the system process nor a score requester.");
+        }
     }
 
     @Override
@@ -1159,7 +1169,7 @@
     @VisibleForTesting
     public final class ServiceHandler extends Handler {
         public static final int MSG_RECOMMENDATION_REQUEST_TIMEOUT = 1;
-        public static final int MSG_RECOMMENDATIONS_ENABLED_CHANGED = 2;
+        public static final int MSG_RECOMMENDATIONS_PACKAGE_CHANGED = 2;
         public static final int MSG_RECOMMENDATION_REQUEST_TIMEOUT_CHANGED = 3;
 
         public ServiceHandler(Looper looper) {
@@ -1181,8 +1191,8 @@
                     sendDefaultRecommendationResponse(request, remoteCallback);
                     break;
 
-                case MSG_RECOMMENDATIONS_ENABLED_CHANGED:
-                    bindToScoringServiceIfNeeded();
+                case MSG_RECOMMENDATIONS_PACKAGE_CHANGED:
+                    refreshBinding();
                     break;
 
                 case MSG_RECOMMENDATION_REQUEST_TIMEOUT_CHANGED:
diff --git a/services/core/java/com/android/server/NetworkScorerAppManager.java b/services/core/java/com/android/server/NetworkScorerAppManager.java
new file mode 100644
index 0000000..2f4485a
--- /dev/null
+++ b/services/core/java/com/android/server/NetworkScorerAppManager.java
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server;
+
+import android.Manifest.permission;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.net.NetworkScoreManager;
+import android.net.NetworkScorerAppData;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Internal class for discovering and managing the network scorer/recommendation application.
+ *
+ * @hide
+ */
+@VisibleForTesting
+public class NetworkScorerAppManager {
+    private static final String TAG = "NetworkScorerAppManager";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+    private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
+    private final Context mContext;
+    private final SettingsFacade mSettingsFacade;
+
+    public NetworkScorerAppManager(Context context) {
+      this(context, new SettingsFacade());
+    }
+
+    @VisibleForTesting
+    public NetworkScorerAppManager(Context context, SettingsFacade settingsFacade) {
+        mContext = context;
+        mSettingsFacade = settingsFacade;
+    }
+
+    /**
+     * Returns the list of available scorer apps. The list will be empty if there are
+     * no valid scorers.
+     */
+    @VisibleForTesting
+    public List<NetworkScorerAppData> getAllValidScorers() {
+        if (VERBOSE) Log.v(TAG, "getAllValidScorers()");
+        final PackageManager pm = mContext.getPackageManager();
+        final Intent serviceIntent = new Intent(NetworkScoreManager.ACTION_RECOMMEND_NETWORKS);
+        final List<ResolveInfo> resolveInfos =
+                pm.queryIntentServices(serviceIntent, PackageManager.GET_META_DATA);
+        if (resolveInfos == null || resolveInfos.isEmpty()) {
+            if (DEBUG) Log.d(TAG, "Found 0 Services able to handle " + serviceIntent);
+            return Collections.emptyList();
+        }
+
+        List<NetworkScorerAppData> appDataList = new ArrayList<>();
+        for (int i = 0; i < resolveInfos.size(); i++) {
+            final ServiceInfo serviceInfo = resolveInfos.get(i).serviceInfo;
+            if (hasPermissions(serviceInfo.packageName)) {
+                if (VERBOSE) {
+                    Log.v(TAG, serviceInfo.packageName + " is a valid scorer/recommender.");
+                }
+                final ComponentName serviceComponentName =
+                        new ComponentName(serviceInfo.packageName, serviceInfo.name);
+                final ComponentName useOpenWifiNetworksActivity =
+                        findUseOpenWifiNetworksActivity(serviceInfo);
+                appDataList.add(
+                        new NetworkScorerAppData(serviceInfo.applicationInfo.uid,
+                                serviceComponentName, useOpenWifiNetworksActivity));
+            } else {
+                if (VERBOSE) Log.v(TAG, serviceInfo.packageName
+                        + " is NOT a valid scorer/recommender.");
+            }
+        }
+
+        return appDataList;
+    }
+
+    @Nullable
+    private ComponentName findUseOpenWifiNetworksActivity(ServiceInfo serviceInfo) {
+        if (serviceInfo.metaData == null) {
+            if (DEBUG) {
+                Log.d(TAG, "No metadata found on " + serviceInfo.getComponentName());
+            }
+            return null;
+        }
+        final String useOpenWifiPackage = serviceInfo.metaData
+                .getString(NetworkScoreManager.USE_OPEN_WIFI_PACKAGE_META_DATA);
+        if (TextUtils.isEmpty(useOpenWifiPackage)) {
+            if (DEBUG) {
+                Log.d(TAG, "No use_open_wifi_package metadata found on "
+                        + serviceInfo.getComponentName());
+            }
+            return null;
+        }
+        final Intent enableUseOpenWifiIntent = new Intent(NetworkScoreManager.ACTION_CUSTOM_ENABLE)
+                .setPackage(useOpenWifiPackage);
+        final ResolveInfo resolveActivityInfo = mContext.getPackageManager()
+                .resolveActivity(enableUseOpenWifiIntent, 0 /* flags */);
+        if (VERBOSE) {
+            Log.d(TAG, "Resolved " + enableUseOpenWifiIntent + " to " + resolveActivityInfo);
+        }
+
+        if (resolveActivityInfo != null && resolveActivityInfo.activityInfo != null) {
+            return resolveActivityInfo.activityInfo.getComponentName();
+        }
+
+        return null;
+    }
+
+    /**
+     * Get the application to use for scoring networks.
+     *
+     * @return the scorer app info or null if scoring is disabled (including if no scorer was ever
+     *     selected) or if the previously-set scorer is no longer a valid scorer app (e.g. because
+     *     it was disabled or uninstalled).
+     */
+    @Nullable
+    @VisibleForTesting
+    public NetworkScorerAppData getActiveScorer() {
+        return getScorer(getNetworkRecommendationsPackage());
+    }
+
+    private NetworkScorerAppData getScorer(String packageName) {
+        if (TextUtils.isEmpty(packageName)) {
+            return null;
+        }
+
+        // Otherwise return the recommendation provider (which may be null).
+        List<NetworkScorerAppData> apps = getAllValidScorers();
+        for (int i = 0; i < apps.size(); i++) {
+            NetworkScorerAppData app = apps.get(i);
+            if (app.getRecommendationServicePackageName().equals(packageName)) {
+                return app;
+            }
+        }
+
+        return null;
+    }
+
+    private boolean hasPermissions(String packageName) {
+        final PackageManager pm = mContext.getPackageManager();
+        return pm.checkPermission(permission.SCORE_NETWORKS, packageName)
+                == PackageManager.PERMISSION_GRANTED;
+    }
+
+    /**
+     * Set the specified package as the default scorer application.
+     *
+     * <p>The caller must have permission to write to {@link Settings.Global}.
+     *
+     * @param packageName the packageName of the new scorer to use. If null, the scoring app will
+     *                    revert back to the configured default. Otherwise, the scorer will only
+     *                    be set if it is a valid scorer application.
+     * @return true if the scorer was changed, or false if the package is not a valid scorer or
+     *         a valid network recommendation provider exists.
+     */
+    @VisibleForTesting
+    public boolean setActiveScorer(String packageName) {
+        String oldPackageName = getNetworkRecommendationsPackage();
+        if (TextUtils.equals(oldPackageName, packageName)) {
+            // No change.
+            return true;
+        }
+
+        Log.i(TAG, "Changing network scorer from " + oldPackageName + " to " + packageName);
+
+        if (packageName == null) {
+            // revert to the default setting.
+            setNetworkRecommendationsPackage(getDefaultPackageSetting());
+            return true;
+        } else {
+            // We only make the change if the new package is valid.
+            if (getScorer(packageName) != null) {
+                setNetworkRecommendationsPackage(packageName);
+                return true;
+            } else {
+                Log.w(TAG, "Requested network scorer is not valid: " + packageName);
+                return false;
+            }
+        }
+    }
+
+    /**
+     * If the active scorer is null then revert to the default scorer.
+     */
+    @VisibleForTesting
+    public void revertToDefaultIfNoActive() {
+        if (getActiveScorer() == null) {
+            final String defaultPackage = getDefaultPackageSetting();
+            setNetworkRecommendationsPackage(defaultPackage);
+            Log.i(TAG, "Defaulted the network recommendations app to: " + defaultPackage);
+        }
+    }
+
+    private String getDefaultPackageSetting() {
+        return mContext.getResources().getString(
+                R.string.config_defaultNetworkRecommendationProviderPackage);
+    }
+
+    private String getNetworkRecommendationsPackage() {
+        return mSettingsFacade.getString(mContext, Settings.Global.NETWORK_RECOMMENDATIONS_PACKAGE);
+    }
+
+    private void setNetworkRecommendationsPackage(String packageName) {
+        mSettingsFacade.putString(mContext,
+                Settings.Global.NETWORK_RECOMMENDATIONS_PACKAGE, packageName);
+    }
+
+    /**
+     * Wrapper around Settings to make testing easier.
+     */
+    public static class SettingsFacade {
+        public boolean putString(Context context, String name, String value) {
+            return Settings.Global.putString(context.getContentResolver(), name, value);
+        }
+
+        public String getString(Context context, String name) {
+            return Settings.Global.getString(context.getContentResolver(), name);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/SystemService.java b/services/core/java/com/android/server/SystemService.java
index ce3166d..421d5a6 100644
--- a/services/core/java/com/android/server/SystemService.java
+++ b/services/core/java/com/android/server/SystemService.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.os.IBinder;
 import android.os.ServiceManager;
+import android.os.UserManager;
 
 /**
  * The base class for services running in the system process. Override and implement
@@ -133,9 +134,16 @@
     public void onStartUser(int userHandle) {}
 
     /**
-     * Called when an existing user is unlocked. This means the
-     * credential-encrypted storage for that user is now available, and
-     * encryption-aware component filtering is no longer in effect.
+     * Called when an existing user is in the process of being unlocked. This
+     * means the credential-encrypted storage for that user is now available,
+     * and encryption-aware component filtering is no longer in effect.
+     * <p>
+     * While dispatching this event to services, the user is in the
+     * {@code STATE_RUNNING_UNLOCKING} state, and once dispatching is finished
+     * the user will transition into the {@code STATE_RUNNING_UNLOCKED} state.
+     * Code written inside system services should use
+     * {@link UserManager#isUserUnlockingOrUnlocked(int)} to handle both of
+     * these states.
      *
      * @param userHandle The identifier of the user.
      */
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 7524351..d287d85 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -10708,10 +10708,7 @@
         } catch (RemoteException ignored) {
         }
         if (cpi == null) {
-            // TODO: make this an outright failure in a future platform release;
-            // until then anonymous content notifications are unprotected
-            //return "Failed to find provider " + authority + " for user " + userId;
-            return null;
+            return "Failed to find provider " + authority + " for user " + userId;
         }
 
         ProcessRecord r = null;
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index 886c97f..4b34eba56 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -43,6 +43,7 @@
 import android.database.sqlite.SQLiteException;
 import android.net.Uri;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.FactoryTest;
 import android.os.IBinder;
@@ -287,7 +288,7 @@
      */
     @Override
     public void registerContentObserver(Uri uri, boolean notifyForDescendants,
-                                        IContentObserver observer, int userHandle) {
+            IContentObserver observer, int userHandle, int targetSdkVersion) {
         if (observer == null || uri == null) {
             throw new IllegalArgumentException("You must pass a valid uri and observer");
         }
@@ -301,8 +302,17 @@
         final String msg = LocalServices.getService(ActivityManagerInternal.class)
                 .checkContentProviderAccess(uri.getAuthority(), userHandle);
         if (msg != null) {
-            Log.w(TAG, "Ignoring content changes for " + uri + " from " + uid + ": " + msg);
-            return;
+            if (targetSdkVersion >= Build.VERSION_CODES.O) {
+                throw new SecurityException(msg);
+            } else {
+                if (msg.startsWith("Failed to find provider")) {
+                    // Sigh, we need to quietly let apps targeting older API
+                    // levels notify on non-existent providers.
+                } else {
+                    Log.w(TAG, "Ignoring content changes for " + uri + " from " + uid + ": " + msg);
+                    return;
+                }
+            }
         }
 
         synchronized (mRootNode) {
@@ -316,7 +326,7 @@
     public void registerContentObserver(Uri uri, boolean notifyForDescendants,
                                         IContentObserver observer) {
         registerContentObserver(uri, notifyForDescendants, observer,
-                UserHandle.getCallingUserId());
+                UserHandle.getCallingUserId(), Build.VERSION_CODES.CUR_DEVELOPMENT);
     }
 
     @Override
@@ -340,8 +350,8 @@
      */
     @Override
     public void notifyChange(Uri uri, IContentObserver observer,
-                             boolean observerWantsSelfNotifications, int flags,
-                             int userHandle) {
+            boolean observerWantsSelfNotifications, int flags, int userHandle,
+            int targetSdkVersion) {
         if (DEBUG) Slog.d(TAG, "Notifying update of " + uri + " for user " + userHandle
                 + " from observer " + observer + ", flags " + Integer.toHexString(flags));
 
@@ -359,8 +369,17 @@
         final String msg = LocalServices.getService(ActivityManagerInternal.class)
                 .checkContentProviderAccess(uri.getAuthority(), userHandle);
         if (msg != null) {
-            Log.w(TAG, "Ignoring notify for " + uri + " from " + uid + ": " + msg);
-            return;
+            if (targetSdkVersion >= Build.VERSION_CODES.O) {
+                throw new SecurityException(msg);
+            } else {
+                if (msg.startsWith("Failed to find provider")) {
+                    // Sigh, we need to quietly let apps targeting older API
+                    // levels notify on non-existent providers.
+                } else {
+                    Log.w(TAG, "Ignoring notify for " + uri + " from " + uid + ": " + msg);
+                    return;
+                }
+            }
         }
 
         // This makes it so that future permission checks will be in the context of this
@@ -427,7 +446,7 @@
                              boolean observerWantsSelfNotifications, boolean syncToNetwork) {
         notifyChange(uri, observer, observerWantsSelfNotifications,
                 syncToNetwork ? ContentResolver.NOTIFY_SYNC_TO_NETWORK : 0,
-                UserHandle.getCallingUserId());
+                UserHandle.getCallingUserId(), Build.VERSION_CODES.CUR_DEVELOPMENT);
     }
 
     /**
diff --git a/services/core/java/com/android/server/notification/BadgeExtractor.java b/services/core/java/com/android/server/notification/BadgeExtractor.java
index 4795fbf..e6edaf1 100644
--- a/services/core/java/com/android/server/notification/BadgeExtractor.java
+++ b/services/core/java/com/android/server/notification/BadgeExtractor.java
@@ -46,7 +46,9 @@
         if (!appCanShowBadge) {
             record.setShowBadge(false);
         } else {
-            record.setShowBadge(record.getChannel().canShowBadge() && appCanShowBadge);
+            record.setShowBadge(mConfig.getNotificationChannel(record.sbn.getPackageName(),
+                    record.sbn.getUid(), record.getChannel().getId(), false).canShowBadge()
+                    && appCanShowBadge);
         }
 
         return null;
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 8f4ad00..45ff20b 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2029,11 +2029,11 @@
          */
         @Override
         public void snoozeNotificationUntilFromListener(INotificationListener token, String key,
-                long snoozeUntil) {
+                long duration) {
             long identity = Binder.clearCallingIdentity();
             try {
                 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
-                snoozeNotificationInt(key, snoozeUntil, null, info);
+                snoozeNotificationInt(key, duration, null, info);
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
@@ -3409,7 +3409,7 @@
 
     @VisibleForTesting
     void scheduleTimeoutLocked(NotificationRecord record) {
-        if (record.getNotification().getTimeout() > System.currentTimeMillis()) {
+        if (record.getNotification().getTimeout() > 0) {
             final PendingIntent pi = PendingIntent.getBroadcast(getContext(),
                     REQUEST_CODE_TIMEOUT,
                     new Intent(ACTION_NOTIFICATION_TIMEOUT)
@@ -3418,8 +3418,8 @@
                             .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
                             .putExtra(EXTRA_KEY, record.getKey()),
                     PendingIntent.FLAG_UPDATE_CURRENT);
-            mAlarmManager.setExactAndAllowWhileIdle(
-                    AlarmManager.RTC_WAKEUP, record.getNotification().getTimeout(), pi);
+            mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+                    SystemClock.elapsedRealtime() + record.getNotification().getTimeout(), pi);
         }
     }
 
@@ -4185,16 +4185,16 @@
         }
     }
 
-    void snoozeNotificationInt(String key, long until, String snoozeCriterionId,
+    void snoozeNotificationInt(String key, long duration, String snoozeCriterionId,
             ManagedServiceInfo listener) {
         String listenerName = listener == null ? null : listener.component.toShortString();
-        if (until < System.currentTimeMillis() && snoozeCriterionId == null) {
+        if (duration <= 0 && snoozeCriterionId == null) {
             return;
         }
 
         if (DBG) {
-            Slog.d(TAG, String.format("snooze event(%s, %d, %s, %s)", key, until, snoozeCriterionId,
-                    listenerName));
+            Slog.d(TAG, String.format("snooze event(%s, %d, %s, %s)", key, duration,
+                    snoozeCriterionId, listenerName));
         }
         // Needs to post so that it can cancel notifications not yet enqueued.
         mHandler.post(new Runnable() {
@@ -4215,7 +4215,7 @@
                                     snoozeCriterionId);
                             mSnoozeHelper.snooze(r);
                         } else {
-                            mSnoozeHelper.snooze(r, until);
+                            mSnoozeHelper.snooze(r, duration);
                         }
                         savePolicyFile();
                     }
diff --git a/services/core/java/com/android/server/notification/SnoozeHelper.java b/services/core/java/com/android/server/notification/SnoozeHelper.java
index 0cd8cea..913f636 100644
--- a/services/core/java/com/android/server/notification/SnoozeHelper.java
+++ b/services/core/java/com/android/server/notification/SnoozeHelper.java
@@ -32,6 +32,7 @@
 import android.content.IntentFilter;
 import android.net.Uri;
 import android.os.Binder;
+import android.os.SystemClock;
 import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
 import android.util.ArrayMap;
@@ -125,9 +126,9 @@
     /**
      * Snoozes a notification and schedules an alarm to repost at that time.
      */
-    protected void snooze(NotificationRecord record, long until) {
+    protected void snooze(NotificationRecord record, long duration) {
         snooze(record);
-        scheduleRepost(record.sbn.getPackageName(), record.getKey(), record.getUserId(), until);
+        scheduleRepost(record.sbn.getPackageName(), record.getKey(), record.getUserId(), duration);
     }
 
     /**
@@ -291,13 +292,14 @@
                 PendingIntent.FLAG_UPDATE_CURRENT);
     }
 
-    private void scheduleRepost(String pkg, String key, int userId, long time) {
+    private void scheduleRepost(String pkg, String key, int userId, long duration) {
         long identity = Binder.clearCallingIdentity();
         try {
             final PendingIntent pi = createPendingIntent(pkg, key, userId);
             mAm.cancel(pi);
+            long time = SystemClock.elapsedRealtime() + duration;
             if (DEBUG) Slog.d(TAG, "Scheduling evaluate for " + new Date(time));
-            mAm.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, time, pi);
+            mAm.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, time, pi);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 53765f2..a7a1683 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -607,6 +607,12 @@
                     + "to use the PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS flag");
         }
 
+        if ((params.installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0
+                || (params.installFlags & PackageManager.INSTALL_EXTERNAL) != 0) {
+            throw new IllegalArgumentException(
+                    "New installs into ASEC containers no longer supported");
+        }
+
         // Defensively resize giant app icons
         if (params.appIcon != null) {
             final ActivityManager am = (ActivityManager) mContext.getSystemService(
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index fbf953f..6157f57 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -128,7 +128,6 @@
 import android.content.pm.AppsQueryHelper;
 import android.content.pm.ChangedPackages;
 import android.content.pm.ComponentInfo;
-import android.content.pm.InstantAppInfo;
 import android.content.pm.EphemeralRequest;
 import android.content.pm.EphemeralResolveInfo;
 import android.content.pm.AuxiliaryResolveInfo;
@@ -143,6 +142,7 @@
 import android.content.pm.IPackageManager;
 import android.content.pm.IPackageMoveObserver;
 import android.content.pm.IPackageStatsObserver;
+import android.content.pm.InstantAppInfo;
 import android.content.pm.InstrumentationInfo;
 import android.content.pm.IntentFilterVerificationInfo;
 import android.content.pm.KeySet;
@@ -204,15 +204,16 @@
 import android.os.UserManager;
 import android.os.UserManagerInternal;
 import android.os.storage.IStorageManager;
-import android.os.storage.StorageManagerInternal;
 import android.os.storage.StorageEventListener;
 import android.os.storage.StorageManager;
+import android.os.storage.StorageManagerInternal;
 import android.os.storage.VolumeInfo;
 import android.os.storage.VolumeRecord;
 import android.provider.Settings.Global;
 import android.provider.Settings.Secure;
 import android.security.KeyStore;
 import android.security.SystemKeyStore;
+import android.service.pm.PackageServiceDumpProto;
 import android.system.ErrnoException;
 import android.system.Os;
 import android.text.TextUtils;
@@ -235,6 +236,7 @@
 import android.util.SparseIntArray;
 import android.util.Xml;
 import android.util.jar.StrictJarFile;
+import android.util.proto.ProtoOutputStream;
 import android.view.Display;
 
 import com.android.internal.R;
@@ -316,8 +318,8 @@
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.Date;
-import java.util.HashSet;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -13068,6 +13070,12 @@
                     + "to use the PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS flag");
         }
 
+        if ((installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0
+                || (installFlags & PackageManager.INSTALL_EXTERNAL) != 0) {
+            throw new IllegalArgumentException(
+                    "New installs into ASEC containers no longer supported");
+        }
+
         final File originFile = new File(originPath);
         final OriginInfo origin = OriginInfo.fromUntrustedFile(originFile);
 
@@ -20299,6 +20307,9 @@
                 checkin = true;
             } else if ("-f".equals(opt)) {
                 dumpState.setOptionEnabled(DumpState.OPTION_SHOW_FILTERS);
+            } else if ("--proto".equals(opt)) {
+                dumpProto(fd);
+                return;
             } else {
                 pw.println("Unknown argument: " + opt + "; use -h for help");
             }
@@ -20836,6 +20847,98 @@
         }
     }
 
+    private void dumpProto(FileDescriptor fd) {
+        final ProtoOutputStream proto = new ProtoOutputStream(fd);
+
+        synchronized (mPackages) {
+            final long requiredVerifierPackageToken =
+                    proto.start(PackageServiceDumpProto.REQUIRED_VERIFIER_PACKAGE);
+            proto.write(PackageServiceDumpProto.PackageShortProto.NAME, mRequiredVerifierPackage);
+            proto.write(
+                    PackageServiceDumpProto.PackageShortProto.UID,
+                    getPackageUid(
+                            mRequiredVerifierPackage,
+                            MATCH_DEBUG_TRIAGED_MISSING,
+                            UserHandle.USER_SYSTEM));
+            proto.end(requiredVerifierPackageToken);
+
+            if (mIntentFilterVerifierComponent != null) {
+                String verifierPackageName = mIntentFilterVerifierComponent.getPackageName();
+                final long verifierPackageToken =
+                        proto.start(PackageServiceDumpProto.VERIFIER_PACKAGE);
+                proto.write(PackageServiceDumpProto.PackageShortProto.NAME, verifierPackageName);
+                proto.write(
+                        PackageServiceDumpProto.PackageShortProto.UID,
+                        getPackageUid(
+                                verifierPackageName,
+                                MATCH_DEBUG_TRIAGED_MISSING,
+                                UserHandle.USER_SYSTEM));
+                proto.end(verifierPackageToken);
+            }
+
+            dumpSharedLibrariesProto(proto);
+            dumpFeaturesProto(proto);
+            mSettings.dumpPackagesProto(proto);
+            mSettings.dumpSharedUsersProto(proto);
+            dumpMessagesProto(proto);
+        }
+        proto.flush();
+    }
+
+    private void dumpMessagesProto(ProtoOutputStream proto) {
+        BufferedReader in = null;
+        String line = null;
+        try {
+            in = new BufferedReader(new FileReader(getSettingsProblemFile()));
+            while ((line = in.readLine()) != null) {
+                if (line.contains("ignored: updated version")) continue;
+                proto.write(PackageServiceDumpProto.MESSAGES, line);
+            }
+        } catch (IOException ignored) {
+        } finally {
+            IoUtils.closeQuietly(in);
+        }
+    }
+
+    private void dumpFeaturesProto(ProtoOutputStream proto) {
+        synchronized (mAvailableFeatures) {
+            final int count = mAvailableFeatures.size();
+            for (int i = 0; i < count; i++) {
+                final FeatureInfo feat = mAvailableFeatures.valueAt(i);
+                final long featureToken = proto.start(PackageServiceDumpProto.FEATURES);
+                proto.write(PackageServiceDumpProto.FeatureProto.NAME, feat.name);
+                proto.write(PackageServiceDumpProto.FeatureProto.VERSION, feat.version);
+                proto.end(featureToken);
+            }
+        }
+    }
+
+    private void dumpSharedLibrariesProto(ProtoOutputStream proto) {
+        final int count = mSharedLibraries.size();
+        for (int i = 0; i < count; i++) {
+            final String libName = mSharedLibraries.keyAt(i);
+            SparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.get(libName);
+            if (versionedLib == null) {
+                continue;
+            }
+            final int versionCount = versionedLib.size();
+            for (int j = 0; j < versionCount; j++) {
+                final SharedLibraryEntry libEntry = versionedLib.valueAt(j);
+                final long sharedLibraryToken =
+                        proto.start(PackageServiceDumpProto.SHARED_LIBRARIES);
+                proto.write(PackageServiceDumpProto.SharedLibraryProto.NAME, libEntry.info.getName());
+                final boolean isJar = (libEntry.path != null);
+                proto.write(PackageServiceDumpProto.SharedLibraryProto.IS_JAR, isJar);
+                if (isJar) {
+                    proto.write(PackageServiceDumpProto.SharedLibraryProto.PATH, libEntry.path);
+                } else {
+                    proto.write(PackageServiceDumpProto.SharedLibraryProto.APK, libEntry.apk);
+                }
+                proto.end(sharedLibraryToken);
+            }
+        }
+    }
+
     private void dumpDexoptStateLPr(PrintWriter pw, String packageName) {
         final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ", 120);
         ipw.println();
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 5f348ab..b4bba88 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -19,6 +19,9 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageParser;
+import android.content.pm.UserInfo;
+import android.service.pm.PackageProto;
+import android.util.proto.ProtoOutputStream;
 
 import java.io.File;
 import java.util.List;
@@ -128,4 +131,32 @@
         }
         return true;
     }
+
+    public void writeToProto(ProtoOutputStream proto, long fieldId, List<UserInfo> users) {
+        final long packageToken = proto.start(fieldId);
+        proto.write(PackageProto.NAME, (realName != null ? realName : name));
+        proto.write(PackageProto.UID, appId);
+        proto.write(PackageProto.VERSION_CODE, versionCode);
+        proto.write(PackageProto.VERSION_STRING, pkg.mVersionName);
+        proto.write(PackageProto.INSTALL_TIME_MS, firstInstallTime);
+        proto.write(PackageProto.UPDATE_TIME_MS, lastUpdateTime);
+        proto.write(PackageProto.INSTALLER_NAME, installerPackageName);
+
+        if (pkg != null) {
+            long splitToken = proto.start(PackageProto.SPLITS);
+            proto.write(PackageProto.SplitProto.NAME, "base");
+            proto.write(PackageProto.SplitProto.REVISION_CODE, pkg.baseRevisionCode);
+            proto.end(splitToken);
+            if (pkg.splitNames != null) {
+                for (int i = 0; i < pkg.splitNames.length; i++) {
+                    splitToken = proto.start(PackageProto.SPLITS);
+                    proto.write(PackageProto.SplitProto.NAME, pkg.splitNames[i]);
+                    proto.write(PackageProto.SplitProto.REVISION_CODE, pkg.splitRevisionCodes[i]);
+                    proto.end(splitToken);
+                }
+            }
+        }
+        writeUsersInfoToProto(proto, PackageProto.USERS);
+        proto.end(packageToken);
+    }
 }
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 601377d6..b9c43da 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -25,8 +25,10 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageUserState;
 import android.os.storage.VolumeInfo;
+import android.service.pm.PackageProto;
 import android.util.ArraySet;
 import android.util.SparseArray;
+import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.VisibleForTesting;
 
@@ -564,4 +566,32 @@
         modifyUserState(userId).domainVerificationStatus =
                 PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
     }
+
+    protected void writeUsersInfoToProto(ProtoOutputStream proto, long fieldId) {
+        int count = userState.size();
+        for (int i = 0; i < count; i++) {
+            final long userToken = proto.start(fieldId);
+            final int userId = userState.keyAt(i);
+            final PackageUserState state = userState.valueAt(i);
+            proto.write(PackageProto.UserInfoProto.ID, userId);
+            final int installType;
+            if (state.instantApp) {
+                installType = PackageProto.UserInfoProto.INSTANT_APP_INSTALL;
+            } else if (state.installed) {
+                installType = PackageProto.UserInfoProto.FULL_APP_INSTALL;
+            } else {
+                installType = PackageProto.UserInfoProto.NOT_INSTALLED_FOR_USER;
+            }
+            proto.write(PackageProto.UserInfoProto.INSTALL_TYPE, installType);
+            proto.write(PackageProto.UserInfoProto.IS_HIDDEN, state.hidden);
+            proto.write(PackageProto.UserInfoProto.IS_SUSPENDED, state.suspended);
+            proto.write(PackageProto.UserInfoProto.IS_STOPPED, state.stopped);
+            proto.write(PackageProto.UserInfoProto.IS_LAUNCHED, !state.notLaunched);
+            proto.write(PackageProto.UserInfoProto.ENABLED_STATE, state.enabled);
+            proto.write(
+                    PackageProto.UserInfoProto.LAST_DISABLED_APP_CALLER,
+                    state.lastDisableAppCaller);
+            proto.end(userToken);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index a057e9b..570b31f 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -65,6 +65,7 @@
 import android.os.UserManager;
 import android.os.storage.StorageManager;
 import android.os.storage.VolumeInfo;
+import android.service.pm.PackageServiceDumpProto;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -77,6 +78,7 @@
 import android.util.SparseIntArray;
 import android.util.SparseLongArray;
 import android.util.Xml;
+import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.os.BackgroundThread;
@@ -887,9 +889,9 @@
         }
         if (p.appId < 0) {
             PackageManagerService.reportSettingsProblem(Log.WARN,
-                    "Package " + p.name + " could not be assigned a valid uid");
+                    "Package " + p.name + " could not be assigned a valid UID");
             throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
-                    "Creating application package " + p.name + " failed");
+                    "Package " + p.name + " could not be assigned a valid UID");
         }
     }
 
@@ -4876,6 +4878,16 @@
         }
     }
 
+    void dumpPackagesProto(ProtoOutputStream proto) {
+        List<UserInfo> users = getAllUsers(UserManagerService.getInstance());
+
+        final int count = mPackages.size();
+        for (int i = 0; i < count; i++) {
+            final PackageSetting ps = mPackages.valueAt(i);
+            ps.writeToProto(proto, PackageServiceDumpProto.PACKAGES, users);
+        }
+    }
+
     void dumpPermissionsLPr(PrintWriter pw, String packageName, ArraySet<String> permissionNames,
             DumpState dumpState) {
         boolean printedSomething = false;
@@ -4966,6 +4978,17 @@
         }
     }
 
+    void dumpSharedUsersProto(ProtoOutputStream proto) {
+        final int count = mSharedUsers.size();
+        for (int i = 0; i < count; i++) {
+            final SharedUserSetting su = mSharedUsers.valueAt(i);
+            final long sharedUserToken = proto.start(PackageServiceDumpProto.SHARED_USERS);
+            proto.write(PackageServiceDumpProto.SharedUserProto.USER_ID, su.userId);
+            proto.write(PackageServiceDumpProto.SharedUserProto.NAME, su.name);
+            proto.end(sharedUserToken);
+        }
+    }
+
     void dumpReadMessagesLPr(PrintWriter pw, DumpState dumpState) {
         pw.println("Settings parse messages:");
         pw.print(mReadMessages.toString());
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index b76a249..d3931fb 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -51,21 +51,23 @@
 import android.os.UserHandle;
 import android.os.WorkSource;
 import android.provider.Settings;
-import android.provider.Settings.Secure;
 import android.provider.Settings.SettingNotFoundException;
 import android.service.dreams.DreamManagerInternal;
+import android.service.power.PowerServiceDumpProto;
+import android.service.power.PowerServiceSettingsAndConfigurationDumpProto;
+import android.service.power.SuspendBlockerProto;
+import android.service.power.WakeLockProto;
 import android.service.vr.IVrManager;
 import android.service.vr.IVrStateCallbacks;
 import android.util.EventLog;
 import android.util.KeyValueListParser;
-import android.util.Log;
 import android.util.PrintWriterPrinter;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.TimeUtils;
+import android.util.proto.ProtoOutputStream;
 import android.view.Display;
 import android.view.WindowManagerPolicy;
-
 import com.android.internal.app.IAppOpsService;
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.os.BackgroundThread;
@@ -78,7 +80,7 @@
 import com.android.server.am.BatteryStatsService;
 import com.android.server.lights.Light;
 import com.android.server.lights.LightsManager;
-import com.android.server.vr.VrManagerService;
+
 import libcore.util.Objects;
 
 import java.io.FileDescriptor;
@@ -575,6 +577,13 @@
             pw.print("    "); pw.print(KEY_NO_CACHED_WAKE_LOCKS); pw.print("=");
             pw.println(NO_CACHED_WAKE_LOCKS);
         }
+
+        void dumpProto(ProtoOutputStream proto) {
+            final long constantsToken = proto.start(PowerServiceDumpProto.CONSTANTS);
+            proto.write(PowerServiceDumpProto.ConstantsProto.IS_NO_CACHED_WAKE_LOCKS,
+                    NO_CACHED_WAKE_LOCKS);
+            proto.end(constantsToken);
+        }
     }
 
     final Constants mConstants;
@@ -3244,6 +3253,354 @@
         }
     }
 
+    private void dumpProto(FileDescriptor fd) {
+        final WirelessChargerDetector wcd;
+        final ProtoOutputStream proto = new ProtoOutputStream(fd);
+
+        synchronized (mLock) {
+            mConstants.dumpProto(proto);
+            proto.write(PowerServiceDumpProto.DIRTY, mDirty);
+            proto.write(PowerServiceDumpProto.WAKEFULNESS, mWakefulness);
+            proto.write(PowerServiceDumpProto.IS_WAKEFULNESS_CHANGING, mWakefulnessChanging);
+            proto.write(PowerServiceDumpProto.IS_POWERED, mIsPowered);
+            proto.write(PowerServiceDumpProto.PLUG_TYPE, mPlugType);
+            proto.write(PowerServiceDumpProto.BATTERY_LEVEL, mBatteryLevel);
+            proto.write(
+                    PowerServiceDumpProto.BATTERY_LEVEL_WHEN_DREAM_STARTED,
+                    mBatteryLevelWhenDreamStarted);
+            proto.write(PowerServiceDumpProto.DOCK_STATE, mDockState);
+            proto.write(PowerServiceDumpProto.IS_STAY_ON, mStayOn);
+            proto.write(PowerServiceDumpProto.IS_PROXIMITY_POSITIVE, mProximityPositive);
+            proto.write(PowerServiceDumpProto.IS_BOOT_COMPLETED, mBootCompleted);
+            proto.write(PowerServiceDumpProto.IS_SYSTEM_READY, mSystemReady);
+            proto.write(
+                    PowerServiceDumpProto.IS_HAL_AUTO_SUSPEND_MODE_ENABLED,
+                    mHalAutoSuspendModeEnabled);
+            proto.write(
+                    PowerServiceDumpProto.IS_HAL_AUTO_INTERACTIVE_MODE_ENABLED,
+                    mHalInteractiveModeEnabled);
+
+            final long activeWakeLocksToken = proto.start(PowerServiceDumpProto.ACTIVE_WAKE_LOCKS);
+            proto.write(
+                    PowerServiceDumpProto.ActiveWakeLocksProto.IS_CPU,
+                    (mWakeLockSummary & WAKE_LOCK_CPU) != 0);
+            proto.write(
+                    PowerServiceDumpProto.ActiveWakeLocksProto.IS_SCREEN_BRIGHT,
+                    (mWakeLockSummary & WAKE_LOCK_SCREEN_BRIGHT) != 0);
+            proto.write(
+                    PowerServiceDumpProto.ActiveWakeLocksProto.IS_SCREEN_DIM,
+                    (mWakeLockSummary & WAKE_LOCK_SCREEN_DIM) != 0);
+            proto.write(
+                    PowerServiceDumpProto.ActiveWakeLocksProto.IS_BUTTON_BRIGHT,
+                    (mWakeLockSummary & WAKE_LOCK_BUTTON_BRIGHT) != 0);
+            proto.write(
+                    PowerServiceDumpProto.ActiveWakeLocksProto.IS_PROXIMITY_SCREEN_OFF,
+                    (mWakeLockSummary & WAKE_LOCK_PROXIMITY_SCREEN_OFF) != 0);
+            proto.write(
+                    PowerServiceDumpProto.ActiveWakeLocksProto.IS_STAY_AWAKE,
+                    (mWakeLockSummary & WAKE_LOCK_STAY_AWAKE) != 0);
+            proto.write(
+                    PowerServiceDumpProto.ActiveWakeLocksProto.IS_DOZE,
+                    (mWakeLockSummary & WAKE_LOCK_DOZE) != 0);
+            proto.write(
+                    PowerServiceDumpProto.ActiveWakeLocksProto.IS_DRAW,
+                    (mWakeLockSummary & WAKE_LOCK_DRAW) != 0);
+            proto.end(activeWakeLocksToken);
+
+            proto.write(PowerServiceDumpProto.NOTIFY_LONG_SCHEDULED_MS, mNotifyLongScheduled);
+            proto.write(PowerServiceDumpProto.NOTIFY_LONG_DISPATCHED_MS, mNotifyLongDispatched);
+            proto.write(PowerServiceDumpProto.NOTIFY_LONG_NEXT_CHECK_MS, mNotifyLongNextCheck);
+
+            final long userActivityToken = proto.start(PowerServiceDumpProto.USER_ACTIVITY);
+            proto.write(
+                    PowerServiceDumpProto.UserActivityProto.IS_SCREEN_BRIGHT,
+                    (mUserActivitySummary & USER_ACTIVITY_SCREEN_BRIGHT) != 0);
+            proto.write(
+                    PowerServiceDumpProto.UserActivityProto.IS_SCREEN_DIM,
+                    (mUserActivitySummary & USER_ACTIVITY_SCREEN_DIM) != 0);
+            proto.write(
+                    PowerServiceDumpProto.UserActivityProto.IS_SCREEN_DREAM,
+                    (mUserActivitySummary & USER_ACTIVITY_SCREEN_DREAM) != 0);
+            proto.end(userActivityToken);
+
+            proto.write(
+                    PowerServiceDumpProto.IS_REQUEST_WAIT_FOR_NEGATIVE_PROXIMITY,
+                    mRequestWaitForNegativeProximity);
+            proto.write(PowerServiceDumpProto.IS_SANDMAN_SCHEDULED, mSandmanScheduled);
+            proto.write(PowerServiceDumpProto.IS_SANDMAN_SUMMONED, mSandmanSummoned);
+            proto.write(PowerServiceDumpProto.IS_LOW_POWER_MODE_ENABLED, mLowPowerModeEnabled);
+            proto.write(PowerServiceDumpProto.IS_BATTERY_LEVEL_LOW, mBatteryLevelLow);
+            proto.write(PowerServiceDumpProto.IS_LIGHT_DEVICE_IDLE_MODE, mLightDeviceIdleMode);
+            proto.write(PowerServiceDumpProto.IS_DEVICE_IDLE_MODE, mDeviceIdleMode);
+
+            for (int id : mDeviceIdleWhitelist) {
+                proto.write(PowerServiceDumpProto.DEVICE_IDLE_WHITELIST, id);
+            }
+            for (int id : mDeviceIdleTempWhitelist) {
+                proto.write(PowerServiceDumpProto.DEVICE_IDLE_TEMP_WHITELIST, id);
+            }
+
+            proto.write(PowerServiceDumpProto.LAST_WAKE_TIME_MS, mLastWakeTime);
+            proto.write(PowerServiceDumpProto.LAST_SLEEP_TIME_MS, mLastSleepTime);
+            proto.write(PowerServiceDumpProto.LAST_USER_ACTIVITY_TIME_MS, mLastUserActivityTime);
+            proto.write(
+                    PowerServiceDumpProto.LAST_USER_ACTIVITY_TIME_NO_CHANGE_LIGHTS_MS,
+                    mLastUserActivityTimeNoChangeLights);
+            proto.write(
+                    PowerServiceDumpProto.LAST_INTERACTIVE_POWER_HINT_TIME_MS,
+                    mLastInteractivePowerHintTime);
+            proto.write(
+                    PowerServiceDumpProto.LAST_SCREEN_BRIGHTNESS_BOOST_TIME_MS,
+                    mLastScreenBrightnessBoostTime);
+            proto.write(
+                    PowerServiceDumpProto.IS_SCREEN_BRIGHTNESS_BOOST_IN_PROGRESS,
+                    mScreenBrightnessBoostInProgress);
+            proto.write(PowerServiceDumpProto.IS_DISPLAY_READY, mDisplayReady);
+            proto.write(
+                    PowerServiceDumpProto.IS_HOLDING_WAKE_LOCK_SUSPEND_BLOCKER,
+                    mHoldingWakeLockSuspendBlocker);
+            proto.write(
+                    PowerServiceDumpProto.IS_HOLDING_DISPLAY_SUSPEND_BLOCKER,
+                    mHoldingDisplaySuspendBlocker);
+
+            final long settingsAndConfigurationToken =
+                    proto.start(PowerServiceDumpProto.SETTINGS_AND_CONFIGURATION);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto
+                            .IS_DECOUPLE_HAL_AUTO_SUSPEND_MODE_FROM_DISPLAY_CONFIG,
+                    mDecoupleHalAutoSuspendModeFromDisplayConfig);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto
+                            .IS_DECOUPLE_HAL_INTERACTIVE_MODE_FROM_DISPLAY_CONFIG,
+                    mDecoupleHalInteractiveModeFromDisplayConfig);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto
+                            .IS_WAKE_UP_WHEN_PLUGGED_OR_UNPLUGGED_CONFIG,
+                    mWakeUpWhenPluggedOrUnpluggedConfig);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto
+                            .IS_WAKE_UP_WHEN_PLUGGED_OR_UNPLUGGED_IN_THEATER_MODE_CONFIG,
+                    mWakeUpWhenPluggedOrUnpluggedInTheaterModeConfig);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto.IS_THEATER_MODE_ENABLED,
+                    mTheaterModeEnabled);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto
+                            .IS_SUSPEND_WHEN_SCREEN_OFF_DUE_TO_PROXIMITY_CONFIG,
+                    mSuspendWhenScreenOffDueToProximityConfig);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto.ARE_DREAMS_SUPPORTED_CONFIG,
+                    mDreamsSupportedConfig);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto
+                            .ARE_DREAMS_ENABLED_BY_DEFAULT_CONFIG,
+                    mDreamsEnabledByDefaultConfig);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto
+                            .ARE_DREAMS_ACTIVATED_ON_SLEEP_BY_DEFAULT_CONFIG,
+                    mDreamsActivatedOnSleepByDefaultConfig);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto
+                            .ARE_DREAMS_ACTIVATED_ON_DOCK_BY_DEFAULT_CONFIG,
+                    mDreamsActivatedOnDockByDefaultConfig);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto
+                            .ARE_DREAMS_ENABLED_ON_BATTERY_CONFIG,
+                    mDreamsEnabledOnBatteryConfig);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto
+                            .DREAMS_BATTERY_LEVEL_MINIMUM_WHEN_POWERED_CONFIG,
+                    mDreamsBatteryLevelMinimumWhenPoweredConfig);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto
+                            .DREAMS_BATTERY_LEVEL_MINIMUM_WHEN_NOT_POWERED_CONFIG,
+                    mDreamsBatteryLevelMinimumWhenNotPoweredConfig);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto
+                            .DREAMS_BATTERY_LEVEL_DRAIN_CUTOFF_CONFIG,
+                    mDreamsBatteryLevelDrainCutoffConfig);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto.ARE_DREAMS_ENABLED_SETTING,
+                    mDreamsEnabledSetting);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto
+                            .ARE_DREAMS_ACTIVATE_ON_SLEEP_SETTING,
+                    mDreamsActivateOnSleepSetting);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto
+                            .ARE_DREAMS_ACTIVATE_ON_DOCK_SETTING,
+                    mDreamsActivateOnDockSetting);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto.IS_DOZE_AFTER_SCREEN_OFF_CONFIG,
+                    mDozeAfterScreenOffConfig);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto.IS_LOW_POWER_MODE_SETTING,
+                    mLowPowerModeSetting);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto.IS_AUTO_LOW_POWER_MODE_CONFIGURED,
+                    mAutoLowPowerModeConfigured);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto.IS_AUTO_LOW_POWER_MODE_SNOOZING,
+                    mAutoLowPowerModeSnoozing);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto
+                            .MINIMUM_SCREEN_OFF_TIMEOUT_CONFIG_MS,
+                    mMinimumScreenOffTimeoutConfig);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto
+                            .MAXIMUM_SCREEN_DIM_DURATION_CONFIG_MS,
+                    mMaximumScreenDimDurationConfig);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto.MAXIMUM_SCREEN_DIM_RATIO_CONFIG,
+                    mMaximumScreenDimRatioConfig);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto.SCREEN_OFF_TIMEOUT_SETTING_MS,
+                    mScreenOffTimeoutSetting);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto.SLEEP_TIMEOUT_SETTING_MS,
+                    mSleepTimeoutSetting);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto
+                            .MAXIMUM_SCREEN_OFF_TIMEOUT_FROM_DEVICE_ADMIN_MS,
+                    mMaximumScreenOffTimeoutFromDeviceAdmin);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto
+                            .IS_MAXIMUM_SCREEN_OFF_TIMEOUT_FROM_DEVICE_ADMIN_ENFORCED_LOCKED,
+                    isMaximumScreenOffTimeoutFromDeviceAdminEnforcedLocked());
+
+            final long stayOnWhilePluggedInToken =
+                    proto.start(
+                            PowerServiceSettingsAndConfigurationDumpProto.STAY_ON_WHILE_PLUGGED_IN);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto.StayOnWhilePluggedInProto
+                            .IS_STAY_ON_WHILE_PLUGGED_IN_AC,
+                    ((mStayOnWhilePluggedInSetting & BatteryManager.BATTERY_PLUGGED_AC) != 0));
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto.StayOnWhilePluggedInProto
+                            .IS_STAY_ON_WHILE_PLUGGED_IN_USB,
+                    ((mStayOnWhilePluggedInSetting & BatteryManager.BATTERY_PLUGGED_USB) != 0));
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto.StayOnWhilePluggedInProto
+                            .IS_STAY_ON_WHILE_PLUGGED_IN_WIRELESS,
+                    ((mStayOnWhilePluggedInSetting & BatteryManager.BATTERY_PLUGGED_WIRELESS)
+                            != 0));
+            proto.end(stayOnWhilePluggedInToken);
+
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto.SCREEN_BRIGHTNESS_SETTING,
+                    mScreenBrightnessSetting);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto
+                            .SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT_SETTING,
+                    mScreenAutoBrightnessAdjustmentSetting);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto.SCREEN_BRIGHTNESS_MODE_SETTING,
+                    mScreenBrightnessModeSetting);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto
+                            .SCREEN_BRIGHTNESS_OVERRIDE_FROM_WINDOW_MANAGER,
+                    mScreenBrightnessOverrideFromWindowManager);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto
+                            .USER_ACTIVITY_TIMEOUT_OVERRIDE_FROM_WINDOW_MANAGER_MS,
+                    mUserActivityTimeoutOverrideFromWindowManager);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto
+                            .IS_USER_INACTIVE_OVERRIDE_FROM_WINDOW_MANAGER,
+                    mUserInactiveOverrideFromWindowManager);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto
+                            .TEMPORARY_SCREEN_BRIGHTNESS_SETTING_OVERRIDE,
+                    mTemporaryScreenBrightnessSettingOverride);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto
+                            .TEMPORARY_SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT_SETTING_OVERRIDE,
+                    mTemporaryScreenAutoBrightnessAdjustmentSettingOverride);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto
+                            .DOZE_SCREEN_STATE_OVERRIDE_FROM_DREAM_MANAGER,
+                    mDozeScreenStateOverrideFromDreamManager);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto
+                            .DOZED_SCREEN_BRIGHTNESS_OVERRIDE_FROM_DREAM_MANAGER,
+                    mDozeScreenBrightnessOverrideFromDreamManager);
+
+            final long screenBrightnessSettingLimitsToken =
+                    proto.start(
+                            PowerServiceSettingsAndConfigurationDumpProto
+                                    .SCREEN_BRIGHTNESS_SETTING_LIMITS);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto.ScreenBrightnessSettingLimitsProto
+                            .SETTING_MINIMUM,
+                    mScreenBrightnessSettingMinimum);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto.ScreenBrightnessSettingLimitsProto
+                            .SETTING_MAXIMUM,
+                    mScreenBrightnessSettingMaximum);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto.ScreenBrightnessSettingLimitsProto
+                            .SETTING_DEFAULT,
+                    mScreenBrightnessSettingDefault);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto.ScreenBrightnessSettingLimitsProto
+                            .SETTING_FOR_VR_DEFAULT,
+                    mScreenBrightnessForVrSettingDefault);
+            proto.end(screenBrightnessSettingLimitsToken);
+
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto.SCREEN_BRIGHTNESS_FOR_VR_SETTING,
+                    mScreenBrightnessForVrSetting);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto.IS_DOUBLE_TAP_WAKE_ENABLED,
+                    mDoubleTapWakeEnabled);
+            proto.write(
+                    PowerServiceSettingsAndConfigurationDumpProto.IS_VR_MODE_ENABLED,
+                    mIsVrModeEnabled);
+            proto.end(settingsAndConfigurationToken);
+
+            final int sleepTimeout = getSleepTimeoutLocked();
+            final int screenOffTimeout = getScreenOffTimeoutLocked(sleepTimeout);
+            final int screenDimDuration = getScreenDimDurationLocked(screenOffTimeout);
+            proto.write(PowerServiceDumpProto.SLEEP_TIMEOUT_MS, sleepTimeout);
+            proto.write(PowerServiceDumpProto.SCREEN_OFF_TIMEOUT_MS, screenOffTimeout);
+            proto.write(PowerServiceDumpProto.SCREEN_DIM_DURATION_MS, screenDimDuration);
+            proto.write(PowerServiceDumpProto.ARE_UIDS_CHANGING, mUidsChanging);
+            proto.write(PowerServiceDumpProto.ARE_UIDS_CHANGED, mUidsChanged);
+
+            for (int i = 0; i < mUidState.size(); i++) {
+                final UidState state = mUidState.valueAt(i);
+                final long uIDToken = proto.start(PowerServiceDumpProto.UIDS);
+                final int uid = mUidState.keyAt(i);
+                proto.write(PowerServiceDumpProto.UidProto.UID, uid);
+                proto.write(PowerServiceDumpProto.UidProto.UID_STRING, UserHandle.formatUid(uid));
+                proto.write(PowerServiceDumpProto.UidProto.IS_ACTIVE, state.mActive);
+                proto.write(PowerServiceDumpProto.UidProto.NUM_WAKE_LOCKS, state.mNumWakeLocks);
+                if (state.mProcState == ActivityManager.PROCESS_STATE_UNKNOWN) {
+                    proto.write(PowerServiceDumpProto.UidProto.IS_PROCESS_STATE_UNKNOWN, true);
+                } else {
+                    proto.write(PowerServiceDumpProto.UidProto.PROCESS_STATE, state.mProcState);
+                }
+                proto.end(uIDToken);
+            }
+
+            mHandler.getLooper().writeToProto(proto, PowerServiceDumpProto.LOOPER);
+
+            for (WakeLock wl : mWakeLocks) {
+                wl.writeToProto(proto, PowerServiceDumpProto.WAKE_LOCKS);
+            }
+
+            for (SuspendBlocker sb : mSuspendBlockers) {
+                sb.writeToProto(proto, PowerServiceDumpProto.SUSPEND_BLOCKERS);
+            }
+            wcd = mWirelessChargerDetector;
+        }
+
+        if (wcd != null) {
+            wcd.writeToProto(proto, PowerServiceDumpProto.WIRELESS_CHARGER_DETECTOR);
+        }
+        proto.flush();
+    }
+
     private SuspendBlocker createSuspendBlockerLocked(String name) {
         SuspendBlocker suspendBlocker = new SuspendBlockerImpl(name);
         mSuspendBlockers.add(suspendBlocker);
@@ -3471,6 +3828,32 @@
             return sb.toString();
         }
 
+        public void writeToProto(ProtoOutputStream proto, long fieldId) {
+            final long wakeLockToken = proto.start(fieldId);
+            proto.write(WakeLockProto.LOCK_LEVEL, (mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK));
+            proto.write(WakeLockProto.TAG, mTag);
+
+            final long wakeLockFlagsToken = proto.start(WakeLockProto.FLAGS);
+            proto.write(WakeLockProto.WakeLockFlagsProto.IS_ACQUIRE_CAUSES_WAKEUP,
+                    (mFlags & PowerManager.ACQUIRE_CAUSES_WAKEUP)!=0);
+            proto.write(WakeLockProto.WakeLockFlagsProto.IS_ON_AFTER_RELEASE,
+                    (mFlags & PowerManager.ON_AFTER_RELEASE)!=0);
+            proto.end(wakeLockFlagsToken);
+
+            proto.write(WakeLockProto.IS_DISABLED, mDisabled);
+            if (mNotifiedAcquired) {
+                proto.write(WakeLockProto.ACQ_MS, mAcquireTime);
+            }
+            proto.write(WakeLockProto.IS_NOTIFIED_LONG, mNotifiedLong);
+            proto.write(WakeLockProto.UID, mOwnerUid);
+            proto.write(WakeLockProto.PID, mOwnerPid);
+
+            if (mWorkSource != null) {
+                mWorkSource.writeToProto(proto, WakeLockProto.WORK_SOURCE);
+            }
+            proto.end(wakeLockToken);
+        }
+
         @SuppressWarnings("deprecation")
         private String getLockLevelString() {
             switch (mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
@@ -3568,6 +3951,15 @@
                 return mName + ": ref count=" + mReferenceCount;
             }
         }
+
+        public void writeToProto(ProtoOutputStream proto, long fieldId) {
+            final long sbToken = proto.start(fieldId);
+            synchronized (this) {
+                proto.write(SuspendBlockerProto.NAME, mName);
+                proto.write(SuspendBlockerProto.REFERENCE_COUNT, mReferenceCount);
+            }
+            proto.end(sbToken);
+        }
     }
 
     static final class UidState {
@@ -4055,8 +4447,19 @@
             }
 
             final long ident = Binder.clearCallingIdentity();
+
+            boolean isDumpProto = false;
+            for (String arg : args) {
+                if (arg.equals("--proto")) {
+                    isDumpProto = true;
+                }
+            }
             try {
-                dumpInternal(pw);
+                if (isDumpProto) {
+                    dumpProto(fd);
+                } else {
+                    dumpInternal(pw);
+                }
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
diff --git a/services/core/java/com/android/server/power/SuspendBlocker.java b/services/core/java/com/android/server/power/SuspendBlocker.java
index 70b278a..30b35f0 100644
--- a/services/core/java/com/android/server/power/SuspendBlocker.java
+++ b/services/core/java/com/android/server/power/SuspendBlocker.java
@@ -16,6 +16,8 @@
 
 package com.android.server.power;
 
+import android.util.proto.ProtoOutputStream;
+
 /**
  * Low-level suspend blocker mechanism equivalent to holding a partial wake lock.
  *
@@ -40,4 +42,6 @@
      * The system may crash.
      */
     void release();
+
+    void writeToProto(ProtoOutputStream proto, long fieldId);
 }
diff --git a/services/core/java/com/android/server/power/WirelessChargerDetector.java b/services/core/java/com/android/server/power/WirelessChargerDetector.java
index 38f5d77..6ee9dcd 100644
--- a/services/core/java/com/android/server/power/WirelessChargerDetector.java
+++ b/services/core/java/com/android/server/power/WirelessChargerDetector.java
@@ -24,8 +24,10 @@
 import android.os.Handler;
 import android.os.Message;
 import android.os.SystemClock;
+import android.service.power.WirelessChargerDetectorProto;
 import android.util.Slog;
 import android.util.TimeUtils;
+import android.util.proto.ProtoOutputStream;
 
 import java.io.PrintWriter;
 
@@ -170,6 +172,44 @@
         }
     }
 
+    public void writeToProto(ProtoOutputStream proto, long fieldId) {
+        final long wcdToken = proto.start(fieldId);
+        synchronized (mLock) {
+            proto.write(WirelessChargerDetectorProto.IS_POWERED_WIRELESSLY, mPoweredWirelessly);
+            proto.write(WirelessChargerDetectorProto.IS_AT_REST, mAtRest);
+
+            final long restVectorToken = proto.start(WirelessChargerDetectorProto.REST);
+            proto.write(WirelessChargerDetectorProto.VectorProto.X, mRestX);
+            proto.write(WirelessChargerDetectorProto.VectorProto.Y, mRestY);
+            proto.write(WirelessChargerDetectorProto.VectorProto.Z, mRestZ);
+            proto.end(restVectorToken);
+
+            proto.write(
+                    WirelessChargerDetectorProto.IS_DETECTION_IN_PROGRESS, mDetectionInProgress);
+            proto.write(WirelessChargerDetectorProto.DETECTION_START_TIME_MS, mDetectionStartTime);
+            proto.write(
+                    WirelessChargerDetectorProto.IS_MUST_UPDATE_REST_POSITION,
+                    mMustUpdateRestPosition);
+            proto.write(WirelessChargerDetectorProto.TOTAL_SAMPLES, mTotalSamples);
+            proto.write(WirelessChargerDetectorProto.MOVING_SAMPLES, mMovingSamples);
+
+            final long firstSampleVectorToken =
+                    proto.start(WirelessChargerDetectorProto.FIRST_SAMPLE);
+            proto.write(WirelessChargerDetectorProto.VectorProto.X, mFirstSampleX);
+            proto.write(WirelessChargerDetectorProto.VectorProto.Y, mFirstSampleY);
+            proto.write(WirelessChargerDetectorProto.VectorProto.Z, mFirstSampleZ);
+            proto.end(firstSampleVectorToken);
+
+            final long lastSampleVectorToken =
+                    proto.start(WirelessChargerDetectorProto.LAST_SAMPLE);
+            proto.write(WirelessChargerDetectorProto.VectorProto.X, mLastSampleX);
+            proto.write(WirelessChargerDetectorProto.VectorProto.Y, mLastSampleY);
+            proto.write(WirelessChargerDetectorProto.VectorProto.Z, mLastSampleZ);
+            proto.end(lastSampleVectorToken);
+        }
+        proto.end(wcdToken);
+    }
+
     /**
      * Updates the charging state and returns true if docking was detected.
      *
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index 2b74f84..5041138 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -19,6 +19,7 @@
 import static android.app.ActivityManager.ENABLE_TASK_SNAPSHOTS;
 
 import android.annotation.Nullable;
+import android.app.ActivityManager;
 import android.app.ActivityManager.StackId;
 import android.app.ActivityManager.TaskSnapshot;
 import android.graphics.GraphicBuffer;
@@ -65,26 +66,22 @@
     }
 
     void onTransitionStarting() {
-        if (!ENABLE_TASK_SNAPSHOTS) {
-            return;
-        }
         handleClosingApps(mService.mClosingApps);
     }
 
-
     /**
      * Called when the visibility of an app changes outside of the regular app transition flow.
      */
     void notifyAppVisibilityChanged(AppWindowToken appWindowToken, boolean visible) {
-        if (!ENABLE_TASK_SNAPSHOTS) {
-            return;
-        }
         if (!visible) {
             handleClosingApps(Sets.newArraySet(appWindowToken));
         }
     }
 
     private void handleClosingApps(ArraySet<AppWindowToken> closingApps) {
+        if (!ENABLE_TASK_SNAPSHOTS || ActivityManager.isLowRamDeviceStatic()) {
+            return;
+        }
 
         // We need to take a snapshot of the task if and only if all activities of the task are
         // either closing or hidden.
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index 4c89705..20b70a6 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -1036,7 +1036,7 @@
     }
 
     // TODO(b/31632518)
-    gnssHal = IGnss::getService("gnss");
+    gnssHal = IGnss::getService();
     if (gnssHal != nullptr) {
         auto gnssXtra = gnssHal->getExtensionXtra();
         if (!gnssXtra.isOk()) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 620d441..7b6b941 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -41,6 +41,7 @@
 import static android.app.admin.DevicePolicyManager.DELEGATION_PACKAGE_ACCESS;
 import static android.app.admin.DevicePolicyManager.DELEGATION_PERMISSION_GRANT;
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
+import static android.app.admin.DevicePolicyManager.PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER;
 import static android.app.admin.DevicePolicyManager.WIPE_EXTERNAL_STORAGE;
 import static android.app.admin.DevicePolicyManager.WIPE_RESET_PROTECTION_DATA;
 import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
@@ -332,15 +333,6 @@
     }
 
     /**
-     * Keyguard features that when set on a managed profile that doesn't have its own challenge will
-     * affect the profile's parent user. These can also be set on the managed profile's parent DPM
-     * instance.
-     */
-    private static final int PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER =
-            DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS
-            | DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT;
-
-    /**
      * Keyguard features that when set on a profile affect the profile content or challenge only.
      * These cannot be set on the managed profile's parent DPM instance
      */
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 b26bac3..0cf4994 100644
--- a/services/tests/notification/src/com/android/server/notification/BadgeExtractorTest.java
+++ b/services/tests/notification/src/com/android/server/notification/BadgeExtractorTest.java
@@ -89,6 +89,7 @@
         when(mConfig.canShowBadge(mPkg, mUid)).thenReturn(true);
         NotificationChannel channel =
                 new NotificationChannel("a", "a", NotificationManager.IMPORTANCE_UNSPECIFIED);
+        when(mConfig.getNotificationChannel(mPkg, mUid, "a", false)).thenReturn(channel);
         channel.setShowBadge(false);
 
         NotificationRecord r = getNotificationRecord(channel);
@@ -107,6 +108,7 @@
         NotificationChannel channel =
                 new NotificationChannel("a", "a", NotificationManager.IMPORTANCE_HIGH);
         channel.setShowBadge(true);
+        when(mConfig.getNotificationChannel(mPkg, mUid, "a", false)).thenReturn(channel);
 
         NotificationRecord r = getNotificationRecord(channel);
 
@@ -124,6 +126,7 @@
         NotificationChannel channel =
                 new NotificationChannel("a", "a", NotificationManager.IMPORTANCE_UNSPECIFIED);
         channel.setShowBadge(true);
+        when(mConfig.getNotificationChannel(mPkg, mUid, "a", false)).thenReturn(channel);
 
         NotificationRecord r = getNotificationRecord(channel);
 
@@ -141,6 +144,7 @@
         NotificationChannel channel =
                 new NotificationChannel("a", "a", NotificationManager.IMPORTANCE_UNSPECIFIED);
         channel.setShowBadge(false);
+        when(mConfig.getNotificationChannel(mPkg, mUid, "a", false)).thenReturn(channel);
 
         NotificationRecord r = getNotificationRecord(channel);
 
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 69724f4..c5abba8 100644
--- a/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java
@@ -18,6 +18,7 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
@@ -27,6 +28,7 @@
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.content.Context;
+import android.os.SystemClock;
 import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
 import android.support.test.InstrumentationRegistry;
@@ -71,8 +73,11 @@
     public void testSnoozeForTime() throws Exception {
         NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
         mSnoozeHelper.snooze(r, 1000);
+        ArgumentCaptor<Long> captor = ArgumentCaptor.forClass(Long.class);
         verify(mAm, times(1)).setExactAndAllowWhileIdle(
-                anyInt(), eq((long) 1000), any(PendingIntent.class));
+                anyInt(), captor.capture(), any(PendingIntent.class));
+        long actualSnoozedUntilDuration = captor.getValue() - SystemClock.elapsedRealtime();
+        assertTrue(Math.abs(actualSnoozedUntilDuration - 1000) < 2);
         assertTrue(mSnoozeHelper.isSnoozed(
                 UserHandle.USER_SYSTEM, r.sbn.getPackageName(), r.getKey()));
     }
diff --git a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
index 665f01f..4141f2f 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
@@ -56,8 +56,7 @@
 import android.net.INetworkScoreCache;
 import android.net.NetworkKey;
 import android.net.NetworkScoreManager;
-import android.net.NetworkScorerAppManager;
-import android.net.NetworkScorerAppManager.NetworkScorerAppData;
+import android.net.NetworkScorerAppData;
 import android.net.RecommendationRequest;
 import android.net.RecommendationResult;
 import android.net.ScoredNetwork;
@@ -201,10 +200,10 @@
     }
 
     @Test
-    public void testSystemRunning() {
+    public void testOnUserUnlocked() {
         when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(NEW_SCORER);
 
-        mNetworkScoreService.systemRunning();
+        mNetworkScoreService.onUserUnlocked(0);
 
         verify(mContext).bindServiceAsUser(MockUtils.checkIntent(
                 new Intent(NetworkScoreManager.ACTION_RECOMMEND_NETWORKS)
@@ -549,9 +548,9 @@
     }
 
     @Test
-    public void testSetActiveScorer_noScoreNetworksPermission() {
-        doThrow(new SecurityException()).when(mContext)
-                .enforceCallingOrSelfPermission(eq(permission.SCORE_NETWORKS), anyString());
+    public void testSetActiveScorer_noRequestNetworkScoresPermission() {
+        when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
+                .thenReturn(PackageManager.PERMISSION_DENIED);
 
         try {
             mNetworkScoreService.setActiveScorer(null);
@@ -630,7 +629,7 @@
 
     @Test
     public void testIsCallerActiveScorer_noBoundService() throws Exception {
-        mNetworkScoreService.systemRunning();
+        mNetworkScoreService.onUserUnlocked(0);
 
         assertFalse(mNetworkScoreService.isCallerActiveScorer(Binder.getCallingUid()));
     }
@@ -651,7 +650,7 @@
 
     @Test
     public void testGetActiveScorerPackage_notActive() throws Exception {
-        mNetworkScoreService.systemRunning();
+        mNetworkScoreService.onUserUnlocked(0);
 
         assertNull(mNetworkScoreService.getActiveScorerPackage());
     }
@@ -659,7 +658,7 @@
     @Test
     public void testGetActiveScorerPackage_active() throws Exception {
         when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(NEW_SCORER);
-        mNetworkScoreService.systemRunning();
+        mNetworkScoreService.onUserUnlocked(0);
 
         assertEquals(NEW_SCORER.getRecommendationServicePackageName(),
                 mNetworkScoreService.getActiveScorerPackage());
@@ -960,7 +959,7 @@
                 return true;
             }
         });
-        mNetworkScoreService.systemRunning();
+        mNetworkScoreService.onUserUnlocked(0);
     }
 
     private void bindToScorer(boolean callerIsScorer) {
@@ -974,7 +973,7 @@
         when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(appData);
         when(mContext.bindServiceAsUser(isA(Intent.class), isA(ServiceConnection.class), anyInt(),
                 isA(UserHandle.class))).thenReturn(true);
-        mNetworkScoreService.systemRunning();
+        mNetworkScoreService.onUserUnlocked(0);
     }
 
     private static class OnResultListener implements RemoteCallback.OnResultListener {
diff --git a/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java b/services/tests/servicestests/src/com/android/server/NetworkScorerAppManagerTest.java
similarity index 61%
rename from core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java
rename to services/tests/servicestests/src/com/android/server/NetworkScorerAppManagerTest.java
index 347024d..e9a2d34 100644
--- a/core/tests/coretests/src/android/net/NetworkScorerAppManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkScorerAppManagerTest.java
@@ -14,13 +14,22 @@
  * limitations under the License
  */
 
-package android.net;
+package com.android.server;
 
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.assertTrue;
+
+import static org.junit.Assert.assertFalse;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.Manifest.permission;
 import android.content.ComponentName;
-import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
@@ -29,144 +38,84 @@
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.content.res.Resources;
-import android.net.NetworkScorerAppManager.NetworkScorerAppData;
+import android.net.NetworkScoreManager;
+import android.net.NetworkScorerAppData;
 import android.os.Bundle;
 import android.provider.Settings;
-import android.test.InstrumentationTestCase;
+import android.support.test.runner.AndroidJUnit4;
 
 import com.android.internal.R;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.ArgumentMatcher;
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
+import java.util.ArrayList;
 import java.util.List;
 
-public class NetworkScorerAppManagerTest extends InstrumentationTestCase {
+@RunWith(AndroidJUnit4.class)
+public class NetworkScorerAppManagerTest {
     @Mock private Context mMockContext;
     @Mock private PackageManager mMockPm;
     @Mock private Resources mResources;
-    @Mock private ContentResolver mContentResolver;
-    private Context mTargetContext;
+    @Mock private NetworkScorerAppManager.SettingsFacade mSettingsFacade;
     private NetworkScorerAppManager mNetworkScorerAppManager;
+    private List<ResolveInfo> mAvailableServices;
 
-    @Override
+    @Before
     public void setUp() throws Exception {
-        super.setUp();
-
-        // Configuration needed to make mockito/dexcache work.
-        mTargetContext = getInstrumentation().getTargetContext();
-        System.setProperty("dexmaker.dexcache", mTargetContext.getCacheDir().getPath());
-        ClassLoader newClassLoader = getInstrumentation().getClass().getClassLoader();
-        Thread.currentThread().setContextClassLoader(newClassLoader);
-
         MockitoAnnotations.initMocks(this);
+        mAvailableServices = new ArrayList<>();
         when(mMockContext.getPackageManager()).thenReturn(mMockPm);
+        when(mMockPm.queryIntentServices(Mockito.argThat(new ArgumentMatcher<Intent>() {
+            @Override
+            public boolean matches(Object object) {
+                Intent intent = (Intent) object;
+                return NetworkScoreManager.ACTION_RECOMMEND_NETWORKS.equals(intent.getAction());
+            }
+        }), eq(PackageManager.GET_META_DATA))).thenReturn(mAvailableServices);
         when(mMockContext.getResources()).thenReturn(mResources);
-        when(mMockContext.getContentResolver()).thenReturn(mTargetContext.getContentResolver());
-        mNetworkScorerAppManager = new NetworkScorerAppManager(mMockContext);
+
+        mNetworkScorerAppManager = new NetworkScorerAppManager(mMockContext, mSettingsFacade);
     }
 
-    public void testGetPotentialRecommendationProviderPackages_emptyConfig() throws Exception {
-        setNetworkRecommendationPackageNames(/*no configured packages*/);
-        assertTrue(mNetworkScorerAppManager.getPotentialRecommendationProviderPackages().isEmpty());
-    }
-
-    public void testGetPotentialRecommendationProviderPackages_permissionNotGranted()
-            throws Exception {
-        setNetworkRecommendationPackageNames("package1");
-        mockScoreNetworksDenied("package1");
-
-        assertTrue(mNetworkScorerAppManager.getPotentialRecommendationProviderPackages().isEmpty());
-    }
-
-    public void testGetPotentialRecommendationProviderPackages_permissionGranted()
-            throws Exception {
-        setNetworkRecommendationPackageNames("package1");
-        mockScoreNetworksGranted("package1");
-
-        List<String> potentialProviderPackages =
-                mNetworkScorerAppManager.getPotentialRecommendationProviderPackages();
-
-        assertFalse(potentialProviderPackages.isEmpty());
-        assertEquals("package1", potentialProviderPackages.get(0));
-    }
-
-    public void testGetPotentialRecommendationProviderPackages_multipleConfigured()
-            throws Exception {
-        setNetworkRecommendationPackageNames("package1", "package2");
-        mockScoreNetworksDenied("package1");
-        mockScoreNetworksGranted("package2");
-
-        List<String> potentialProviderPackages =
-                mNetworkScorerAppManager.getPotentialRecommendationProviderPackages();
-
-        assertEquals(1, potentialProviderPackages.size());
-        assertEquals("package2", potentialProviderPackages.get(0));
-    }
-
-    public void testGetNetworkRecommendationProviderData_noPotentialPackages() throws Exception {
-        setNetworkRecommendationPackageNames(/*no configured packages*/);
-        assertNull(mNetworkScorerAppManager.getNetworkRecommendationProviderData());
-    }
-
-    public void testGetNetworkRecommendationProviderData_serviceMissing() throws Exception {
-        setNetworkRecommendationPackageNames("package1");
-        mockScoreNetworksGranted("package1");
-
-        assertNull(mNetworkScorerAppManager.getNetworkRecommendationProviderData());
-    }
-
-    public void testGetNetworkRecommendationProviderData_scoreNetworksNotGranted()
-            throws Exception {
-        final ComponentName recoComponent = new ComponentName("package1", "class1");
-        setNetworkRecommendationPackageNames(recoComponent.getPackageName());
-        mockScoreNetworksDenied(recoComponent.getPackageName());
-        mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */);
-
-        assertNull(mNetworkScorerAppManager.getNetworkRecommendationProviderData());
-    }
-
-    public void testGetNetworkRecommendationProviderData_available() throws Exception {
-        final ComponentName recoComponent = new ComponentName("package1", "class1");
-        setNetworkRecommendationPackageNames(recoComponent.getPackageName());
-        mockScoreNetworksGranted(recoComponent.getPackageName());
-        mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */);
-
-        NetworkScorerAppData appData =
-                mNetworkScorerAppManager.getNetworkRecommendationProviderData();
-        assertNotNull(appData);
-        assertEquals(recoComponent, appData.getRecommendationServiceComponent());
-        assertEquals(924, appData.packageUid);
-    }
-
+    @Test
     public void testGetActiveScorer_providerAvailable() throws Exception {
         final ComponentName recoComponent = new ComponentName("package1", "class1");
-        setNetworkRecommendationPackageNames(recoComponent.getPackageName());
+        setNetworkRecoPackageSetting(recoComponent.getPackageName());
         mockScoreNetworksGranted(recoComponent.getPackageName());
         mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */);
 
-        ContentResolver cr = mTargetContext.getContentResolver();
-        Settings.Global.putInt(cr, Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 1);
-
         final NetworkScorerAppData activeScorer = mNetworkScorerAppManager.getActiveScorer();
         assertNotNull(activeScorer);
         assertEquals(recoComponent, activeScorer.getRecommendationServiceComponent());
         assertEquals(924, activeScorer.packageUid);
     }
 
+    @Test
+    public void testGetActiveScorer_permissionMissing() throws Exception {
+        final ComponentName recoComponent = new ComponentName("package1", "class1");
+        setNetworkRecoPackageSetting(recoComponent.getPackageName());
+        mockScoreNetworksDenied(recoComponent.getPackageName());
+        mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */);
+
+        final NetworkScorerAppData activeScorer = mNetworkScorerAppManager.getActiveScorer();
+        assertNull(activeScorer);
+    }
+
+    @Test
     public void testGetActiveScorer_providerAvailable_enableUseOpenWifiActivityNotSet()
             throws Exception {
         final ComponentName recoComponent = new ComponentName("package1", "class1");
-        setNetworkRecommendationPackageNames(recoComponent.getPackageName());
+        setNetworkRecoPackageSetting(recoComponent.getPackageName());
         mockScoreNetworksGranted(recoComponent.getPackageName());
         mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */,
                 null /* enableUseOpenWifiPackageActivityPackage*/);
 
-        ContentResolver cr = mTargetContext.getContentResolver();
-        Settings.Global.putInt(cr, Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 1);
-
         final NetworkScorerAppData activeScorer = mNetworkScorerAppManager.getActiveScorer();
         assertNotNull(activeScorer);
         assertEquals(recoComponent, activeScorer.getRecommendationServiceComponent());
@@ -174,17 +123,15 @@
         assertNull(activeScorer.getEnableUseOpenWifiActivity());
     }
 
+    @Test
     public void testGetActiveScorer_providerAvailable_enableUseOpenWifiActivityNotResolved()
             throws Exception {
         final ComponentName recoComponent = new ComponentName("package1", "class1");
-        setNetworkRecommendationPackageNames(recoComponent.getPackageName());
+        setNetworkRecoPackageSetting(recoComponent.getPackageName());
         mockScoreNetworksGranted(recoComponent.getPackageName());
         mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */,
                 "package2" /* enableUseOpenWifiPackageActivityPackage*/);
 
-        ContentResolver cr = mTargetContext.getContentResolver();
-        Settings.Global.putInt(cr, Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 1);
-
         final NetworkScorerAppData activeScorer = mNetworkScorerAppManager.getActiveScorer();
         assertNotNull(activeScorer);
         assertEquals(recoComponent, activeScorer.getRecommendationServiceComponent());
@@ -192,19 +139,17 @@
         assertNull(activeScorer.getEnableUseOpenWifiActivity());
     }
 
+    @Test
     public void testGetActiveScorer_providerAvailable_enableUseOpenWifiActivityResolved()
             throws Exception {
         final ComponentName recoComponent = new ComponentName("package1", "class1");
         final ComponentName enableUseOpenWifiComponent = new ComponentName("package2", "class2");
-        setNetworkRecommendationPackageNames(recoComponent.getPackageName());
+        setNetworkRecoPackageSetting(recoComponent.getPackageName());
         mockScoreNetworksGranted(recoComponent.getPackageName());
         mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */,
                 enableUseOpenWifiComponent.getPackageName());
         mockEnableUseOpenWifiActivity(enableUseOpenWifiComponent);
 
-        ContentResolver cr = mTargetContext.getContentResolver();
-        Settings.Global.putInt(cr, Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 1);
-
         final NetworkScorerAppData activeScorer = mNetworkScorerAppManager.getActiveScorer();
         assertNotNull(activeScorer);
         assertEquals(recoComponent, activeScorer.getRecommendationServiceComponent());
@@ -212,33 +157,105 @@
         assertEquals(enableUseOpenWifiComponent, activeScorer.getEnableUseOpenWifiActivity());
     }
 
-    public void testGetActiveScorer_providerNotAvailable()
+    @Test
+    public void testGetActiveScorer_packageSettingIsNull()
             throws Exception {
-        ContentResolver cr = mTargetContext.getContentResolver();
-        Settings.Global.putInt(cr, Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 1);
+        // NETWORK_RECOMMENDATIONS_PACKAGE is null
 
         final NetworkScorerAppData activeScorer = mNetworkScorerAppManager.getActiveScorer();
         assertNull(activeScorer);
     }
 
-    public void testGetActiveScorer_recommendationsDisabled() throws Exception {
+    @Test
+    public void testGetActiveScorer_packageSettingIsInvalid() throws Exception {
         final ComponentName recoComponent = new ComponentName("package1", "class1");
-        setNetworkRecommendationPackageNames(recoComponent.getPackageName());
+        setDefaultNetworkRecommendationPackage(recoComponent.getPackageName());
         mockScoreNetworksGranted(recoComponent.getPackageName());
-        mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */);
-        ContentResolver cr = mTargetContext.getContentResolver();
-        Settings.Global.putInt(cr, Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 0);
+        // NETWORK_RECOMMENDATIONS_PACKAGE is set to a package that isn't a recommender.
 
         final NetworkScorerAppData activeScorer = mNetworkScorerAppManager.getActiveScorer();
         assertNull(activeScorer);
     }
 
-    private void setNetworkRecommendationPackageNames(String... names) {
-        if (names == null) {
-            names = new String[0];
-        }
-        when(mResources.getStringArray(R.array.config_networkRecommendationPackageNames))
-                .thenReturn(names);
+    @Test
+    public void testSetActiveScorer_noChange() throws Exception {
+        String packageName = "package";
+        setNetworkRecoPackageSetting(packageName);
+
+        assertTrue(mNetworkScorerAppManager.setActiveScorer(packageName));
+        verify(mSettingsFacade, never()).putString(any(), any(), any());
+    }
+
+    @Test
+    public void testSetActiveScorer_nullPackage() throws Exception {
+        String packageName = "package";
+        String defaultPackage = "defaultPackage";
+        setNetworkRecoPackageSetting(packageName);
+        setDefaultNetworkRecommendationPackage(defaultPackage);
+
+        assertTrue(mNetworkScorerAppManager.setActiveScorer(null));
+        verify(mSettingsFacade).putString(mMockContext,
+                Settings.Global.NETWORK_RECOMMENDATIONS_PACKAGE, defaultPackage);
+    }
+
+    @Test
+    public void testSetActiveScorer_validPackage() throws Exception {
+        String packageName = "package";
+        String newPackage = "newPackage";
+        setNetworkRecoPackageSetting(packageName);
+        final ComponentName recoComponent = new ComponentName(newPackage, "class1");
+        mockScoreNetworksGranted(recoComponent.getPackageName());
+        mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */, null);
+
+        assertTrue(mNetworkScorerAppManager.setActiveScorer(newPackage));
+        verify(mSettingsFacade).putString(mMockContext,
+                Settings.Global.NETWORK_RECOMMENDATIONS_PACKAGE, newPackage);
+    }
+
+    @Test
+    public void testSetActiveScorer_invalidPackage() throws Exception {
+        String packageName = "package";
+        String newPackage = "newPackage";
+        setNetworkRecoPackageSetting(packageName);
+        // newPackage doesn't resolve to a valid recommender
+
+        assertFalse(mNetworkScorerAppManager.setActiveScorer(newPackage));
+        verify(mSettingsFacade, never()).putString(any(), any(), any());
+    }
+
+
+    @Test
+    public void testRevertToDefaultIfNoActive_notActive() throws Exception {
+        String defaultPackage = "defaultPackage";
+        setDefaultNetworkRecommendationPackage(defaultPackage);
+
+        mNetworkScorerAppManager.revertToDefaultIfNoActive();
+
+        verify(mSettingsFacade).putString(mMockContext,
+                Settings.Global.NETWORK_RECOMMENDATIONS_PACKAGE, defaultPackage);
+    }
+
+    @Test
+    public void testRevertToDefaultIfNoActive_active() throws Exception {
+        String packageName = "package";
+        setNetworkRecoPackageSetting(packageName);
+        final ComponentName recoComponent = new ComponentName(packageName, "class1");
+        mockScoreNetworksGranted(recoComponent.getPackageName());
+        mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */, null);
+
+        mNetworkScorerAppManager.revertToDefaultIfNoActive();
+
+        verify(mSettingsFacade, never()).putString(any(), any(), any());
+    }
+
+    private void setNetworkRecoPackageSetting(String packageName) {
+        when(mSettingsFacade.getString(mMockContext,
+                Settings.Global.NETWORK_RECOMMENDATIONS_PACKAGE)).thenReturn(packageName);
+    }
+
+    private void setDefaultNetworkRecommendationPackage(String name) {
+        when(mResources.getString(R.string.config_defaultNetworkRecommendationProviderPackage))
+                .thenReturn(name);
     }
 
     private void mockScoreNetworksGranted(String packageName) {
@@ -281,6 +298,8 @@
                                 && compName.getPackageName().equals(intent.getPackage());
                     }
                 }), Mockito.eq(flags))).thenReturn(serviceInfo);
+
+        mAvailableServices.add(serviceInfo);
     }
 
     private void mockEnableUseOpenWifiActivity(final ComponentName useOpenWifiComp) {
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index dd03305..afff6d5 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -208,7 +208,9 @@
      *
      * @see #onOemHookRawEvent
      * @hide
+     * @deprecated OEM needs a vendor-extension hal and their apps should use that instead
      */
+    @Deprecated
     public static final int LISTEN_OEM_HOOK_RAW_EVENT                       = 0x00008000;
 
     /**
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index a4235d7..f5974cd 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -5229,7 +5229,9 @@
      *         0 request was handled succesfully, but no response data
      *         positive value success, data length of response
      * @hide
+     * @deprecated OEM needs a vendor-extension hal and their apps should use that instead
      */
+    @Deprecated
     public int invokeOemRilRequestRaw(byte[] oemReq, byte[] oemResp) {
         try {
             ITelephony telephony = getITelephony();
diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
index d40835b..dc8dfba 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
@@ -264,15 +264,6 @@
             = "android.intent.action.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS";
 
     /**
-     * Activity Action: Start this activity to invoke the carrier setup app.
-     * The carrier app must be signed using a certificate that matches the UICC access rules.
-     *
-     * <p class="note">Callers of this should hold the android.permission.INVOKE_CARRIER_SETUP
-     * permission.</p>
-     */
-    public static final String ACTION_CARRIER_SETUP = "android.intent.action.ACTION_CARRIER_SETUP";
-
-    /**
      * <p>Broadcast Action: Indicates that the action is forbidden by network.
      * <p class="note">
      * This is for the OEM applications to understand about possible provisioning issues.
diff --git a/tests/SoundTriggerTestApp/res/layout/main.xml b/tests/SoundTriggerTestApp/res/layout/main.xml
index 0fd8b12..2c6c8d7 100644
--- a/tests/SoundTriggerTestApp/res/layout/main.xml
+++ b/tests/SoundTriggerTestApp/res/layout/main.xml
@@ -87,6 +87,7 @@
             android:text="@string/capture"
             android:id="@+id/caputre_check_box"
             android:layout_gravity="center_horizontal"
+            android:onClick="onCaptureAudioCheckboxClicked"
             android:padding="20dp" />
 
         <Button
@@ -94,6 +95,7 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:text="@string/play_capture"
+            android:onClick="onPlayCapturedAudioButtonClicked"
             android:padding="20dp"
             android:enabled="false" />
     </LinearLayout>
diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
index 56aad23..9b1a9f2 100644
--- a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
+++ b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
@@ -297,6 +297,7 @@
                     Notification n = new Notification.Builder(NotificationTestList.this)
                             .setSmallIcon(R.drawable.icon2)
                             .setContentTitle("Low priority")
+                            .setTimeout(60000)
                             .setLights(0xff0000ff, 1, 0)
                             .setPriority(Notification.PRIORITY_LOW)
                             .build();