Merge "Relax strict ActionMode instance checking when finishing action modes" into mnc-dev
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 844900d..9f4bc52 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -1003,8 +1003,10 @@
     private void sendBroadcast() throws Exception {
         Intent intent = makeIntent(UserHandle.USER_CURRENT);
         IntentReceiver receiver = new IntentReceiver();
+        String[] requiredPermissions = mReceiverPermission == null ? null
+                : new String[] {mReceiverPermission};
         System.out.println("Broadcasting: " + intent);
-        mAm.broadcastIntent(null, intent, null, receiver, 0, null, null, mReceiverPermission,
+        mAm.broadcastIntent(null, intent, null, receiver, 0, null, null, requiredPermissions,
                 android.app.AppOpsManager.OP_NONE, null, true, false, mUserId);
         receiver.waitForFinish();
     }
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index cc93ac9..fc408a8 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -456,14 +456,14 @@
             int resultCode = data.readInt();
             String resultData = data.readString();
             Bundle resultExtras = data.readBundle();
-            String perm = data.readString();
+            String[] perms = data.readStringArray();
             int appOp = data.readInt();
             Bundle options = data.readBundle();
             boolean serialized = data.readInt() != 0;
             boolean sticky = data.readInt() != 0;
             int userId = data.readInt();
             int res = broadcastIntent(app, intent, resolvedType, resultTo,
-                    resultCode, resultData, resultExtras, perm, appOp,
+                    resultCode, resultData, resultExtras, perms, appOp,
                     options, serialized, sticky, userId);
             reply.writeNoException();
             reply.writeInt(res);
@@ -3007,7 +3007,7 @@
     public int broadcastIntent(IApplicationThread caller,
             Intent intent, String resolvedType, IIntentReceiver resultTo,
             int resultCode, String resultData, Bundle map,
-            String requiredPermission, int appOp, Bundle options, boolean serialized,
+            String[] requiredPermissions, int appOp, Bundle options, boolean serialized,
             boolean sticky, int userId) throws RemoteException
     {
         Parcel data = Parcel.obtain();
@@ -3020,7 +3020,7 @@
         data.writeInt(resultCode);
         data.writeString(resultData);
         data.writeBundle(map);
-        data.writeString(requiredPermission);
+        data.writeStringArray(requiredPermissions);
         data.writeInt(appOp);
         data.writeBundle(options);
         data.writeInt(serialized ? 1 : 0);
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 75dd35c..235f294 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -180,7 +180,7 @@
     @GuardedBy("mSync")
     private File[] mExternalMediaDirs;
 
-    private static final String[] EMPTY_FILE_LIST = {};
+    private static final String[] EMPTY_STRING_ARRAY = {};
 
     // The system service cache for the system services that are cached per-ContextImpl.
     final Object[] mServiceCache = SystemServiceRegistry.createServiceCache();
@@ -552,7 +552,7 @@
     @Override
     public String[] fileList() {
         final String[] list = getFilesDir().list();
-        return (list != null) ? list : EMPTY_FILE_LIST;
+        return (list != null) ? list : EMPTY_STRING_ARRAY;
     }
 
     @Override
@@ -591,7 +591,7 @@
     @Override
     public String[] databaseList() {
         final String[] list = getDatabasesDir().list();
-        return (list != null) ? list : EMPTY_FILE_LIST;
+        return (list != null) ? list : EMPTY_STRING_ARRAY;
     }
 
 
@@ -777,11 +777,28 @@
     public void sendBroadcast(Intent intent, String receiverPermission) {
         warnIfCallingFromSystemProcess();
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
+        String[] receiverPermissions = receiverPermission == null ? null
+                : new String[] {receiverPermission};
         try {
             intent.prepareToLeaveProcess();
             ActivityManagerNative.getDefault().broadcastIntent(
                     mMainThread.getApplicationThread(), intent, resolvedType, null,
-                    Activity.RESULT_OK, null, null, receiverPermission, AppOpsManager.OP_NONE,
+                    Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE,
+                    null, false, false, getUserId());
+        } catch (RemoteException e) {
+            throw new RuntimeException("Failure from system", e);
+        }
+    }
+
+    @Override
+    public void sendBroadcastMultiplePermissions(Intent intent, String[] receiverPermissions) {
+        warnIfCallingFromSystemProcess();
+        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
+        try {
+            intent.prepareToLeaveProcess();
+            ActivityManagerNative.getDefault().broadcastIntent(
+                    mMainThread.getApplicationThread(), intent, resolvedType, null,
+                    Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE,
                     null, false, false, getUserId());
         } catch (RemoteException e) {
             throw new RuntimeException("Failure from system", e);
@@ -792,11 +809,13 @@
     public void sendBroadcast(Intent intent, String receiverPermission, Bundle options) {
         warnIfCallingFromSystemProcess();
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
+        String[] receiverPermissions = receiverPermission == null ? null
+                : new String[] {receiverPermission};
         try {
             intent.prepareToLeaveProcess();
             ActivityManagerNative.getDefault().broadcastIntent(
                     mMainThread.getApplicationThread(), intent, resolvedType, null,
-                    Activity.RESULT_OK, null, null, receiverPermission, AppOpsManager.OP_NONE,
+                    Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE,
                     options, false, false, getUserId());
         } catch (RemoteException e) {
             throw new RuntimeException("Failure from system", e);
@@ -807,11 +826,13 @@
     public void sendBroadcast(Intent intent, String receiverPermission, int appOp) {
         warnIfCallingFromSystemProcess();
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
+        String[] receiverPermissions = receiverPermission == null ? null
+                : new String[] {receiverPermission};
         try {
             intent.prepareToLeaveProcess();
             ActivityManagerNative.getDefault().broadcastIntent(
                     mMainThread.getApplicationThread(), intent, resolvedType, null,
-                    Activity.RESULT_OK, null, null, receiverPermission, appOp, null, false, false,
+                    Activity.RESULT_OK, null, null, receiverPermissions, appOp, null, false, false,
                     getUserId());
         } catch (RemoteException e) {
             throw new RuntimeException("Failure from system", e);
@@ -822,11 +843,13 @@
     public void sendOrderedBroadcast(Intent intent, String receiverPermission) {
         warnIfCallingFromSystemProcess();
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
+        String[] receiverPermissions = receiverPermission == null ? null
+                : new String[] {receiverPermission};
         try {
             intent.prepareToLeaveProcess();
             ActivityManagerNative.getDefault().broadcastIntent(
                     mMainThread.getApplicationThread(), intent, resolvedType, null,
-                    Activity.RESULT_OK, null, null, receiverPermission, AppOpsManager.OP_NONE,
+                    Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE,
                     null, true, false, getUserId());
         } catch (RemoteException e) {
             throw new RuntimeException("Failure from system", e);
@@ -883,11 +906,13 @@
             }
         }
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
+        String[] receiverPermissions = receiverPermission == null ? null
+                : new String[] {receiverPermission};
         try {
             intent.prepareToLeaveProcess();
             ActivityManagerNative.getDefault().broadcastIntent(
                 mMainThread.getApplicationThread(), intent, resolvedType, rd,
-                initialCode, initialData, initialExtras, receiverPermission, appOp,
+                initialCode, initialData, initialExtras, receiverPermissions, appOp,
                     options, true, false, getUserId());
         } catch (RemoteException e) {
             throw new RuntimeException("Failure from system", e);
@@ -917,11 +942,13 @@
     public void sendBroadcastAsUser(Intent intent, UserHandle user,
             String receiverPermission, int appOp) {
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
+        String[] receiverPermissions = receiverPermission == null ? null
+                : new String[] {receiverPermission};
         try {
             intent.prepareToLeaveProcess();
             ActivityManagerNative.getDefault().broadcastIntent(
                     mMainThread.getApplicationThread(), intent, resolvedType, null,
-                    Activity.RESULT_OK, null, null, receiverPermission, appOp, null, false, false,
+                    Activity.RESULT_OK, null, null, receiverPermissions, appOp, null, false, false,
                     user.getIdentifier());
         } catch (RemoteException e) {
             throw new RuntimeException("Failure from system", e);
@@ -933,14 +960,21 @@
             String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler,
             int initialCode, String initialData, Bundle initialExtras) {
         sendOrderedBroadcastAsUser(intent, user, receiverPermission, AppOpsManager.OP_NONE,
-                resultReceiver, scheduler, initialCode, initialData, initialExtras);
+                null, resultReceiver, scheduler, initialCode, initialData, initialExtras);
     }
 
     @Override
     public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
             String receiverPermission, int appOp, BroadcastReceiver resultReceiver,
-            Handler scheduler,
-            int initialCode, String initialData, Bundle initialExtras) {
+            Handler scheduler, int initialCode, String initialData, Bundle initialExtras) {
+        sendOrderedBroadcastAsUser(intent, user, receiverPermission, appOp,
+                null, resultReceiver, scheduler, initialCode, initialData, initialExtras);
+    }
+
+    @Override
+    public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
+            String receiverPermission, int appOp, Bundle options, BroadcastReceiver resultReceiver,
+            Handler scheduler, int initialCode, String initialData, Bundle initialExtras) {
         IIntentReceiver rd = null;
         if (resultReceiver != null) {
             if (mPackageInfo != null) {
@@ -954,17 +988,19 @@
                 if (scheduler == null) {
                     scheduler = mMainThread.getHandler();
                 }
-                rd = new LoadedApk.ReceiverDispatcher(
-                        resultReceiver, getOuterContext(), scheduler, null, false).getIIntentReceiver();
+                rd = new LoadedApk.ReceiverDispatcher(resultReceiver, getOuterContext(),
+                        scheduler, null, false).getIIntentReceiver();
             }
         }
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
+        String[] receiverPermissions = receiverPermission == null ? null
+                : new String[] {receiverPermission};
         try {
             intent.prepareToLeaveProcess();
             ActivityManagerNative.getDefault().broadcastIntent(
                 mMainThread.getApplicationThread(), intent, resolvedType, rd,
-                initialCode, initialData, initialExtras, receiverPermission,
-                    appOp, null, true, false, user.getIdentifier());
+                initialCode, initialData, initialExtras, receiverPermissions,
+                    appOp, options, true, false, user.getIdentifier());
         } catch (RemoteException e) {
             throw new RuntimeException("Failure from system", e);
         }
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index acce81c..1d87d77 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -106,7 +106,7 @@
     public void unregisterReceiver(IIntentReceiver receiver) throws RemoteException;
     public int broadcastIntent(IApplicationThread caller, Intent intent,
             String resolvedType, IIntentReceiver resultTo, int resultCode,
-            String resultData, Bundle map, String requiredPermission,
+            String resultData, Bundle map, String[] requiredPermissions,
             int appOp, Bundle options, boolean serialized, boolean sticky, int userId) throws RemoteException;
     public void unbroadcastIntent(IApplicationThread caller, Intent intent, int userId) throws RemoteException;
     public void finishReceiver(IBinder who, int resultCode, String resultData, Bundle map,
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index c96fe71..d27dfa0 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -92,7 +92,8 @@
      * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
      * #EXTRA_CLASS}. Can contain the extra fields {@link #EXTRA_NAME} and/or
      * {@link #EXTRA_RSSI} if they are available.
-     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} and
+     * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION} to receive.
      */
      // TODO: Change API to not broadcast RSSI if not available (incoming connection)
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 675515b..4c7dd10 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1516,6 +1516,33 @@
     public abstract void sendBroadcast(Intent intent,
             @Nullable String receiverPermission);
 
+
+    /**
+     * Broadcast the given intent to all interested BroadcastReceivers, allowing
+     * an array of required permissions to be enforced.  This call is asynchronous; it returns
+     * immediately, and you will continue executing while the receivers are run.  No results are
+     * propagated from receivers and receivers can not abort the broadcast. If you want to allow
+     * receivers to propagate results or abort the broadcast, you must send an ordered broadcast
+     * using {@link #sendOrderedBroadcast(Intent, String)}.
+     *
+     * <p>See {@link BroadcastReceiver} for more information on Intent broadcasts.
+     *
+     * @param intent The Intent to broadcast; all receivers matching this
+     *               Intent will receive the broadcast.
+     * @param receiverPermissions Array of names of permissions that a receiver must hold
+     *                            in order to receive your broadcast.
+     *                            If null or empty, no permissions are required.
+     *
+     * @see android.content.BroadcastReceiver
+     * @see #registerReceiver
+     * @see #sendBroadcast(Intent)
+     * @see #sendOrderedBroadcast(Intent, String)
+     * @see #sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle)
+     * @hide
+     */
+    public abstract void sendBroadcastMultiplePermissions(Intent intent,
+            String[] receiverPermissions);
+
     /**
      * Broadcast the given intent to all interested BroadcastReceivers, allowing
      * an optional required permission to be enforced.  This
@@ -1782,6 +1809,17 @@
             @Nullable  Bundle initialExtras);
 
     /**
+     * Similar to above but takes an appOp as well, to enforce restrictions, and an options Bundle.
+     * @see #sendOrderedBroadcastAsUser(Intent, UserHandle, String,
+     *       BroadcastReceiver, Handler, int, String, Bundle)
+     * @hide
+     */
+    public abstract void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
+            @Nullable String receiverPermission, int appOp, @Nullable Bundle options,
+            BroadcastReceiver resultReceiver, @Nullable Handler scheduler, int initialCode,
+            @Nullable String initialData, @Nullable  Bundle initialExtras);
+
+    /**
      * <p>Perform a {@link #sendBroadcast(Intent)} that is "sticky," meaning the
      * Intent you are sending stays around after the broadcast is complete,
      * so that others can quickly retrieve that data through the return
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 4e7c832..8359edf 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -402,6 +402,12 @@
     }
 
     /** @hide */
+    @Override
+    public void sendBroadcastMultiplePermissions(Intent intent, String[] receiverPermissions) {
+        mBase.sendBroadcastMultiplePermissions(intent, receiverPermissions);
+    }
+
+    /** @hide */
     @SystemApi
     @Override
     public void sendBroadcast(Intent intent, String receiverPermission, Bundle options) {
@@ -483,12 +489,20 @@
     @Override
     public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
             String receiverPermission, int appOp, BroadcastReceiver resultReceiver,
-            Handler scheduler,
-            int initialCode, String initialData, Bundle initialExtras) {
+            Handler scheduler, int initialCode, String initialData, Bundle initialExtras) {
         mBase.sendOrderedBroadcastAsUser(intent, user, receiverPermission, appOp, resultReceiver,
                 scheduler, initialCode, initialData, initialExtras);
     }
 
+    /** @hide */
+    @Override
+    public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
+            String receiverPermission, int appOp, Bundle options, BroadcastReceiver resultReceiver,
+            Handler scheduler, int initialCode, String initialData, Bundle initialExtras) {
+        mBase.sendOrderedBroadcastAsUser(intent, user, receiverPermission, appOp, options,
+                resultReceiver, scheduler, initialCode, initialData, initialExtras);
+    }
+
     @Override
     @Deprecated
     public void sendStickyBroadcast(Intent intent) {
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 30aa2d5..5583920 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -1901,7 +1901,7 @@
      * <tbody>
      * <tr>
      * <td align="center">{@link android.graphics.ImageFormat#JPEG }</td>
-     * <td align="center">{@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}</td>
+     * <td align="center">{@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} (*1)</td>
      * <td align="center">Any</td>
      * <td align="center"></td>
      * </tr>
@@ -1913,7 +1913,7 @@
      * </tr>
      * <tr>
      * <td align="center">{@link android.graphics.ImageFormat#JPEG }</td>
-     * <td align="center">1280x720 (720)</td>
+     * <td align="center">1280x720 (720p)</td>
      * <td align="center">Any</td>
      * <td align="center">if 720p &lt;= activeArraySize</td>
      * </tr>
@@ -1951,6 +1951,22 @@
      * </table>
      * <p>Refer to {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} and {@link android.hardware.camera2.CameraDevice#createCaptureSession } for additional mandatory
      * stream configurations on a per-capability basis.</p>
+     * <p>*1: For JPEG format, the sizes may be restricted by below conditions:</p>
+     * <ul>
+     * <li>The HAL may choose the aspect ratio of each Jpeg size to be one of well known ones
+     * (e.g. 4:3, 16:9, 3:2 etc.). If the sensor maximum resolution
+     * (defined by {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}) has an aspect ratio other than these,
+     * it does not have to be included in the supported JPEG sizes.</li>
+     * <li>Some hardware JPEG encoders may have pixel boundary alignment requirements, such as
+     * the dimensions being a multiple of 16.
+     * Therefore, the maximum JPEG size may be smaller than sensor maximum resolution.
+     * However, the largest JPEG size will be as close as possible to the sensor maximum
+     * resolution given above constraints. It is required that after aspect ratio adjustments,
+     * additional size reduction due to other issues must be less than 3% in area. For example,
+     * if the sensor maximum resolution is 3280x2464, if the maximum JPEG size has aspect
+     * ratio 4:3, and the JPEG encoder alignment requirement is 16, the maximum JPEG size will be
+     * 3264x2448.</li>
+     * </ul>
      * <p>This key is available on all devices.</p>
      *
      * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index adc84bc..452e4d5 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -1193,9 +1193,11 @@
         public static final int EVENT_PACKAGE_INACTIVE = 0x000f;
         // Event for a package becoming active due to an interaction.
         public static final int EVENT_PACKAGE_ACTIVE = 0x0010;
+        // Event for a package being on the temporary whitelist.
+        public static final int EVENT_TEMP_WHITELIST = 0x0011;
 
         // Number of event types.
-        public static final int EVENT_COUNT = 0x0011;
+        public static final int EVENT_COUNT = 0x0012;
         // Mask to extract out only the type part of the event.
         public static final int EVENT_TYPE_MASK = ~(EVENT_FLAG_START|EVENT_FLAG_FINISH);
 
@@ -1219,6 +1221,10 @@
                 EVENT_USER_FOREGROUND | EVENT_FLAG_FINISH;
         public static final int EVENT_ALARM_START = EVENT_ALARM | EVENT_FLAG_START;
         public static final int EVENT_ALARM_FINISH = EVENT_ALARM | EVENT_FLAG_FINISH;
+        public static final int EVENT_TEMP_WHITELIST_START =
+                EVENT_TEMP_WHITELIST | EVENT_FLAG_START;
+        public static final int EVENT_TEMP_WHITELIST_FINISH =
+                EVENT_TEMP_WHITELIST | EVENT_FLAG_FINISH;
 
         // For CMD_EVENT.
         public int eventCode;
@@ -1852,12 +1858,12 @@
 
     public static final String[] HISTORY_EVENT_NAMES = new String[] {
             "null", "proc", "fg", "top", "sync", "wake_lock_in", "job", "user", "userfg", "conn",
-            "active", "pkginst", "pkgunin", "alarm", "stats", "inactive", "active"
+            "active", "pkginst", "pkgunin", "alarm", "stats", "inactive", "active", "tmpwhitelist"
     };
 
     public static final String[] HISTORY_EVENT_CHECKIN_NAMES = new String[] {
             "Enl", "Epr", "Efg", "Etp", "Esy", "Ewl", "Ejb", "Eur", "Euf", "Ecn",
-            "Eac", "Epi", "Epu", "Eal", "Est", "Eai", "Eaa"
+            "Eac", "Epi", "Epu", "Eal", "Est", "Eai", "Eaa", "Etw"
     };
 
     /**
diff --git a/core/java/android/os/IDeviceIdleController.aidl b/core/java/android/os/IDeviceIdleController.aidl
index fe4aa13..b768852 100644
--- a/core/java/android/os/IDeviceIdleController.aidl
+++ b/core/java/android/os/IDeviceIdleController.aidl
@@ -27,6 +27,7 @@
     int[] getAppIdWhitelist();
     int[] getAppIdTempWhitelist();
     boolean isPowerSaveWhitelistApp(String name);
-    void addPowerSaveTempWhitelistApp(String name, long duration, int userId);
+    void addPowerSaveTempWhitelistApp(String name, long duration, int userId, String reason);
+    long addPowerSaveTempWhitelistAppForMms(String name, int userId, String reason);
     void exitIdle(String reason);
 }
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 84c2417..ae2cbad 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -8073,7 +8073,7 @@
                     timer.mUid.mSystemCpuTime.addCountLocked(systemTimeUs);
 
                     final Uid.Proc proc = timer.mUid.getProcessStatsLocked("*wakelock*");
-                    proc.addCpuTimeLocked(userTimeUs, systemTimeUs);
+                    proc.addCpuTimeLocked(userTimeUs / 1000, systemTimeUs / 1000);
 
                     mTempTotalCpuUserTimeUs -= userTimeUs;
                     mTempTotalCpuSystemTimeUs -= systemTimeUs;
@@ -8097,8 +8097,8 @@
                 u.mSystemCpuTime.addCountLocked(mTempTotalCpuSystemTimeUs);
 
                 final Uid.Proc proc = u.getProcessStatsLocked("*lost*");
-                proc.addCpuTimeLocked((int) mTempTotalCpuUserTimeUs,
-                        (int) mTempTotalCpuSystemTimeUs);
+                proc.addCpuTimeLocked((int) mTempTotalCpuUserTimeUs / 1000,
+                        (int) mTempTotalCpuSystemTimeUs / 1000);
             }
         }
 
diff --git a/core/java/com/android/internal/os/KernelUidCpuTimeReader.java b/core/java/com/android/internal/os/KernelUidCpuTimeReader.java
index 1a1e0b2..0df78ed 100644
--- a/core/java/com/android/internal/os/KernelUidCpuTimeReader.java
+++ b/core/java/com/android/internal/os/KernelUidCpuTimeReader.java
@@ -151,6 +151,7 @@
         if (index >= 0) {
             mLastUserTimeUs.removeAt(index);
             mLastSystemTimeUs.removeAt(index);
+            mLastPowerMaUs.removeAt(index);
         }
 
         try (FileWriter writer = new FileWriter(sRemoveUidProcFile)) {
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 3bf8129..5290cac 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -3859,8 +3859,8 @@
      */
     public void registerAudioDeviceCallback(AudioDeviceCallback callback,
             android.os.Handler handler) {
-        if (callback != null && !mDeviceCallbacks.containsKey(callback)) {
-            synchronized (mDeviceCallbacks) {
+        synchronized (mDeviceCallbacks) {
+            if (callback != null && !mDeviceCallbacks.containsKey(callback)) {
                 if (mDeviceCallbacks.size() == 0) {
                     if (mPortListener == null) {
                         mPortListener = new OnAmPortUpdateListener();
@@ -3924,21 +3924,20 @@
                     calcListDeltas(current_ports, mPreviousPorts, GET_DEVICES_ALL);
 
             if (added_devices.length != 0 || removed_devices.length != 0) {
-                Collection<NativeEventHandlerDelegate> values;
                 synchronized (mDeviceCallbacks) {
-                    values = mDeviceCallbacks.values();
-                }
-                for (NativeEventHandlerDelegate delegate : values) {
-                    handler = delegate.getHandler();
-                    if (handler != null) {
-                        if (added_devices.length != 0) {
-                            handler.sendMessage(
-                                Message.obtain(handler,MSG_DEVICES_DEVICES_ADDED, added_devices));
-                        }
-                        if (removed_devices.length != 0) {
-                            handler.sendMessage(
-                                Message.obtain(handler,MSG_DEVICES_DEVICES_REMOVED,
-                                               removed_devices));
+                    for (int i = 0; i < mDeviceCallbacks.size(); i++) {
+                        handler = mDeviceCallbacks.valueAt(i).getHandler();
+                        if (handler != null) {
+                            if (added_devices.length != 0) {
+                                handler.sendMessage(Message.obtain(handler,
+                                                                   MSG_DEVICES_DEVICES_ADDED,
+                                                                   added_devices));
+                            }
+                            if (removed_devices.length != 0) {
+                                handler.sendMessage(Message.obtain(handler,
+                                                                   MSG_DEVICES_DEVICES_REMOVED,
+                                                                   removed_devices));
+                            }
                         }
                     }
                 }
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index fde1490..c7c9d29 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -36,6 +36,7 @@
 import android.hardware.display.DisplayManager;
 import android.net.INetworkPolicyManager;
 import android.net.Uri;
+import android.os.BatteryStats;
 import android.os.Binder;
 import android.os.Environment;
 import android.os.FileUtils;
@@ -54,9 +55,11 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.KeyValueListParser;
+import android.util.MutableLong;
+import android.util.Pair;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.util.SparseBooleanArray;
-import android.util.SparseLongArray;
 import android.util.TimeUtils;
 import android.util.Xml;
 import android.view.Display;
@@ -177,7 +180,13 @@
      * List of end times for UIDs that are temporarily marked as being allowed to access
      * the network and acquire wakelocks. Times are in milliseconds.
      */
-    private final SparseLongArray mTempWhitelistAppIdEndTimes = new SparseLongArray();
+    private final SparseArray<Pair<MutableLong, String>> mTempWhitelistAppIdEndTimes
+            = new SparseArray<>();
+
+    /**
+     * Callback to the NetworkPolicyManagerService to tell it that the temp whitelist has changed.
+     */
+    Runnable mNetworkPolicyTempWhitelistCallback;
 
     /**
      * Current app IDs of temporarily whitelist apps for high-priority messages.
@@ -242,6 +251,8 @@
         private static final String KEY_MIN_TIME_TO_ALARM = "min_time_to_alarm";
         private static final String KEY_MAX_TEMP_APP_WHITELIST_DURATION =
                 "max_temp_app_whitelist_duration";
+        private static final String KEY_MMS_TEMP_APP_WHITELIST_DURATION =
+                "mms_temp_app_whitelist_duration";
 
         /**
          * This is the time, after becoming inactive, at which we start looking at the
@@ -339,6 +350,13 @@
          */
         public long MAX_TEMP_APP_WHITELIST_DURATION;
 
+        /**
+         * Amount of time we would like to whitelist an app that is receiving an MMS.
+         * @see Settings.Global#DEVICE_IDLE_CONSTANTS
+         * @see #KEY_MMS_TEMP_APP_WHITELIST_DURATION
+         */
+        public long MMS_TEMP_APP_WHITELIST_DURATION;
+
         private final ContentResolver mResolver;
         private final KeyValueListParser mParser = new KeyValueListParser(',');
 
@@ -388,8 +406,10 @@
                         2f);
                 MIN_TIME_TO_ALARM = mParser.getLong(KEY_MIN_TIME_TO_ALARM,
                         !COMPRESS_TIME ? 60 * 60 * 1000L : 6 * 60 * 1000L);
-                MAX_TEMP_APP_WHITELIST_DURATION = mParser.getLong(KEY_MAX_TEMP_APP_WHITELIST_DURATION,
-                        5 * 60 * 1000L);
+                MAX_TEMP_APP_WHITELIST_DURATION = mParser.getLong(
+                        KEY_MAX_TEMP_APP_WHITELIST_DURATION, 5 * 60 * 1000L);
+                MMS_TEMP_APP_WHITELIST_DURATION = mParser.getLong(
+                        KEY_MMS_TEMP_APP_WHITELIST_DURATION, 60 * 1000L);
             }
         }
 
@@ -441,6 +461,10 @@
             pw.print("    "); pw.print(KEY_MAX_TEMP_APP_WHITELIST_DURATION); pw.print("=");
             TimeUtils.formatDuration(MAX_TEMP_APP_WHITELIST_DURATION, pw);
             pw.println();
+
+            pw.print("    "); pw.print(KEY_MMS_TEMP_APP_WHITELIST_DURATION); pw.print("=");
+            TimeUtils.formatDuration(MMS_TEMP_APP_WHITELIST_DURATION, pw);
+            pw.println();
         }
     }
 
@@ -565,7 +589,7 @@
         }
 
         @Override public void addPowerSaveTempWhitelistApp(String packageName, long duration,
-                int userId) throws RemoteException {
+                int userId, String reason) throws RemoteException {
             getContext().enforceCallingPermission(
                     Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST,
                     "No permission to change device idle whitelist");
@@ -580,12 +604,19 @@
             final long token = Binder.clearCallingIdentity();
             try {
                 DeviceIdleController.this.addPowerSaveTempWhitelistAppInternal(callingUid,
-                        packageName, duration, userId);
+                        packageName, duration, userId, true, reason);
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
         }
 
+        @Override public long addPowerSaveTempWhitelistAppForMms(String packageName,
+                int userId, String reason) throws RemoteException {
+            long duration = mConstants.MMS_TEMP_APP_WHITELIST_DURATION;
+            addPowerSaveTempWhitelistApp(packageName, duration, userId, reason);
+            return duration;
+        }
+
         @Override public void exitIdle(String reason) {
             getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
                     null);
@@ -598,8 +629,13 @@
     }
 
     public final class LocalService {
-        public void addPowerSaveTempWhitelistAppDirect(int appId, long duration) {
-            addPowerSaveTempWhitelistAppDirectInternal(0, appId, duration);
+        public void addPowerSaveTempWhitelistAppDirect(int appId, long duration, boolean sync,
+                String reason) {
+            addPowerSaveTempWhitelistAppDirectInternal(0, appId, duration, sync, reason);
+        }
+
+        public void setNetworkPolicyTempWhitelistCallback(Runnable callback) {
+            setNetworkPolicyTempWhitelistCallbackInternal(callback);
         }
     }
 
@@ -777,11 +813,11 @@
      * app an exemption to access network and acquire wakelocks.
      */
     public void addPowerSaveTempWhitelistAppInternal(int callingUid, String packageName,
-            long duration, int userId) {
+            long duration, int userId, boolean sync, String reason) {
         try {
             int uid = getContext().getPackageManager().getPackageUid(packageName, userId);
             int appId = UserHandle.getAppId(uid);
-            addPowerSaveTempWhitelistAppDirectInternal(callingUid, appId, duration);
+            addPowerSaveTempWhitelistAppDirectInternal(callingUid, appId, duration, sync, reason);
         } catch (NameNotFoundException e) {
         }
     }
@@ -791,8 +827,9 @@
      * app an exemption to access network and acquire wakelocks.
      */
     public void addPowerSaveTempWhitelistAppDirectInternal(int callingUid, int appId,
-            long duration) {
+            long duration, boolean sync, String reason) {
         final long timeNow = SystemClock.elapsedRealtime();
+        Runnable networkPolicyTempWhitelistCallback = null;
         synchronized (this) {
             int callingAppId = UserHandle.getAppId(callingUid);
             if (callingAppId >= Process.FIRST_APPLICATION_UID) {
@@ -802,19 +839,45 @@
                 }
             }
             duration = Math.min(duration, mConstants.MAX_TEMP_APP_WHITELIST_DURATION);
-            long currentEndTime = mTempWhitelistAppIdEndTimes.get(appId);
+            Pair<MutableLong, String> entry = mTempWhitelistAppIdEndTimes.get(appId);
+            final boolean newEntry = entry == null;
             // Set the new end time
-            mTempWhitelistAppIdEndTimes.put(appId, timeNow + duration);
+            if (newEntry) {
+                entry = new Pair<>(new MutableLong(0), reason);
+                mTempWhitelistAppIdEndTimes.put(appId, entry);
+            }
+            entry.first.value = timeNow + duration;
             if (DEBUG) {
                 Slog.d(TAG, "Adding AppId " + appId + " to temp whitelist");
             }
-            if (currentEndTime == 0) {
+            if (newEntry) {
                 // No pending timeout for the app id, post a delayed message
+                try {
+                    mBatteryStats.noteEvent(BatteryStats.HistoryItem.EVENT_TEMP_WHITELIST_START,
+                            reason, appId);
+                } catch (RemoteException e) {
+                }
                 postTempActiveTimeoutMessage(appId, duration);
                 updateTempWhitelistAppIdsLocked();
+                if (mNetworkPolicyTempWhitelistCallback != null) {
+                    if (!sync) {
+                        mHandler.post(mNetworkPolicyTempWhitelistCallback);
+                    } else {
+                        networkPolicyTempWhitelistCallback = mNetworkPolicyTempWhitelistCallback;
+                    }
+                }
                 reportTempWhitelistChangedLocked();
             }
         }
+        if (networkPolicyTempWhitelistCallback != null) {
+            networkPolicyTempWhitelistCallback.run();
+        }
+    }
+
+    public void setNetworkPolicyTempWhitelistCallbackInternal(Runnable callback) {
+        synchronized (this) {
+            mNetworkPolicyTempWhitelistCallback = callback;
+        }
     }
 
     private void postTempActiveTimeoutMessage(int uid, long delay) {
@@ -825,21 +888,26 @@
     void checkTempAppWhitelistTimeout(int uid) {
         final long timeNow = SystemClock.elapsedRealtime();
         synchronized (this) {
-            long endTime = mTempWhitelistAppIdEndTimes.get(uid);
-            if (endTime == 0) {
+            Pair<MutableLong, String> entry = mTempWhitelistAppIdEndTimes.get(uid);
+            if (entry == null) {
                 // Nothing to do
                 return;
             }
-            if (timeNow >= endTime) {
+            if (timeNow >= entry.first.value) {
                 mTempWhitelistAppIdEndTimes.delete(uid);
                 if (DEBUG) {
                     Slog.d(TAG, "Removing UID " + uid + " from temp whitelist");
                 }
                 updateTempWhitelistAppIdsLocked();
                 reportTempWhitelistChangedLocked();
+                try {
+                    mBatteryStats.noteEvent(BatteryStats.HistoryItem.EVENT_TEMP_WHITELIST_FINISH,
+                            entry.second, uid);
+                } catch (RemoteException e) {
+                }
             } else {
                 // Need more time
-                postTempActiveTimeoutMessage(uid, endTime - timeNow);
+                postTempActiveTimeoutMessage(uid, entry.first.value - timeNow);
             }
         }
     }
@@ -1101,7 +1169,7 @@
     }
 
     void readConfigFileLocked() {
-        Slog.d(TAG, "Reading config from " + mConfigFile.getBaseFile());
+        if (DEBUG) Slog.d(TAG, "Reading config from " + mConfigFile.getBaseFile());
         mPowerSaveWhitelistUserApps.clear();
         FileInputStream stream;
         try {
@@ -1370,11 +1438,14 @@
                         while (i < args.length) {
                             arg = args[i];
                             i++;
-                            addPowerSaveTempWhitelistAppInternal(0, arg, 10000L, userId);
+                            addPowerSaveTempWhitelistAppInternal(0, arg, 10000L, userId, true,
+                                    "shell");
+                            pw.println("Added: " + arg);
                         }
                     } finally {
                         Binder.restoreCallingIdentity(token);
                     }
+                    return;
                 } else if (arg.length() > 0 && arg.charAt(0) == '-'){
                     pw.println("Unknown option: " + arg);
                     return;
@@ -1421,8 +1492,10 @@
                     pw.print("    UID=");
                     pw.print(mTempWhitelistAppIdEndTimes.keyAt(i));
                     pw.print(": ");
-                    TimeUtils.formatDuration(mTempWhitelistAppIdEndTimes.valueAt(i), timeNow, pw);
-                    pw.println();
+                    Pair<MutableLong, String> entry = mTempWhitelistAppIdEndTimes.valueAt(i);
+                    TimeUtils.formatDuration(entry.first.value, timeNow, pw);
+                    pw.print(" - ");
+                    pw.println(entry.second);
                 }
             }
             size = mTempWhitelistAppIdArray != null ? mTempWhitelistAppIdArray.length : 0;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 5bfca10..37aa408 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -6355,7 +6355,7 @@
                                     }
                                 },
                                 0, null, null,
-                                android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
+                                new String[] {android.Manifest.permission.RECEIVE_BOOT_COMPLETED},
                                 AppOpsManager.OP_NONE, null, true, false,
                                 MY_PID, Process.SYSTEM_UID, userId);
                     }
@@ -11773,7 +11773,7 @@
                                     throws RemoteException {
                             }
                         }, 0, null, null,
-                        INTERACT_ACROSS_USERS, AppOpsManager.OP_NONE,
+                        new String[] {INTERACT_ACROSS_USERS}, AppOpsManager.OP_NONE,
                         null, true, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
             } catch (Throwable t) {
                 Slog.wtf(TAG, "Failed sending first user broadcasts", t);
@@ -16327,7 +16327,7 @@
     private final int broadcastIntentLocked(ProcessRecord callerApp,
             String callerPackage, Intent intent, String resolvedType,
             IIntentReceiver resultTo, int resultCode, String resultData,
-            Bundle resultExtras, String requiredPermission, int appOp, Bundle options,
+            Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle options,
             boolean ordered, boolean sticky, int callingPid, int callingUid, int userId) {
         intent = new Intent(intent);
 
@@ -16580,9 +16580,9 @@
                 Slog.w(TAG, msg);
                 throw new SecurityException(msg);
             }
-            if (requiredPermission != null) {
+            if (requiredPermissions != null && requiredPermissions.length > 0) {
                 Slog.w(TAG, "Can't broadcast sticky intent " + intent
-                        + " and enforce permission " + requiredPermission);
+                        + " and enforce permissions " + Arrays.toString(requiredPermissions));
                 return ActivityManager.BROADCAST_STICKY_CANT_HAVE_PERMISSION;
             }
             if (intent.getComponent() != null) {
@@ -16690,7 +16690,7 @@
             // components to be launched.
             final BroadcastQueue queue = broadcastQueueForIntent(intent);
             BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
-                    callerPackage, callingPid, callingUid, resolvedType, requiredPermission,
+                    callerPackage, callingPid, callingUid, resolvedType, requiredPermissions,
                     appOp, brOptions, registeredReceivers, resultTo, resultCode, resultData,
                     resultExtras, ordered, sticky, false, userId);
             if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing parallel broadcast " + r);
@@ -16780,7 +16780,7 @@
             BroadcastQueue queue = broadcastQueueForIntent(intent);
             BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
                     callerPackage, callingPid, callingUid, resolvedType,
-                    requiredPermission, appOp, brOptions, receivers, resultTo, resultCode,
+                    requiredPermissions, appOp, brOptions, receivers, resultTo, resultCode,
                     resultData, resultExtras, ordered, sticky, false, userId);
 
             if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing ordered broadcast " + r
@@ -16829,7 +16829,7 @@
     public final int broadcastIntent(IApplicationThread caller,
             Intent intent, String resolvedType, IIntentReceiver resultTo,
             int resultCode, String resultData, Bundle resultExtras,
-            String requiredPermission, int appOp, Bundle options,
+            String[] requiredPermissions, int appOp, Bundle options,
             boolean serialized, boolean sticky, int userId) {
         enforceNotIsolatedCaller("broadcastIntent");
         synchronized(this) {
@@ -16842,13 +16842,14 @@
             int res = broadcastIntentLocked(callerApp,
                     callerApp != null ? callerApp.info.packageName : null,
                     intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
-                    requiredPermission, appOp, null, serialized, sticky,
+                    requiredPermissions, appOp, null, serialized, sticky,
                     callingPid, callingUid, userId);
             Binder.restoreCallingIdentity(origId);
             return res;
         }
     }
 
+
     int broadcastIntentInPackage(String packageName, int uid,
             Intent intent, String resolvedType, IIntentReceiver resultTo,
             int resultCode, String resultData, Bundle resultExtras,
@@ -16858,9 +16859,12 @@
             intent = verifyBroadcastLocked(intent);
 
             final long origId = Binder.clearCallingIdentity();
+            String[] requiredPermissions = requiredPermission == null ? null
+                    : new String[] {requiredPermission};
             int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
-                    resultTo, resultCode, resultData, resultExtras, requiredPermission,
-                    AppOpsManager.OP_NONE, options, serialized, sticky, -1, uid, userId);
+                    resultTo, resultCode, resultData, resultExtras,
+                    requiredPermissions, AppOpsManager.OP_NONE, options, serialized,
+                    sticky, -1, uid, userId);
             Binder.restoreCallingIdentity(origId);
             return res;
         }
@@ -19795,7 +19799,7 @@
                                         int sendingUser) throws RemoteException {
                                 }
                             }, 0, null, null,
-                            INTERACT_ACROSS_USERS, AppOpsManager.OP_NONE,
+                            new String[] {INTERACT_ACROSS_USERS}, AppOpsManager.OP_NONE,
                             null, true, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
                 }
             }
@@ -19857,8 +19861,9 @@
                 intent.putExtra(Intent.EXTRA_USER_HANDLE, newUserId);
                 broadcastIntentLocked(null, null, intent,
                         null, null, 0, null, null,
-                        android.Manifest.permission.MANAGE_USERS, AppOpsManager.OP_NONE,
-                        null, false, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
+                        new String[] {android.Manifest.permission.MANAGE_USERS},
+                        AppOpsManager.OP_NONE, null, false, false, MY_PID, Process.SYSTEM_UID,
+                        UserHandle.USER_ALL);
             }
         } finally {
             Binder.restoreCallingIdentity(ident);
@@ -20041,8 +20046,9 @@
                 intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT);
                 broadcastIntentLocked(null, null, intent,
                         null, null, 0, null, null,
-                        android.Manifest.permission.RECEIVE_BOOT_COMPLETED, AppOpsManager.OP_NONE,
-                        null, true, false, MY_PID, Process.SYSTEM_UID, userId);
+                        new String[] {android.Manifest.permission.RECEIVE_BOOT_COMPLETED},
+                        AppOpsManager.OP_NONE, null, true, false, MY_PID, Process.SYSTEM_UID,
+                        userId);
             }
         }
     }
@@ -20180,7 +20186,7 @@
                 // Kick things off.
                 broadcastIntentLocked(null, null, stoppingIntent,
                         null, stoppingReceiver, 0, null, null,
-                        INTERACT_ACROSS_USERS, AppOpsManager.OP_NONE,
+                        new String[] {INTERACT_ACROSS_USERS}, AppOpsManager.OP_NONE,
                         null, true, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
             } finally {
                 Binder.restoreCallingIdentity(ident);
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 070813b..13b75ab 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -101,8 +101,12 @@
                         mUpdateFlags = 0;
                     }
                     updateExternalStats((String)msg.obj, updateFlags);
-                    synchronized (this) {
-                        synchronized (mStats) {
+
+                    // other parts of the system could be calling into us
+                    // from mStats in order to report of changes. We must grab the mStats
+                    // lock before grabbing our own or we'll end up in a deadlock.
+                    synchronized (mStats) {
+                        synchronized (this) {
                             final int numUidsToRemove = mUidsToRemove.size();
                             for (int i = 0; i < numUidsToRemove; i++) {
                                 mStats.removeIsolatedUidLocked(mUidsToRemove.get(i));
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 30aa411..91d97ef 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -175,7 +175,7 @@
                     DeviceIdleController.LocalService dic = mService.mLocalDeviceIdleController;
                     if (dic != null) {
                         dic.addPowerSaveTempWhitelistAppDirect(UserHandle.getAppId(msg.arg1),
-                                msg.arg2);
+                                msg.arg2, true, (String)msg.obj);
                     }
                 } break;
             }
@@ -493,59 +493,74 @@
                 }
             }
         }
-        if (!skip) {
-            int perm = mService.checkComponentPermission(r.requiredPermission,
+        if (!skip && r.requiredPermissions != null && r.requiredPermissions.length > 0) {
+            for (int i = 0; i < r.requiredPermissions.length; i++) {
+                String requiredPermission = r.requiredPermissions[i];
+                int perm = mService.checkComponentPermission(requiredPermission,
+                        filter.receiverList.pid, filter.receiverList.uid, -1, true);
+                if (perm != PackageManager.PERMISSION_GRANTED) {
+                    Slog.w(TAG, "Permission Denial: receiving "
+                            + r.intent.toString()
+                            + " to " + filter.receiverList.app
+                            + " (pid=" + filter.receiverList.pid
+                            + ", uid=" + filter.receiverList.uid + ")"
+                            + " requires " + requiredPermission
+                            + " due to sender " + r.callerPackage
+                            + " (uid " + r.callingUid + ")");
+                    skip = true;
+                    break;
+                }
+                int appOp = AppOpsManager.permissionToOpCode(requiredPermission);
+                if (appOp != r.appOp
+                        && mService.mAppOpsService.noteOperation(appOp,
+                        filter.receiverList.uid, filter.packageName)
+                        != AppOpsManager.MODE_ALLOWED) {
+                    Slog.w(TAG, "Appop Denial: receiving "
+                            + r.intent.toString()
+                            + " to " + filter.receiverList.app
+                            + " (pid=" + filter.receiverList.pid
+                            + ", uid=" + filter.receiverList.uid + ")"
+                            + " requires appop " + AppOpsManager.permissionToOp(
+                            requiredPermission)
+                            + " due to sender " + r.callerPackage
+                            + " (uid " + r.callingUid + ")");
+                    skip = true;
+                    break;
+                }
+            }
+        }
+        if (!skip && (r.requiredPermissions == null || r.requiredPermissions.length == 0)) {
+            int perm = mService.checkComponentPermission(null,
                     filter.receiverList.pid, filter.receiverList.uid, -1, true);
             if (perm != PackageManager.PERMISSION_GRANTED) {
-                Slog.w(TAG, "Permission Denial: receiving "
+                Slog.w(TAG, "Permission Denial: security check failed when receiving "
                         + r.intent.toString()
                         + " to " + filter.receiverList.app
                         + " (pid=" + filter.receiverList.pid
                         + ", uid=" + filter.receiverList.uid + ")"
-                        + " requires " + r.requiredPermission
                         + " due to sender " + r.callerPackage
                         + " (uid " + r.callingUid + ")");
                 skip = true;
             }
-            int appOp = AppOpsManager.OP_NONE;
-            if (r.requiredPermission != null) {
-                appOp = AppOpsManager.permissionToOpCode(r.requiredPermission);
-                if (appOp != AppOpsManager.OP_NONE
-                        && mService.mAppOpsService.noteOperation(appOp,
-                            filter.receiverList.uid, filter.packageName)
-                                != AppOpsManager.MODE_ALLOWED) {
-                    Slog.w(TAG, "Appop Denial: receiving "
-                            + r.intent.toString()
-                            + " to " + filter.receiverList.app
-                            + " (pid=" + filter.receiverList.pid
-                            + ", uid=" + filter.receiverList.uid + ")"
-                            + " requires appop " + AppOpsManager.permissionToOp(
-                                    r.requiredPermission)
-                            + " due to sender " + r.callerPackage
-                            + " (uid " + r.callingUid + ")");
-                    skip = true;
-                }
-            }
-            if (!skip && r.appOp != appOp && r.appOp != AppOpsManager.OP_NONE
-                    && mService.mAppOpsService.noteOperation(r.appOp,
-                            filter.receiverList.uid, filter.packageName)
-                                    != AppOpsManager.MODE_ALLOWED) {
-                    Slog.w(TAG, "Appop Denial: receiving "
-                            + r.intent.toString()
-                            + " to " + filter.receiverList.app
-                            + " (pid=" + filter.receiverList.pid
-                            + ", uid=" + filter.receiverList.uid + ")"
-                            + " requires appop " + AppOpsManager.permissionToOp(
-                            r.requiredPermission)
-                            + " due to sender " + r.callerPackage
-                            + " (uid " + r.callingUid + ")");
-                    skip = true;
-            }
+        }
+        if (!skip && r.appOp != AppOpsManager.OP_NONE
+                && mService.mAppOpsService.noteOperation(r.appOp,
+                filter.receiverList.uid, filter.packageName)
+                != AppOpsManager.MODE_ALLOWED) {
+            Slog.w(TAG, "Appop Denial: receiving "
+                    + r.intent.toString()
+                    + " to " + filter.receiverList.app
+                    + " (pid=" + filter.receiverList.pid
+                    + ", uid=" + filter.receiverList.uid + ")"
+                    + " requires appop " + AppOpsManager.opToName(r.appOp)
+                    + " due to sender " + r.callerPackage
+                    + " (uid " + r.callingUid + ")");
+            skip = true;
         }
 
-        if (!skip) {
-            skip = !mService.mIntentFirewall.checkBroadcast(r.intent, r.callingUid,
-                    r.callingPid, r.resolvedType, filter.receiverList.uid);
+        if (!mService.mIntentFirewall.checkBroadcast(r.intent, r.callingUid,
+                r.callingPid, r.resolvedType, filter.receiverList.uid)) {
+            return;
         }
 
         if (filter.receiverList.app == null || filter.receiverList.app.crashing) {
@@ -597,7 +612,7 @@
         }
     }
 
-    final void scheduleTempWhitelistLocked(int uid, long duration) {
+    final void scheduleTempWhitelistLocked(int uid, long duration, BroadcastRecord r) {
         if (duration > Integer.MAX_VALUE) {
             duration = Integer.MAX_VALUE;
         }
@@ -607,7 +622,19 @@
         // not that big a deal, however, because the main purpose here is to allow apps
         // to hold wake locks, and they will be able to acquire their wake lock immediately
         // it just won't be enabled until we get through this work.
-        mHandler.obtainMessage(SCHEDULE_TEMP_WHITELIST_MSG, uid, (int)duration).sendToTarget();
+        StringBuilder b = new StringBuilder();
+        b.append("broadcast:");
+        UserHandle.formatUid(b, r.callingUid);
+        b.append(":");
+        if (r.intent.getAction() != null) {
+            b.append(r.intent.getAction());
+        } else if (r.intent.getComponent() != null) {
+            b.append(r.intent.getComponent().flattenToShortString());
+        } else if (r.intent.getData() != null) {
+            b.append(r.intent.getData());
+        }
+        mHandler.obtainMessage(SCHEDULE_TEMP_WHITELIST_MSG, uid, (int)duration, b.toString())
+                .sendToTarget();
     }
 
     final void processNextBroadcast(boolean fromMsg) {
@@ -807,7 +834,7 @@
                 } else {
                     if (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0) {
                         scheduleTempWhitelistLocked(filter.owningUid,
-                                brOptions.getTemporaryAppWhitelistDuration());
+                                brOptions.getTemporaryAppWhitelistDuration(), r);
                     }
                 }
                 return;
@@ -860,51 +887,53 @@
                 }
             }
             if (!skip && info.activityInfo.applicationInfo.uid != Process.SYSTEM_UID &&
-                r.requiredPermission != null) {
-                try {
-                    perm = AppGlobals.getPackageManager().
-                            checkPermission(r.requiredPermission,
-                                    info.activityInfo.applicationInfo.packageName,
-                                    UserHandle.getUserId(info.activityInfo.applicationInfo.uid));
-                } catch (RemoteException e) {
-                    perm = PackageManager.PERMISSION_DENIED;
-                }
-                if (perm != PackageManager.PERMISSION_GRANTED) {
-                    Slog.w(TAG, "Permission Denial: receiving "
-                            + r.intent + " to "
-                            + component.flattenToShortString()
-                            + " requires " + r.requiredPermission
-                            + " due to sender " + r.callerPackage
-                            + " (uid " + r.callingUid + ")");
-                    skip = true;
-                }
-            }
-            int appOp = AppOpsManager.OP_NONE;
-            if (!skip && r.requiredPermission != null) {
-                appOp = AppOpsManager.permissionToOpCode(r.requiredPermission);
-                if (appOp != AppOpsManager.OP_NONE
-                        && mService.mAppOpsService.noteOperation(appOp,
-                               info.activityInfo.applicationInfo.uid, info.activityInfo.packageName)
-                                        != AppOpsManager.MODE_ALLOWED) {
-                    Slog.w(TAG, "Appop Denial: receiving "
-                            + r.intent + " to "
-                            + component.flattenToShortString()
-                            + " requires appop " + AppOpsManager.permissionToOp(
-                            r.requiredPermission)
-                            + " due to sender " + r.callerPackage
-                            + " (uid " + r.callingUid + ")");
-                    skip = true;
-                }
-            }
-            if (!skip && r.appOp != appOp && r.appOp != AppOpsManager.OP_NONE
-                    && mService.mAppOpsService.noteOperation(r.appOp,
+                r.requiredPermissions != null && r.requiredPermissions.length > 0) {
+                for (int i = 0; i < r.requiredPermissions.length; i++) {
+                    String requiredPermission = r.requiredPermissions[i];
+                    try {
+                        perm = AppGlobals.getPackageManager().
+                                checkPermission(requiredPermission,
+                                        info.activityInfo.applicationInfo.packageName,
+                                        UserHandle
+                                                .getUserId(info.activityInfo.applicationInfo.uid));
+                    } catch (RemoteException e) {
+                        perm = PackageManager.PERMISSION_DENIED;
+                    }
+                    if (perm != PackageManager.PERMISSION_GRANTED) {
+                        Slog.w(TAG, "Permission Denial: receiving "
+                                + r.intent + " to "
+                                + component.flattenToShortString()
+                                + " requires " + requiredPermission
+                                + " due to sender " + r.callerPackage
+                                + " (uid " + r.callingUid + ")");
+                        skip = true;
+                        break;
+                    }
+                    int appOp = AppOpsManager.permissionToOpCode(requiredPermission);
+                    if (appOp != AppOpsManager.OP_NONE && appOp != r.appOp
+                            && mService.mAppOpsService.noteOperation(appOp,
                             info.activityInfo.applicationInfo.uid, info.activityInfo.packageName)
-                                    != AppOpsManager.MODE_ALLOWED) {
+                            != AppOpsManager.MODE_ALLOWED) {
+                        Slog.w(TAG, "Appop Denial: receiving "
+                                + r.intent + " to "
+                                + component.flattenToShortString()
+                                + " requires appop " + AppOpsManager.permissionToOp(
+                                requiredPermission)
+                                + " due to sender " + r.callerPackage
+                                + " (uid " + r.callingUid + ")");
+                        skip = true;
+                        break;
+                    }
+                }
+            }
+            if (!skip && r.appOp != AppOpsManager.OP_NONE
+                    && mService.mAppOpsService.noteOperation(r.appOp,
+                    info.activityInfo.applicationInfo.uid, info.activityInfo.packageName)
+                    != AppOpsManager.MODE_ALLOWED) {
                 Slog.w(TAG, "Appop Denial: receiving "
                         + r.intent + " to "
                         + component.flattenToShortString()
-                        + " requires appop " + AppOpsManager.permissionToOp(
-                        r.requiredPermission)
+                        + " requires appop " + AppOpsManager.opToName(r.appOp)
                         + " due to sender " + r.callerPackage
                         + " (uid " + r.callingUid + ")");
                 skip = true;
@@ -988,7 +1017,7 @@
 
             if (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0) {
                 scheduleTempWhitelistLocked(receiverUid,
-                        brOptions.getTemporaryAppWhitelistDuration());
+                        brOptions.getTemporaryAppWhitelistDuration(), r);
             }
 
             // Broadcast is being executed, its package can't be stopped.
diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java
index b943222..a7e6471 100644
--- a/services/core/java/com/android/server/am/BroadcastRecord.java
+++ b/services/core/java/com/android/server/am/BroadcastRecord.java
@@ -32,6 +32,7 @@
 import android.util.TimeUtils;
 
 import java.io.PrintWriter;
+import java.util.Arrays;
 import java.util.Date;
 import java.util.List;
 import java.util.Set;
@@ -51,7 +52,7 @@
     final boolean initialSticky; // initial broadcast from register to sticky?
     final int userId;       // user id this broadcast was for
     final String resolvedType; // the resolved data type
-    final String requiredPermission; // a permission the caller has required
+    final String[] requiredPermissions; // permissions the caller has required
     final int appOp;        // an app op that is associated with this broadcast
     final BroadcastOptions options; // BroadcastOptions supplied by caller
     final List receivers;   // contains BroadcastFilter and ResolveInfo
@@ -103,9 +104,11 @@
                 pw.print(callerApp != null ? callerApp.toShortString() : "null");
                 pw.print(" pid="); pw.print(callingPid);
                 pw.print(" uid="); pw.println(callingUid);
-        if (requiredPermission != null || appOp != AppOpsManager.OP_NONE) {
-            pw.print(prefix); pw.print("requiredPermission="); pw.print(requiredPermission);
-                    pw.print("  appOp="); pw.println(appOp);
+        if ((requiredPermissions != null && requiredPermissions.length > 0)
+                || appOp != AppOpsManager.OP_NONE) {
+            pw.print(prefix); pw.print("requiredPermissions=");
+            pw.print(Arrays.toString(requiredPermissions));
+            pw.print("  appOp="); pw.println(appOp);
         }
         if (options != null) {
             pw.print(prefix); pw.print("options="); pw.println(options.toBundle());
@@ -184,7 +187,7 @@
 
     BroadcastRecord(BroadcastQueue _queue,
             Intent _intent, ProcessRecord _callerApp, String _callerPackage,
-            int _callingPid, int _callingUid, String _resolvedType, String _requiredPermission,
+            int _callingPid, int _callingUid, String _resolvedType, String[] _requiredPermissions,
             int _appOp, BroadcastOptions _options, List _receivers, IIntentReceiver _resultTo,
             int _resultCode, String _resultData, Bundle _resultExtras, boolean _serialized,
             boolean _sticky, boolean _initialSticky,
@@ -197,7 +200,7 @@
         callingPid = _callingPid;
         callingUid = _callingUid;
         resolvedType = _resolvedType;
-        requiredPermission = _requiredPermission;
+        requiredPermissions = _requiredPermissions;
         appOp = _appOp;
         options = _options;
         receivers = _receivers;
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index f8f00ef..395aa27 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -147,6 +147,7 @@
 import android.util.TrustedTime;
 import android.util.Xml;
 
+import com.android.server.DeviceIdleController;
 import com.android.server.EventLogTags;
 import libcore.io.IoUtils;
 
@@ -462,9 +463,12 @@
         // listen for changes to power save whitelist
         final IntentFilter whitelistFilter = new IntentFilter(
                 PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED);
-        whitelistFilter.addAction(PowerManager.ACTION_POWER_SAVE_TEMP_WHITELIST_CHANGED);
         mContext.registerReceiver(mPowerSaveWhitelistReceiver, whitelistFilter, null, mHandler);
 
+        DeviceIdleController.LocalService deviceIdleService
+                = LocalServices.getService(DeviceIdleController.LocalService.class);
+        deviceIdleService.setNetworkPolicyTempWhitelistCallback(mTempPowerSaveChangedCallback);
+
         // watch for network interfaces to be claimed
         final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION);
         mContext.registerReceiver(mConnReceiver, connFilter, CONNECTIVITY_INTERNAL, mHandler);
@@ -512,7 +516,7 @@
 
     }
 
-    private IUidObserver mUidObserver = new IUidObserver.Stub() {
+    final private IUidObserver mUidObserver = new IUidObserver.Stub() {
         @Override public void onUidStateChanged(int uid, int procState) throws RemoteException {
             synchronized (mRulesLock) {
                 updateUidStateLocked(uid, procState);
@@ -526,24 +530,29 @@
         }
     };
 
-    private BroadcastReceiver mPowerSaveWhitelistReceiver = new BroadcastReceiver() {
+    final private BroadcastReceiver mPowerSaveWhitelistReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
             // on background handler thread, and POWER_SAVE_WHITELIST_CHANGED is protected
             synchronized (mRulesLock) {
-                if (PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED.equals(intent.getAction())) {
-                    updatePowerSaveWhitelistLocked();
-                    updateRulesForGlobalChangeLocked(false);
-                } else {
-                    updatePowerSaveTempWhitelistLocked();
-                    updateRulesForTempWhitelistChangeLocked();
-                    purgePowerSaveTempWhitelistLocked();
-                }
+                updatePowerSaveWhitelistLocked();
+                updateRulesForGlobalChangeLocked(false);
             }
         }
     };
 
-    private BroadcastReceiver mScreenReceiver = new BroadcastReceiver() {
+    final private Runnable mTempPowerSaveChangedCallback = new Runnable() {
+        @Override
+        public void run() {
+            synchronized (mRulesLock) {
+                updatePowerSaveTempWhitelistLocked();
+                updateRulesForTempWhitelistChangeLocked();
+                purgePowerSaveTempWhitelistLocked();
+            }
+        }
+    };
+
+    final private BroadcastReceiver mScreenReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
             // screen-related broadcasts are protected by system, no need
@@ -552,7 +561,7 @@
         }
     };
 
-    private BroadcastReceiver mPackageReceiver = new BroadcastReceiver() {
+    final private BroadcastReceiver mPackageReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
             // on background handler thread, and PACKAGE_ADDED is protected
@@ -572,7 +581,7 @@
         }
     };
 
-    private BroadcastReceiver mUidRemovedReceiver = new BroadcastReceiver() {
+    final private BroadcastReceiver mUidRemovedReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
             // on background handler thread, and UID_REMOVED is protected
@@ -590,7 +599,7 @@
         }
     };
 
-    private BroadcastReceiver mUserReceiver = new BroadcastReceiver() {
+    final private BroadcastReceiver mUserReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
             // on background handler thread, and USER_ADDED and USER_REMOVED
@@ -619,7 +628,7 @@
      * Receiver that watches for {@link INetworkStatsService} updates, which we
      * use to check against {@link NetworkPolicy#warningBytes}.
      */
-    private BroadcastReceiver mStatsReceiver = new BroadcastReceiver() {
+    final private BroadcastReceiver mStatsReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
             // on background handler thread, and verified
@@ -637,7 +646,7 @@
      * Receiver that watches for {@link Notification} control of
      * {@link #mRestrictBackground}.
      */
-    private BroadcastReceiver mAllowReceiver = new BroadcastReceiver() {
+    final private BroadcastReceiver mAllowReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
             // on background handler thread, and verified MANAGE_NETWORK_POLICY
@@ -651,7 +660,7 @@
      * Receiver that watches for {@link Notification} control of
      * {@link NetworkPolicy#lastWarningSnooze}.
      */
-    private BroadcastReceiver mSnoozeWarningReceiver = new BroadcastReceiver() {
+    final private BroadcastReceiver mSnoozeWarningReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
             // on background handler thread, and verified MANAGE_NETWORK_POLICY
@@ -665,7 +674,7 @@
     /**
      * Receiver that watches for {@link WifiConfiguration} to be changed.
      */
-    private BroadcastReceiver mWifiConfigReceiver = new BroadcastReceiver() {
+    final private BroadcastReceiver mWifiConfigReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
             // on background handler thread, and verified CONNECTIVITY_INTERNAL
@@ -692,7 +701,7 @@
      * Receiver that watches {@link WifiInfo} state changes to infer metered
      * state. Ignores hints when policy is user-defined.
      */
-    private BroadcastReceiver mWifiStateReceiver = new BroadcastReceiver() {
+    final private BroadcastReceiver mWifiStateReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
             // on background handler thread, and verified CONNECTIVITY_INTERNAL
@@ -732,7 +741,8 @@
     /**
      * Observer that watches for {@link INetworkManagementService} alerts.
      */
-    private INetworkManagementEventObserver mAlertObserver = new BaseNetworkObserver() {
+    final private INetworkManagementEventObserver mAlertObserver
+            = new BaseNetworkObserver() {
         @Override
         public void limitReached(String limitName, String iface) {
             // only someone like NMS should be calling us
@@ -1985,6 +1995,10 @@
             // state changed, push updated rules
             mUidState.put(uid, uidState);
             updateRulesForUidStateChangeLocked(uid, oldUidState, uidState);
+            if (mDeviceIdleMode && isProcStateAllowedWhileIdle(oldUidState)
+                    != isProcStateAllowedWhileIdle(uidState)) {
+                updateRulesForDeviceIdleLocked();
+            }
         }
     }
 
@@ -1996,6 +2010,9 @@
             if (oldUidState != ActivityManager.PROCESS_STATE_CACHED_EMPTY) {
                 updateRulesForUidStateChangeLocked(uid, oldUidState,
                         ActivityManager.PROCESS_STATE_CACHED_EMPTY);
+                if (mDeviceIdleMode) {
+                    updateRulesForDeviceIdleLocked();
+                }
             }
         }
     }
@@ -2033,13 +2050,18 @@
         }
     }
 
+    static boolean isProcStateAllowedWhileIdle(int procState) {
+        return procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
+    }
+
     void updateRulesForDeviceIdleLocked() {
         if (mDeviceIdleMode) {
             // sync the whitelists before enable dozable chain.  We don't care about the rules if
             // we are disabling the chain.
             SparseIntArray uidRules = new SparseIntArray();
             final List<UserInfo> users = mUserManager.getUsers();
-            for (UserInfo user : users) {
+            for (int ui = users.size() - 1; ui >= 0; ui--) {
+                UserInfo user = users.get(ui);
                 for (int i = mPowerSaveTempWhitelistAppIds.size() - 1; i >= 0; i--) {
                     int appId = mPowerSaveTempWhitelistAppIds.keyAt(i);
                     int uid = UserHandle.getUid(user.id, appId);
@@ -2051,6 +2073,11 @@
                     uidRules.put(uid, FIREWALL_RULE_ALLOW);
                 }
             }
+            for (int i = mUidState.size() - 1; i >= 0; i--) {
+                if (isProcStateAllowedWhileIdle(mUidState.valueAt(i))) {
+                    uidRules.put(mUidState.keyAt(i), FIREWALL_RULE_ALLOW);
+                }
+            }
             setUidFirewallRules(FIREWALL_CHAIN_DOZABLE, uidRules);
         }
         enableFirewallChainLocked(FIREWALL_CHAIN_DOZABLE, mDeviceIdleMode);
diff --git a/services/tests/servicestests/src/com/android/server/BroadcastInterceptingContext.java b/services/tests/servicestests/src/com/android/server/BroadcastInterceptingContext.java
index ffd1568..757f1c6 100644
--- a/services/tests/servicestests/src/com/android/server/BroadcastInterceptingContext.java
+++ b/services/tests/servicestests/src/com/android/server/BroadcastInterceptingContext.java
@@ -139,6 +139,11 @@
     }
 
     @Override
+    public void sendBroadcastMultiplePermissions(Intent intent, String[] receiverPermissions) {
+        sendBroadcast(intent);
+    }
+
+    @Override
     public void sendBroadcastAsUser(Intent intent, UserHandle user) {
         sendBroadcast(intent);
     }
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index c49a5f9..b0a14c8 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -1177,7 +1177,11 @@
         @Override
         public void whitelistAppTemporarily(String packageName, long duration, int userId)
                 throws RemoteException {
-            mDeviceIdleController.addPowerSaveTempWhitelistApp(packageName, duration, userId);
+            StringBuilder reason = new StringBuilder(32);
+            reason.append("from:");
+            UserHandle.formatUid(reason, Binder.getCallingUid());
+            mDeviceIdleController.addPowerSaveTempWhitelistApp(packageName, duration, userId,
+                    reason.toString());
         }
 
         @Override
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index f304d1d..58fb088 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -1231,17 +1231,17 @@
     public static String stateToString(int state) {
         switch (state) {
             case STATE_INITIALIZING:
-                return "STATE_INITIALIZING";
+                return "INITIALIZING";
             case STATE_NEW:
-                return "STATE_NEW";
+                return "NEW";
             case STATE_RINGING:
-                return "STATE_RINGING";
+                return "RINGING";
             case STATE_DIALING:
-                return "STATE_DIALING";
+                return "DIALING";
             case STATE_ACTIVE:
-                return "STATE_ACTIVE";
+                return "ACTIVE";
             case STATE_HOLDING:
-                return "STATE_HOLDING";
+                return "HOLDING";
             case STATE_DISCONNECTED:
                 return "DISCONNECTED";
             default:
diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java
index e5e3e44..e09d124 100644
--- a/test-runner/src/android/test/mock/MockContext.java
+++ b/test-runner/src/android/test/mock/MockContext.java
@@ -318,6 +318,12 @@
     }
 
     /** @hide */
+    @Override
+    public void sendBroadcastMultiplePermissions(Intent intent, String[] receiverPermissions) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
     @SystemApi
     @Override
     public void sendBroadcast(Intent intent, String receiverPermission, Bundle options) {
@@ -389,13 +395,19 @@
     @Override
     public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
             String receiverPermission, int appOp, BroadcastReceiver resultReceiver,
-            Handler scheduler,
-            int initialCode, String initialData, Bundle initialExtras) {
+            Handler scheduler, int initialCode, String initialData, Bundle initialExtras) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
+            String receiverPermission, int appOp, Bundle options, BroadcastReceiver resultReceiver,
+            Handler scheduler, int initialCode, String initialData, Bundle initialExtras) {
         throw new UnsupportedOperationException();
     }
 
     @Override
-
     public void sendStickyBroadcast(Intent intent) {
         throw new UnsupportedOperationException();
     }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index 362048d..1f3802e 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -1509,6 +1509,12 @@
     }
 
     @Override
+    public void sendBroadcastMultiplePermissions(Intent intent, String[] receiverPermissions) {
+        // pass
+
+    }
+
+    @Override
     public void sendBroadcast(Intent arg0, String arg1, Bundle arg2) {
         // pass
 
@@ -1580,6 +1586,14 @@
     }
 
     @Override
+    public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
+            String receiverPermission, int appOp, Bundle options, BroadcastReceiver resultReceiver,
+            Handler scheduler,
+            int initialCode, String initialData, Bundle initialExtras) {
+        // pass
+    }
+
+    @Override
     public void sendStickyBroadcast(Intent arg0) {
         // pass
 
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index e5a1d02..f91e0e2 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -206,6 +206,16 @@
      * @hide
      */
     public static final String EXTRA_WIFI_AP_STATE = "wifi_state";
+
+    /**
+     * The look up key for an int that indicates why softAP started failed
+     * currently support general and no_channel
+     * @see #SAP_START_FAILURE_GENERAL
+     * @see #SAP_START_FAILURE_NO_CHANNEL
+     *
+     * @hide
+     */
+    public static final String EXTRA_WIFI_AP_FAILURE_REASON = "wifi_ap_error_code";
     /**
      * The previous Wi-Fi state.
      *
@@ -264,6 +274,20 @@
     public static final int WIFI_AP_STATE_FAILED = 14;
 
     /**
+     *  If WIFI AP start failed, this reason code means there is no legal channel exists on
+     *  user selected band by regulatory
+     *
+     *  @hide
+     */
+    public static final int SAP_START_FAILURE_GENERAL= 0;
+
+    /**
+     *  All other reason for AP start failed besides SAP_START_FAILURE_GENERAL
+     *
+     *  @hide
+     */
+    public static final int SAP_START_FAILURE_NO_CHANNEL = 1;
+    /**
      * Broadcast intent action indicating that a connection to the supplicant has
      * been established (and it is now possible
      * to perform Wi-Fi operations) or the connection to the supplicant has been