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

Commit c558857f authored by Lais Andrade's avatar Lais Andrade
Browse files

Check sleep reason and time before cancelling vibrations

Add a method PowerManagerInternal.getLastGoToSleep(), similar to
existing method getLastWakeup(), to retrieve global values for last go
to sleep events, including system uptime and reason.

Retrieve this data in VibratorManagerService before cancelling ongoing
vibrations by the broadcast of ACTION_SCREEN_OFF intents to indicate
that the screen was turned of when the vibration was still playing. This
new logic allows vibrations to continue in the following cases:

- the broadcasted event was triggered before the vibration started;
- there is already a wakeup event triggered by the time the screen off
  broadcast is being processed by the vibrator service;
- the screen off reason is in allowlist, indicating it's an
  automatically triggered event (screen timeout or user inattentive);

This should handle the following scenarios:

- delayed broadcasts of screen off events, that should not cancel
  vibrations that started when the screen was already off (e.g.
  notification or ringtone that are allowed to vibrate in that state);

- race conditions when the screen automatically turns off right after a
  ringtone/notification vibration starts, before the notification
  acquires a screen lock;

Fix: 219849350
Test: VibrationSettingsTest
Change-Id: I358327192196989a7d4fc49a96b2ab92ec677302
parent c9daa032
Loading
Loading
Loading
Loading
+54 −19
Original line number Original line Diff line number Diff line
@@ -463,21 +463,22 @@ public final class PowerManager {
    /**
    /**
     * @hide
     * @hide
     */
     */
    public static String sleepReasonToString(int sleepReason) {
    public static String sleepReasonToString(@GoToSleepReason int sleepReason) {
        switch (sleepReason) {
        switch (sleepReason) {
            case GO_TO_SLEEP_REASON_ACCESSIBILITY: return "accessibility";
            case GO_TO_SLEEP_REASON_APPLICATION: return "application";
            case GO_TO_SLEEP_REASON_APPLICATION: return "application";
            case GO_TO_SLEEP_REASON_DEVICE_ADMIN: return "device_admin";
            case GO_TO_SLEEP_REASON_DEVICE_ADMIN: return "device_admin";
            case GO_TO_SLEEP_REASON_TIMEOUT: return "timeout";
            case GO_TO_SLEEP_REASON_DEVICE_FOLD: return "device_folded";
            case GO_TO_SLEEP_REASON_DISPLAY_GROUP_REMOVED: return "display_group_removed";
            case GO_TO_SLEEP_REASON_DISPLAY_GROUPS_TURNED_OFF: return "display_groups_turned_off";
            case GO_TO_SLEEP_REASON_FORCE_SUSPEND: return "force_suspend";
            case GO_TO_SLEEP_REASON_HDMI: return "hdmi";
            case GO_TO_SLEEP_REASON_INATTENTIVE: return "inattentive";
            case GO_TO_SLEEP_REASON_LID_SWITCH: return "lid_switch";
            case GO_TO_SLEEP_REASON_LID_SWITCH: return "lid_switch";
            case GO_TO_SLEEP_REASON_POWER_BUTTON: return "power_button";
            case GO_TO_SLEEP_REASON_POWER_BUTTON: return "power_button";
            case GO_TO_SLEEP_REASON_HDMI: return "hdmi";
            case GO_TO_SLEEP_REASON_QUIESCENT: return "quiescent";
            case GO_TO_SLEEP_REASON_SLEEP_BUTTON: return "sleep_button";
            case GO_TO_SLEEP_REASON_SLEEP_BUTTON: return "sleep_button";
            case GO_TO_SLEEP_REASON_ACCESSIBILITY: return "accessibility";
            case GO_TO_SLEEP_REASON_TIMEOUT: return "timeout";
            case GO_TO_SLEEP_REASON_FORCE_SUSPEND: return "force_suspend";
            case GO_TO_SLEEP_REASON_INATTENTIVE: return "inattentive";
            case GO_TO_SLEEP_REASON_DISPLAY_GROUP_REMOVED: return "display_group_removed";
            case GO_TO_SLEEP_REASON_DISPLAY_GROUPS_TURNED_OFF: return "display_groups_turned_off";
            case GO_TO_SLEEP_REASON_DEVICE_FOLD: return "device_folded";
            default: return Integer.toString(sleepReason);
            default: return Integer.toString(sleepReason);
        }
        }
    }
    }
@@ -576,18 +577,20 @@ public final class PowerManager {
     * @hide
     * @hide
     */
     */
    @IntDef(prefix = { "GO_TO_SLEEP_REASON_" }, value = {
    @IntDef(prefix = { "GO_TO_SLEEP_REASON_" }, value = {
            GO_TO_SLEEP_REASON_ACCESSIBILITY,
            GO_TO_SLEEP_REASON_APPLICATION,
            GO_TO_SLEEP_REASON_APPLICATION,
            GO_TO_SLEEP_REASON_DEVICE_ADMIN,
            GO_TO_SLEEP_REASON_DEVICE_ADMIN,
            GO_TO_SLEEP_REASON_TIMEOUT,
            GO_TO_SLEEP_REASON_DEVICE_FOLD,
            GO_TO_SLEEP_REASON_LID_SWITCH,
            GO_TO_SLEEP_REASON_DISPLAY_GROUP_REMOVED,
            GO_TO_SLEEP_REASON_POWER_BUTTON,
            GO_TO_SLEEP_REASON_DISPLAY_GROUPS_TURNED_OFF,
            GO_TO_SLEEP_REASON_HDMI,
            GO_TO_SLEEP_REASON_SLEEP_BUTTON,
            GO_TO_SLEEP_REASON_ACCESSIBILITY,
            GO_TO_SLEEP_REASON_FORCE_SUSPEND,
            GO_TO_SLEEP_REASON_FORCE_SUSPEND,
            GO_TO_SLEEP_REASON_HDMI,
            GO_TO_SLEEP_REASON_INATTENTIVE,
            GO_TO_SLEEP_REASON_INATTENTIVE,
            GO_TO_SLEEP_REASON_LID_SWITCH,
            GO_TO_SLEEP_REASON_POWER_BUTTON,
            GO_TO_SLEEP_REASON_QUIESCENT,
            GO_TO_SLEEP_REASON_QUIESCENT,
            GO_TO_SLEEP_REASON_DEVICE_FOLD
            GO_TO_SLEEP_REASON_SLEEP_BUTTON,
            GO_TO_SLEEP_REASON_TIMEOUT,
    })
    })
    @Retention(RetentionPolicy.SOURCE)
    @Retention(RetentionPolicy.SOURCE)
    public @interface GoToSleepReason{}
    public @interface GoToSleepReason{}
@@ -704,6 +707,8 @@ public final class PowerManager {
    }
    }


    /**
    /**
     * Information related to the device waking up, triggered by {@link #wakeUp}.
     *
     * @hide
     * @hide
     */
     */
    public static class WakeData {
    public static class WakeData {
@@ -712,9 +717,9 @@ public final class PowerManager {
            this.wakeReason = wakeReason;
            this.wakeReason = wakeReason;
            this.sleepDuration = sleepDuration;
            this.sleepDuration = sleepDuration;
        }
        }
        public long wakeTime;
        public final long wakeTime;
        public @WakeReason int wakeReason;
        public final @WakeReason int wakeReason;
        public long sleepDuration;
        public final long sleepDuration;


        @Override
        @Override
        public boolean equals(@Nullable Object o) {
        public boolean equals(@Nullable Object o) {
@@ -732,6 +737,35 @@ public final class PowerManager {
        }
        }
    }
    }


    /**
     * Information related to the device going to sleep, triggered by {@link #goToSleep}.
     *
     * @hide
     */
    public static class SleepData {
        public SleepData(long goToSleepUptimeMillis, @GoToSleepReason int goToSleepReason) {
            this.goToSleepUptimeMillis = goToSleepUptimeMillis;
            this.goToSleepReason = goToSleepReason;
        }
        public final long goToSleepUptimeMillis;
        public final @GoToSleepReason int goToSleepReason;

        @Override
        public boolean equals(@Nullable Object o) {
            if (o instanceof SleepData) {
                final SleepData other = (SleepData) o;
                return goToSleepUptimeMillis == other.goToSleepUptimeMillis
                        && goToSleepReason == other.goToSleepReason;
            }
            return false;
        }

        @Override
        public int hashCode() {
            return Objects.hash(goToSleepUptimeMillis, goToSleepReason);
        }
    }

    /**
    /**
     * The value to pass as the 'reason' argument to reboot() to reboot into
     * The value to pass as the 'reason' argument to reboot() to reboot into
     * recovery mode for tasks other than applying system updates, such as
     * recovery mode for tasks other than applying system updates, such as
@@ -2644,6 +2678,7 @@ public final class PowerManager {
     *
     *
     * @hide
     * @hide
     */
     */
    @GoToSleepReason
    public int getLastSleepReason() {
    public int getLastSleepReason() {
        try {
        try {
            return mService.getLastSleepReason();
            return mService.getLastSleepReason();
+3 −0
Original line number Original line Diff line number Diff line
@@ -330,6 +330,9 @@ public abstract class PowerManagerInternal {
    /** Returns information about the last wakeup event. */
    /** Returns information about the last wakeup event. */
    public abstract PowerManager.WakeData getLastWakeup();
    public abstract PowerManager.WakeData getLastWakeup();


    /** Returns information about the last event to go to sleep. */
    public abstract PowerManager.SleepData getLastGoToSleep();

    /** Allows power button to intercept a power key button press. */
    /** Allows power button to intercept a power key button press. */
    public abstract boolean interceptPowerKeyDown(KeyEvent event);
    public abstract boolean interceptPowerKeyDown(KeyEvent event);
}
}
+2 −1
Original line number Original line Diff line number Diff line
@@ -86,7 +86,7 @@ message VibrationAttributesProto {
    optional int32 flags = 3;
    optional int32 flags = 3;
}
}


// Next id: 7
// Next id: 8
message VibrationProto {
message VibrationProto {
    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
    optional int64 start_time = 1;
    optional int64 start_time = 1;
@@ -95,6 +95,7 @@ message VibrationProto {
    optional CombinedVibrationEffectProto original_effect = 4;
    optional CombinedVibrationEffectProto original_effect = 4;
    optional VibrationAttributesProto attributes = 5;
    optional VibrationAttributesProto attributes = 5;
    optional int32 status = 6;
    optional int32 status = 6;
    optional int64 duration_ms = 7;
}
}


// Next id: 25
// Next id: 25
+16 −5
Original line number Original line Diff line number Diff line
@@ -72,8 +72,8 @@ import android.os.Looper;
import android.os.Message;
import android.os.Message;
import android.os.ParcelDuration;
import android.os.ParcelDuration;
import android.os.PowerManager;
import android.os.PowerManager;
import android.os.PowerManager.GoToSleepReason;
import android.os.PowerManager.ServiceType;
import android.os.PowerManager.ServiceType;
import android.os.PowerManager.WakeData;
import android.os.PowerManager.WakeReason;
import android.os.PowerManager.WakeReason;
import android.os.PowerManagerInternal;
import android.os.PowerManagerInternal;
import android.os.PowerSaveState;
import android.os.PowerSaveState;
@@ -352,7 +352,7 @@ public final class PowerManagerService extends SystemService


    // Last reason the device went to sleep.
    // Last reason the device went to sleep.
    private @WakeReason int mLastGlobalWakeReason;
    private @WakeReason int mLastGlobalWakeReason;
    private int mLastGlobalSleepReason;
    private @GoToSleepReason int mLastGlobalSleepReason;


    // Timestamp of last time power boost interaction was sent.
    // Timestamp of last time power boost interaction was sent.
    private long mLastInteractivePowerHintTime;
    private long mLastInteractivePowerHintTime;
@@ -6350,20 +6350,26 @@ public final class PowerManagerService extends SystemService
        }
        }
    }
    }


    @GoToSleepReason
    private int getLastSleepReasonInternal() {
    private int getLastSleepReasonInternal() {
        synchronized (mLock) {
        synchronized (mLock) {
            return mLastGlobalSleepReason;
            return mLastGlobalSleepReason;
        }
        }
    }
    }


    @VisibleForTesting
    private PowerManager.WakeData getLastWakeupInternal() {
    private PowerManager.WakeData getLastWakeupInternal() {
        synchronized (mLock) {
        synchronized (mLock) {
            return new WakeData(mLastGlobalWakeTime, mLastGlobalWakeReason,
            return new PowerManager.WakeData(mLastGlobalWakeTime, mLastGlobalWakeReason,
                    mLastGlobalWakeTime - mLastGlobalSleepTime);
                    mLastGlobalWakeTime - mLastGlobalSleepTime);
        }
        }
    }
    }


    private PowerManager.SleepData getLastGoToSleepInternal() {
        synchronized (mLock) {
            return new PowerManager.SleepData(mLastGlobalSleepTime, mLastGlobalSleepReason);
        }
    }

    /**
    /**
     * If the user presses power while the proximity sensor is enabled and keeping
     * If the user presses power while the proximity sensor is enabled and keeping
     * the screen off, then turn the screen back on by telling display manager to
     * the screen off, then turn the screen back on by telling display manager to
@@ -6528,10 +6534,15 @@ public final class PowerManagerService extends SystemService
        }
        }


        @Override
        @Override
        public WakeData getLastWakeup() {
        public PowerManager.WakeData getLastWakeup() {
            return getLastWakeupInternal();
            return getLastWakeupInternal();
        }
        }


        @Override
        public PowerManager.SleepData getLastGoToSleep() {
            return getLastGoToSleepInternal();
        }

        @Override
        @Override
        public boolean interceptPowerKeyDown(KeyEvent event) {
        public boolean interceptPowerKeyDown(KeyEvent event) {
            return interceptPowerKeyDownInternal(event);
            return interceptPowerKeyDownInternal(event);
+20 −10
Original line number Original line Diff line number Diff line
@@ -71,8 +71,8 @@ final class Vibration {
        IGNORED_SUPERSEDED,
        IGNORED_SUPERSEDED,
    }
    }


    /** Start time in CLOCK_BOOTTIME base. */
    /** Start time using {@link SystemClock#uptimeMillis()}, for calculations. */
    public final long startTime;
    public final long startUptimeMillis;
    public final VibrationAttributes attrs;
    public final VibrationAttributes attrs;
    public final long id;
    public final long id;
    public final int uid;
    public final int uid;
@@ -94,11 +94,14 @@ final class Vibration {


    /**
    /**
     * Start/end times in unix epoch time. Only to be used for debugging purposes and to correlate
     * Start/end times in unix epoch time. Only to be used for debugging purposes and to correlate
     * with other system events, any duration calculations should be done use {@link #startTime} so
     * with other system events, any duration calculations should be done use
     * as not to be affected by discontinuities created by RTC adjustments.
     * {@link #startUptimeMillis} so as not to be affected by discontinuities created by RTC
     * adjustments.
     */
     */
    private final long mStartTimeDebug;
    private final long mStartTimeDebug;
    private long mEndTimeDebug;
    private long mEndTimeDebug;
    /** End time using {@link SystemClock#uptimeMillis()}, for calculations. */
    private long mEndUptimeMillis;
    private Status mStatus;
    private Status mStatus;


    /** A {@link CountDownLatch} to enable waiting for completion. */
    /** A {@link CountDownLatch} to enable waiting for completion. */
@@ -109,7 +112,7 @@ final class Vibration {
        this.token = token;
        this.token = token;
        this.mEffect = effect;
        this.mEffect = effect;
        this.id = id;
        this.id = id;
        this.startTime = SystemClock.elapsedRealtime();
        this.startUptimeMillis = SystemClock.uptimeMillis();
        this.attrs = attrs;
        this.attrs = attrs;
        this.uid = uid;
        this.uid = uid;
        this.opPkg = opPkg;
        this.opPkg = opPkg;
@@ -131,6 +134,7 @@ final class Vibration {
            return;
            return;
        }
        }
        mStatus = status;
        mStatus = status;
        mEndUptimeMillis = SystemClock.uptimeMillis();
        mEndTimeDebug = System.currentTimeMillis();
        mEndTimeDebug = System.currentTimeMillis();
        mCompletionLatch.countDown();
        mCompletionLatch.countDown();
    }
    }
@@ -225,15 +229,17 @@ final class Vibration {


    /** Return {@link Vibration.DebugInfo} with read-only debug information about this vibration. */
    /** Return {@link Vibration.DebugInfo} with read-only debug information about this vibration. */
    public Vibration.DebugInfo getDebugInfo() {
    public Vibration.DebugInfo getDebugInfo() {
        long durationMs = hasEnded() ? mEndUptimeMillis - startUptimeMillis : -1;
        return new Vibration.DebugInfo(
        return new Vibration.DebugInfo(
                mStartTimeDebug, mEndTimeDebug, mEffect, mOriginalEffect, /* scale= */ 0, attrs,
                mStartTimeDebug, mEndTimeDebug, durationMs, mEffect, mOriginalEffect,
                uid, opPkg, reason, mStatus);
                /* scale= */ 0, attrs, uid, opPkg, reason, mStatus);
    }
    }


    /** Debug information about vibrations. */
    /** Debug information about vibrations. */
    static final class DebugInfo {
    static final class DebugInfo {
        private final long mStartTimeDebug;
        private final long mStartTimeDebug;
        private final long mEndTimeDebug;
        private final long mEndTimeDebug;
        private final long mDurationMs;
        private final CombinedVibration mEffect;
        private final CombinedVibration mEffect;
        private final CombinedVibration mOriginalEffect;
        private final CombinedVibration mOriginalEffect;
        private final float mScale;
        private final float mScale;
@@ -243,11 +249,12 @@ final class Vibration {
        private final String mReason;
        private final String mReason;
        private final Status mStatus;
        private final Status mStatus;


        DebugInfo(long startTimeDebug, long endTimeDebug, CombinedVibration effect,
        DebugInfo(long startTimeDebug, long endTimeDebug, long durationMs,
                CombinedVibration originalEffect, float scale, VibrationAttributes attrs,
                CombinedVibration effect, CombinedVibration originalEffect, float scale,
                int uid, String opPkg, String reason, Status status) {
                VibrationAttributes attrs, int uid, String opPkg, String reason, Status status) {
            mStartTimeDebug = startTimeDebug;
            mStartTimeDebug = startTimeDebug;
            mEndTimeDebug = endTimeDebug;
            mEndTimeDebug = endTimeDebug;
            mDurationMs = durationMs;
            mEffect = effect;
            mEffect = effect;
            mOriginalEffect = originalEffect;
            mOriginalEffect = originalEffect;
            mScale = scale;
            mScale = scale;
@@ -266,6 +273,8 @@ final class Vibration {
                    .append(", endTime: ")
                    .append(", endTime: ")
                    .append(mEndTimeDebug == 0 ? null
                    .append(mEndTimeDebug == 0 ? null
                            : DEBUG_DATE_FORMAT.format(new Date(mEndTimeDebug)))
                            : DEBUG_DATE_FORMAT.format(new Date(mEndTimeDebug)))
                    .append(", durationMs: ")
                    .append(mDurationMs)
                    .append(", status: ")
                    .append(", status: ")
                    .append(mStatus.name().toLowerCase())
                    .append(mStatus.name().toLowerCase())
                    .append(", effect: ")
                    .append(", effect: ")
@@ -290,6 +299,7 @@ final class Vibration {
            final long token = proto.start(fieldId);
            final long token = proto.start(fieldId);
            proto.write(VibrationProto.START_TIME, mStartTimeDebug);
            proto.write(VibrationProto.START_TIME, mStartTimeDebug);
            proto.write(VibrationProto.END_TIME, mEndTimeDebug);
            proto.write(VibrationProto.END_TIME, mEndTimeDebug);
            proto.write(VibrationProto.DURATION_MS, mDurationMs);
            proto.write(VibrationProto.STATUS, mStatus.ordinal());
            proto.write(VibrationProto.STATUS, mStatus.ordinal());


            final long attrsToken = proto.start(VibrationProto.ATTRIBUTES);
            final long attrsToken = proto.start(VibrationProto.ATTRIBUTES);
Loading