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

Commit ed29480f authored by Mao Jinlong's avatar Mao Jinlong Committed by Linux Build Service Account
Browse files

Alarm: Add one more RTC alarm type for poweroff alarm.

Now we use type of RTC_WAKEUP for the poweroff alarm.
Actually lots of other applications also use this type.
But these applications never expect the device will
power on after it has been shut down. So we need to
add dedicated alarm type for the Deskclock or similar
applications.

Change-Id: Ib515d8a737ab73cdd809597ad8cde57030c0a0a1
parent 941102cc
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -106,6 +106,15 @@ public class AlarmManager {
     */
    public static final int ELAPSED_REALTIME = 3;

    /**
     * Alarm time in {@link System#currentTimeMillis System.currentTimeMillis()}
     * (wall clock time in UTC), which will wake up the device when
     * it goes off. And it will power on the devices when it shuts down.
     * Set as 5 to make it be compatible with android_alarm_type.
     * @hide
     */
    public static final int RTC_POWEROFF_WAKEUP = 5;

    /**
     * Broadcast Action: Sent after the value returned by
     * {@link #getNextAlarmClock()} has changed.
+69 −8
Original line number Diff line number Diff line
@@ -80,6 +80,7 @@ import static android.app.AlarmManager.RTC_WAKEUP;
import static android.app.AlarmManager.RTC;
import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP;
import static android.app.AlarmManager.ELAPSED_REALTIME;
import static android.app.AlarmManager.RTC_POWEROFF_WAKEUP;

import com.android.internal.util.LocalLog;

@@ -88,8 +89,10 @@ class AlarmManagerService extends SystemService {
    private static final int RTC_MASK = 1 << RTC;
    private static final int ELAPSED_REALTIME_WAKEUP_MASK = 1 << ELAPSED_REALTIME_WAKEUP;
    private static final int ELAPSED_REALTIME_MASK = 1 << ELAPSED_REALTIME;
    private static final int RTC_POWEROFF_WAKEUP_MASK = 1 << RTC_POWEROFF_WAKEUP;
    static final int TIME_CHANGED_MASK = 1 << 16;
    static final int IS_WAKEUP_MASK = RTC_WAKEUP_MASK|ELAPSED_REALTIME_WAKEUP_MASK;
    static final int IS_WAKEUP_MASK = RTC_WAKEUP_MASK|ELAPSED_REALTIME_WAKEUP_MASK
            |RTC_POWEROFF_WAKEUP_MASK;

    // Mask for testing whether a given alarm type is wakeup vs non-wakeup
    static final int TYPE_NONWAKEUP_MASK = 0x1; // low bit => non-wakeup
@@ -124,6 +127,7 @@ class AlarmManagerService extends SystemService {

    long mNativeData;
    private long mNextWakeup;
    private long mNextRtcWakeup;
    private long mNextNonWakeup;
    private long mLastWakeupSet;
    private long mLastWakeup;
@@ -389,6 +393,15 @@ class AlarmManagerService extends SystemService {
            return alarms.get(index);
        }

        long getWhenByElapsedTime(long whenElapsed) {
            for(int i=0;i< alarms.size();i++) {
                if(alarms.get(i).whenElapsed == whenElapsed) {
                    return alarms.get(i).when;
                }
            }
            return 0;
        }

        boolean canHold(long whenElapsed, long maxWhen) {
            return (end >= whenElapsed) && (start <= maxWhen);
        }
@@ -587,6 +600,17 @@ class AlarmManagerService extends SystemService {
            return false;
        }

        boolean isRtcPowerOffWakeup() {
            final int N = alarms.size();
            for (int i = 0; i < N; i++) {
                Alarm a = alarms.get(i);
                if (a.type == RTC_POWEROFF_WAKEUP) {
                    return true;
                }
            }
            return false;
        }

        @Override
        public String toString() {
            StringBuilder b = new StringBuilder(40);
@@ -697,7 +721,8 @@ class AlarmManagerService extends SystemService {
    }

    static long convertToElapsed(long when, int type) {
        final boolean isRtc = (type == RTC || type == RTC_WAKEUP);
        final boolean isRtc = (type == RTC || type == RTC_WAKEUP
                || type == RTC_POWEROFF_WAKEUP);
        if (isRtc) {
            when -= System.currentTimeMillis() - SystemClock.elapsedRealtime();
        }
@@ -904,7 +929,7 @@ class AlarmManagerService extends SystemService {
    @Override
    public void onStart() {
        mNativeData = init();
        mNextWakeup = mNextNonWakeup = 0;
        mNextWakeup = mNextRtcWakeup = mNextNonWakeup = 0;

        // We have to set current TimeZone info to kernel
        // because kernel doesn't keep this after reboot
@@ -1042,7 +1067,7 @@ class AlarmManagerService extends SystemService {
            interval = minInterval;
        }

        if (type < RTC_WAKEUP || type > ELAPSED_REALTIME) {
        if (type < RTC_WAKEUP || type > RTC_POWEROFF_WAKEUP) {
            throw new IllegalArgumentException("Invalid alarm type " + type);
        }

@@ -1704,6 +1729,18 @@ class AlarmManagerService extends SystemService {
        return null;
    }

    private Batch findFirstRtcWakeupBatchLocked() {
        final int N = mAlarmBatches.size();
        for (int i = 0; i < N; i++) {
            Batch b = mAlarmBatches.get(i);
            long intervalTime  = b.start - SystemClock.elapsedRealtime();
            if (b.isRtcPowerOffWakeup()) {
                return b;
            }
        }
        return null;
    }

    long getNextWakeFromIdleTimeImpl() {
        synchronized (mLock) {
            return mNextWakeFromIdle != null ? mNextWakeFromIdle.whenElapsed : Long.MAX_VALUE;
@@ -1852,11 +1889,19 @@ class AlarmManagerService extends SystemService {
        if (mAlarmBatches.size() > 0) {
            final Batch firstWakeup = findFirstWakeupBatchLocked();
            final Batch firstBatch = mAlarmBatches.get(0);
            final Batch firstRtcWakeup = findFirstRtcWakeupBatchLocked();
            if (firstWakeup != null && mNextWakeup != firstWakeup.start) {
                mNextWakeup = firstWakeup.start;
                mLastWakeupSet = SystemClock.elapsedRealtime();
                setLocked(ELAPSED_REALTIME_WAKEUP, firstWakeup.start);
            }
            if (firstRtcWakeup != null && mNextRtcWakeup != firstRtcWakeup.start) {
                mNextRtcWakeup = firstRtcWakeup.start;
                long when = firstRtcWakeup.getWhenByElapsedTime(mNextRtcWakeup);
                if (when != 0) {
                    setLocked(RTC_POWEROFF_WAKEUP, when);
                }
            }
            if (firstBatch != firstWakeup) {
                nextNonWakeup = firstBatch.start;
            }
@@ -1876,6 +1921,18 @@ class AlarmManagerService extends SystemService {
        boolean didRemove = false;
        for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
            Batch b = mAlarmBatches.get(i);
            ArrayList<Alarm> alarmList = b.alarms;
            Alarm alarm = null;
            for (int j = alarmList.size() - 1; j >= 0; j--) {
                alarm = alarmList.get(j);
                if (alarm.type == RTC_POWEROFF_WAKEUP && alarm.operation.equals(operation)) {
                    long alarmSeconds, alarmNanoseconds;
                    alarmSeconds = alarm.when / 1000;
                    alarmNanoseconds = (alarm.when % 1000) * 1000 * 1000;
                    clear(mNativeData, alarm.type, alarmSeconds, alarmNanoseconds);
                    mNextRtcWakeup = 0;
                }
            }
            didRemove |= b.remove(operation, directReceiver);
            if (b.size() == 0) {
                mAlarmBatches.remove(i);
@@ -2079,6 +2136,7 @@ class AlarmManagerService extends SystemService {
        case RTC_WAKEUP : return "RTC_WAKEUP";
        case ELAPSED_REALTIME : return "ELAPSED";
        case ELAPSED_REALTIME_WAKEUP: return "ELAPSED_WAKEUP";
        case RTC_POWEROFF_WAKEUP : return "RTC_POWEROFF_WAKEUP";
        default:
            break;
        }
@@ -2099,6 +2157,7 @@ class AlarmManagerService extends SystemService {
    private native long init();
    private native void close(long nativeData);
    private native void set(long nativeData, int type, long seconds, long nanoseconds);
    private native void clear(long nativeData, int type, long seconds, long nanoseconds);
    private native int waitForAlarm(long nativeData);
    private native int setKernelTime(long nativeData, long millis);
    private native int setKernelTimezone(long nativeData, int minuteswest);
@@ -2256,7 +2315,8 @@ class AlarmManagerService extends SystemService {
            type = _type;
            origWhen = _when;
            wakeup = _type == AlarmManager.ELAPSED_REALTIME_WAKEUP
                    || _type == AlarmManager.RTC_WAKEUP;
                    || _type == AlarmManager.RTC_WAKEUP
                    || _type == AlarmManager.RTC_POWEROFF_WAKEUP;
            when = _when;
            whenElapsed = _whenElapsed;
            windowLength = _windowLength;
@@ -2277,7 +2337,7 @@ class AlarmManagerService extends SystemService {

        public static String makeTag(PendingIntent pi, String tag, int type) {
            final String alarmString = type == ELAPSED_REALTIME_WAKEUP || type == RTC_WAKEUP
                    ? "*walarm*:" : "*alarm*:";
                    || type == RTC_POWEROFF_WAKEUP? "*walarm*:" : "*alarm*:";
            return (pi != null) ? pi.getTag(alarmString) : (alarmString + tag);
        }

@@ -2322,7 +2382,8 @@ class AlarmManagerService extends SystemService {

        public void dump(PrintWriter pw, String prefix, long nowRTC, long nowELAPSED,
                SimpleDateFormat sdf) {
            final boolean isRtc = (type == RTC || type == RTC_WAKEUP);
            final boolean isRtc = (type == RTC || type == RTC_WAKEUP
                    || type == RTC_POWEROFF_WAKEUP);
            pw.print(prefix); pw.print("tag="); pw.println(statsTag);
            pw.print(prefix); pw.print("type="); pw.print(type);
                    pw.print(" whenElapsed="); TimeUtils.formatDuration(whenElapsed,
@@ -3087,7 +3148,7 @@ class AlarmManagerService extends SystemService {
                fs.nesting++;
            }
            if (alarm.type == ELAPSED_REALTIME_WAKEUP
                    || alarm.type == RTC_WAKEUP) {
                    || alarm.type == RTC_WAKEUP || alarm.type == RTC_POWEROFF_WAKEUP) {
                bs.numWakeup++;
                fs.numWakeup++;
                if (alarm.workSource != null && alarm.workSource.size() > 0) {
+45 −0
Original line number Diff line number Diff line
@@ -51,6 +51,7 @@ static const clockid_t android_alarm_to_clockid[N_ANDROID_TIMERFDS] = {
    CLOCK_BOOTTIME_ALARM,
    CLOCK_BOOTTIME,
    CLOCK_MONOTONIC,
    CLOCK_POWEROFF_ALARM,
    CLOCK_REALTIME,
};
/* to match the legacy alarm driver implementation, we need an extra
@@ -63,6 +64,7 @@ public:
    virtual ~AlarmImpl();

    virtual int set(int type, struct timespec *ts) = 0;
    virtual int clear(int type, struct timespec *ts) = 0;
    virtual int setTime(struct timeval *tv) = 0;
    virtual int waitForAlarm() = 0;

@@ -77,6 +79,7 @@ public:
    AlarmImplAlarmDriver(int fd) : AlarmImpl(&fd, 1) { }

    int set(int type, struct timespec *ts);
    int clear(int type, struct timespec *ts);
    int setTime(struct timeval *tv);
    int waitForAlarm();
};
@@ -89,6 +92,7 @@ public:
    ~AlarmImplTimerFd();

    int set(int type, struct timespec *ts);
    int clear(int type, struct timespec *ts);
    int setTime(struct timeval *tv);
    int waitForAlarm();

@@ -116,6 +120,11 @@ int AlarmImplAlarmDriver::set(int type, struct timespec *ts)
    return ioctl(fds[0], ANDROID_ALARM_SET(type), ts);
}

int AlarmImplAlarmDriver::clear(int type, struct timespec *ts)
{
    return ioctl(fds[0], ANDROID_ALARM_CLEAR(type), ts);
}

int AlarmImplAlarmDriver::setTime(struct timeval *tv)
{
    struct timespec ts;
@@ -162,6 +171,23 @@ int AlarmImplTimerFd::set(int type, struct timespec *ts)
    return timerfd_settime(fds[type], TFD_TIMER_ABSTIME, &spec, NULL);
}

int AlarmImplTimerFd::clear(int type, struct timespec *ts)
{
    if (type > ANDROID_ALARM_TYPE_COUNT) {
        errno = EINVAL;
        return -1;
    }

    ts->tv_sec = 0;
    ts->tv_nsec = 0;

    struct itimerspec spec;
    memset(&spec, 0, sizeof(spec));
    memcpy(&spec.it_value, ts, sizeof(spec.it_value));

    return timerfd_settime(fds[type], TFD_TIMER_ABSTIME, &spec, NULL);
}

int AlarmImplTimerFd::setTime(struct timeval *tv)
{
    struct rtc_time rtc;
@@ -443,6 +469,24 @@ static void android_server_AlarmManagerService_set(JNIEnv*, jobject, jlong nativ
    }
}

static void android_server_AlarmManagerService_clear(JNIEnv*, jobject, jlong nativeData, jint type, jlong seconds,
        jlong nanoseconds)
{
    AlarmImpl *impl = reinterpret_cast<AlarmImpl *>(nativeData);
    struct timespec ts;
    ts.tv_sec = seconds;
    ts.tv_nsec = nanoseconds;

    int result = impl->clear(type, &ts);
    if (result < 0)
    {
        ALOGE("Unable to clear alarm  %lld.%09lld: %s\n",
              static_cast<long long>(seconds),
              static_cast<long long>(nanoseconds), strerror(errno));
    }
}


static jint android_server_AlarmManagerService_waitForAlarm(JNIEnv*, jobject, jlong nativeData)
{
    AlarmImpl *impl = reinterpret_cast<AlarmImpl *>(nativeData);
@@ -467,6 +511,7 @@ static const JNINativeMethod sMethods[] = {
    {"init", "()J", (void*)android_server_AlarmManagerService_init},
    {"close", "(J)V", (void*)android_server_AlarmManagerService_close},
    {"set", "(JIJJ)V", (void*)android_server_AlarmManagerService_set},
    {"clear", "(JIJJ)V", (void*)android_server_AlarmManagerService_clear},
    {"waitForAlarm", "(J)I", (void*)android_server_AlarmManagerService_waitForAlarm},
    {"setKernelTime", "(JJ)I", (void*)android_server_AlarmManagerService_setKernelTime},
    {"setKernelTimezone", "(JI)I", (void*)android_server_AlarmManagerService_setKernelTimezone},