Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a1b79bfd authored by Felipe Leme's avatar Felipe Leme
Browse files

Allow apps to bypass Power Save restrictions when launched from a Notification's PendingIntent.

This scenario typically happens when the device is on Doze Mode and a
notification action is triggered from a Wear device.

In a nutshell, the workflow is:

- ProcessRecord has a flag telling whether a process has "whitelist
  management" privileges.
- When NotificationManager binds a new NotificationListenerService, it
  sets the BIND_ALLOW_WHITELIST_MANAGEMENT flag.
- On bind(), ActiveService asserts that only system apps can set that
  flag.
- On computeOomAdjLocked(), ActivityManagerService sets the
  ProcessRecord flag if necessary.
- Upon creating a notification, NotificationManager calls AM to mark its
  PendingIntents as coming from a notification.
- When PendingIntentRecord sends it to the target, it checks if it's
  from a notification and if so calls AM to do the temp whitelist.
- On unbind(), ActiveService removes the ProcessRecord flag if necessary.

Fixes: 28818704

Change-Id: I00d46036a2cbb73f7f733fd35bf0b743a02807a1
parent bd34103c
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package android.app;

import android.annotation.NonNull;
import android.content.ComponentName;
import android.content.IIntentSender;
import android.os.IBinder;
import android.service.voice.IVoiceInteractionSession;

@@ -144,4 +145,10 @@ public abstract class ActivityManagerInternal {
     * Kill foreground apps from the specified user.
     */
    public abstract void killForegroundAppsForUser(int userHandle);

    /**
     *  Sets how long a {@link PendingIntent} can be temporarily whitelist to by bypass restrictions
     *  such as Power Save mode.
     */
    public abstract void setPendingIntentWhitelistDuration(IIntentSender target, long duration);
}
+4 −2
Original line number Diff line number Diff line
@@ -6966,8 +6966,8 @@ class ActivityManagerProxy implements IActivityManager
        reply.recycle();
    }

    public void notifyLockedProfile(@UserIdInt int userId) throws RemoteException
    {
    @Override
    public void notifyLockedProfile(@UserIdInt int userId) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IActivityManager.descriptor);
@@ -6978,6 +6978,7 @@ class ActivityManagerProxy implements IActivityManager
        reply.recycle();
    }

    @Override
    public void startConfirmDeviceCredentialIntent(Intent intent) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
@@ -6989,6 +6990,7 @@ class ActivityManagerProxy implements IActivityManager
        reply.recycle();
    }

    @Override
    public int sendIntentSender(IIntentSender target, int code, Intent intent, String resolvedType,
            IIntentReceiver finishedReceiver, String requiredPermission, Bundle options)
            throws RemoteException {
+6 −0
Original line number Diff line number Diff line
@@ -284,6 +284,12 @@ public abstract class Context {
     */
    public static final int BIND_ADJUST_WITH_ACTIVITY = 0x0080;

    /**
     * @hide Flag for {@link #bindService}: allows application hosting service to manage whitelists
     * such as temporary allowing a {@code PendingIntent} to bypass Power Save mode.
     */
    public static final int BIND_ALLOW_WHITELIST_MANAGEMENT = 0x01000000;

    /**
     * @hide Flag for {@link #bindService}: Like {@link #BIND_FOREGROUND_SERVICE},
     * but only applies while the device is awake.
+2 −1
Original line number Diff line number Diff line
@@ -60,8 +60,8 @@ import android.util.AndroidException;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;

import android.util.MemoryIntArray;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.ArrayUtils;
import com.android.internal.widget.ILockSettings;
@@ -7950,6 +7950,7 @@ public final class Settings {
         * idle_factor                      (float)
         * min_time_to_alarm                (long)
         * max_temp_app_whitelist_duration  (long)
         * notification_whitelist_duration  (long)
         * </pre>
         *
         * <p>
+59 −19
Original line number Diff line number Diff line
@@ -542,6 +542,8 @@ public class DeviceIdleController extends SystemService
                "mms_temp_app_whitelist_duration";
        private static final String KEY_SMS_TEMP_APP_WHITELIST_DURATION =
                "sms_temp_app_whitelist_duration";
        private static final String KEY_NOTIFICATION_WHITELIST_DURATION =
                "notification_whitelist_duration";

        /**
         * This is the time, after becoming inactive, that we go in to the first
@@ -752,6 +754,14 @@ public class DeviceIdleController extends SystemService
         */
        public long SMS_TEMP_APP_WHITELIST_DURATION;

        /**
         * Amount of time we would like to whitelist an app that is handling a
         * {@link android.app.PendingIntent} triggered by a {@link android.app.Notification}.
         * @see Settings.Global#DEVICE_IDLE_CONSTANTS
         * @see #KEY_NOTIFICATION_WHITELIST_DURATION
         */
        public long NOTIFICATION_WHITELIST_DURATION;

        private final ContentResolver mResolver;
        private final boolean mHasWatch;
        private final KeyValueListParser mParser = new KeyValueListParser(',');
@@ -842,6 +852,8 @@ public class DeviceIdleController extends SystemService
                        KEY_MMS_TEMP_APP_WHITELIST_DURATION, 60 * 1000L);
                SMS_TEMP_APP_WHITELIST_DURATION = mParser.getLong(
                        KEY_SMS_TEMP_APP_WHITELIST_DURATION, 20 * 1000L);
                NOTIFICATION_WHITELIST_DURATION = mParser.getLong(
                        KEY_NOTIFICATION_WHITELIST_DURATION, 30 * 1000L);
            }
        }

@@ -945,6 +957,10 @@ public class DeviceIdleController extends SystemService
            pw.print("    "); pw.print(KEY_SMS_TEMP_APP_WHITELIST_DURATION); pw.print("=");
            TimeUtils.formatDuration(SMS_TEMP_APP_WHITELIST_DURATION, pw);
            pw.println();

            pw.print("    "); pw.print(KEY_NOTIFICATION_WHITELIST_DURATION); pw.print("=");
            TimeUtils.formatDuration(NOTIFICATION_WHITELIST_DURATION, pw);
            pw.println();
        }
    }

@@ -1252,6 +1268,10 @@ public class DeviceIdleController extends SystemService
            addPowerSaveTempWhitelistAppDirectInternal(0, appId, duration, sync, reason);
        }

        public long getNotificationWhitelistDuration() {
            return mConstants.NOTIFICATION_WHITELIST_DURATION;
        }

        public void setNetworkPolicyTempWhitelistCallback(Runnable callback) {
            setNetworkPolicyTempWhitelistCallbackInternal(callback);
        }
@@ -1632,7 +1652,7 @@ public class DeviceIdleController extends SystemService
            }
            entry.first.value = timeNow + duration;
            if (DEBUG) {
                Slog.d(TAG, "Adding AppId " + appId + " to temp whitelist");
                Slog.d(TAG, "Adding AppId " + appId + " to temp whitelist. New entry: " + newEntry);
            }
            if (newEntry) {
                // No pending timeout for the app id, post a delayed message
@@ -1665,12 +1685,18 @@ public class DeviceIdleController extends SystemService
    }

    private void postTempActiveTimeoutMessage(int uid, long delay) {
        if (DEBUG) {
            Slog.d(TAG, "postTempActiveTimeoutMessage: uid=" + uid + ", delay=" + delay);
        }
        mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_TEMP_APP_WHITELIST_TIMEOUT, uid, 0),
                delay);
    }

    void checkTempAppWhitelistTimeout(int uid) {
        final long timeNow = SystemClock.elapsedRealtime();
        if (DEBUG) {
            Slog.d(TAG, "checkTempAppWhitelistTimeout: uid=" + uid + ", timeNow=" + timeNow);
        }
        synchronized (this) {
            Pair<MutableLong, String> entry = mTempWhitelistAppIdEndTimes.get(uid);
            if (entry == null) {
@@ -1694,6 +1720,9 @@ public class DeviceIdleController extends SystemService
                }
            } else {
                // Need more time
                if (DEBUG) {
                    Slog.d(TAG, "Time to remove UID " + uid + ": " + entry.first.value);
                }
                postTempActiveTimeoutMessage(uid, entry.first.value - timeNow);
            }
        }
@@ -2514,6 +2543,8 @@ public class DeviceIdleController extends SystemService
        pw.println("    Print currently whitelisted apps.");
        pw.println("  whitelist [package ...]");
        pw.println("    Add (prefix with +) or remove (prefix with -) packages.");
        pw.println("  tempwhitelist");
        pw.println("    Print packages that are temporarily whitelisted.");
        pw.println("  tempwhitelist [-u] [package ..]");
        pw.println("    Temporarily place packages in whitelist for 10 seconds.");
    }
@@ -2817,8 +2848,7 @@ public class DeviceIdleController extends SystemService
                    pw.println("Failed: " + re);
                }
            } else {
                pw.println("At least one package name must be specified");
                return -1;
                dumpTempWhitelistSchedule(pw, false);
            }
        } else {
            return shell.handleDefaultCommands(cmd);
@@ -2943,20 +2973,8 @@ public class DeviceIdleController extends SystemService
                    pw.println();
                }
            }
            size = mTempWhitelistAppIdEndTimes.size();
            if (size > 0) {
                pw.println("  Temp whitelist schedule:");
                final long timeNow = SystemClock.elapsedRealtime();
                for (int i = 0; i < size; i++) {
                    pw.print("    UID=");
                    pw.print(mTempWhitelistAppIdEndTimes.keyAt(i));
                    pw.print(": ");
                    Pair<MutableLong, String> entry = mTempWhitelistAppIdEndTimes.valueAt(i);
                    TimeUtils.formatDuration(entry.first.value, timeNow, pw);
                    pw.print(" - ");
                    pw.println(entry.second);
                }
            }
            dumpTempWhitelistSchedule(pw, true);

            size = mTempWhitelistAppIdArray != null ? mTempWhitelistAppIdArray.length : 0;
            if (size > 0) {
                pw.println("  Temp whitelist app ids:");
@@ -3040,4 +3058,26 @@ public class DeviceIdleController extends SystemService
            }
        }
    }

    void dumpTempWhitelistSchedule(PrintWriter pw, boolean printTitle) {
        final int size = mTempWhitelistAppIdEndTimes.size();
        if (size > 0) {
            String prefix = "";
            if (printTitle) {
                pw.println("  Temp whitelist schedule:");
                prefix = "    ";
            }
            final long timeNow = SystemClock.elapsedRealtime();
            for (int i = 0; i < size; i++) {
                pw.print(prefix);
                pw.print("UID=");
                pw.print(mTempWhitelistAppIdEndTimes.keyAt(i));
                pw.print(": ");
                Pair<MutableLong, String> entry = mTempWhitelistAppIdEndTimes.valueAt(i);
                TimeUtils.formatDuration(entry.first.value, timeNow, pw);
                pw.print(" - ");
                pw.println(entry.second);
            }
        }
    }
 }
Loading