11c5f1a65d
When the wakeup time is negative, the kernel /dev/alarm driver never triggers the alarm. This can cause alarms to back up in the priority queue since an alarm at the head with a negative wakup time will never be triggered. Now we use 0 as the wakup time which causes an immediate triggering. When the wakeup time is very large, it is possible for a numeric overflow to occur when converting the timestamp from milliseconds since epoch to nanoseconds. This has been fixed by avoiding the intermediate conversion in the JNI call so that overflow cannot occur. Bug: b/2558820 Change-Id: I4f5b4646a04090cc749a9fc5d3982a68402954ef
140 lines
3.6 KiB
C++
140 lines
3.6 KiB
C++
/* //device/libs/android_runtime/android_server_AlarmManagerService.cpp
|
|
**
|
|
** Copyright 2006, The Android Open Source Project
|
|
**
|
|
** Licensed under the Apache License, Version 2.0 (the "License");
|
|
** you may not use this file except in compliance with the License.
|
|
** You may obtain a copy of the License at
|
|
**
|
|
** http://www.apache.org/licenses/LICENSE-2.0
|
|
**
|
|
** Unless required by applicable law or agreed to in writing, software
|
|
** distributed under the License is distributed on an "AS IS" BASIS,
|
|
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
** See the License for the specific language governing permissions and
|
|
** limitations under the License.
|
|
*/
|
|
|
|
#define LOG_TAG "AlarmManagerService"
|
|
|
|
#include "JNIHelp.h"
|
|
#include "jni.h"
|
|
#include <utils/Log.h>
|
|
#include <utils/misc.h>
|
|
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <arpa/inet.h>
|
|
#include <netinet/in.h>
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
#include <unistd.h>
|
|
|
|
#if HAVE_ANDROID_OS
|
|
#include <linux/ioctl.h>
|
|
#include <linux/android_alarm.h>
|
|
#endif
|
|
|
|
namespace android {
|
|
|
|
static jint android_server_AlarmManagerService_setKernelTimezone(JNIEnv* env, jobject obj, jint fd, jint minswest)
|
|
{
|
|
#if HAVE_ANDROID_OS
|
|
struct timezone tz;
|
|
|
|
tz.tz_minuteswest = minswest;
|
|
tz.tz_dsttime = 0;
|
|
|
|
int result = settimeofday(NULL, &tz);
|
|
if (result < 0) {
|
|
LOGE("Unable to set kernel timezone to %d: %s\n", minswest, strerror(errno));
|
|
return -1;
|
|
} else {
|
|
LOGD("Kernel timezone updated to %d minutes west of GMT\n", minswest);
|
|
}
|
|
|
|
return 0;
|
|
#else
|
|
return -ENOSYS;
|
|
#endif
|
|
}
|
|
|
|
static jint android_server_AlarmManagerService_init(JNIEnv* env, jobject obj)
|
|
{
|
|
#if HAVE_ANDROID_OS
|
|
return open("/dev/alarm", O_RDWR);
|
|
#else
|
|
return -1;
|
|
#endif
|
|
}
|
|
|
|
static void android_server_AlarmManagerService_close(JNIEnv* env, jobject obj, jint fd)
|
|
{
|
|
#if HAVE_ANDROID_OS
|
|
close(fd);
|
|
#endif
|
|
}
|
|
|
|
static void android_server_AlarmManagerService_set(JNIEnv* env, jobject obj, jint fd, jint type, jlong seconds, jlong nanoseconds)
|
|
{
|
|
#if HAVE_ANDROID_OS
|
|
struct timespec ts;
|
|
ts.tv_sec = seconds;
|
|
ts.tv_nsec = nanoseconds;
|
|
|
|
int result = ioctl(fd, ANDROID_ALARM_SET(type), &ts);
|
|
if (result < 0)
|
|
{
|
|
LOGE("Unable to set alarm to %lld.%09lld: %s\n", seconds, nanoseconds, strerror(errno));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static jint android_server_AlarmManagerService_waitForAlarm(JNIEnv* env, jobject obj, jint fd)
|
|
{
|
|
#if HAVE_ANDROID_OS
|
|
int result = 0;
|
|
|
|
do
|
|
{
|
|
result = ioctl(fd, ANDROID_ALARM_WAIT);
|
|
} while (result < 0 && errno == EINTR);
|
|
|
|
if (result < 0)
|
|
{
|
|
LOGE("Unable to wait on alarm: %s\n", strerror(errno));
|
|
return 0;
|
|
}
|
|
|
|
return result;
|
|
#endif
|
|
}
|
|
|
|
static JNINativeMethod sMethods[] = {
|
|
/* name, signature, funcPtr */
|
|
{"init", "()I", (void*)android_server_AlarmManagerService_init},
|
|
{"close", "(I)V", (void*)android_server_AlarmManagerService_close},
|
|
{"set", "(IIJJ)V", (void*)android_server_AlarmManagerService_set},
|
|
{"waitForAlarm", "(I)I", (void*)android_server_AlarmManagerService_waitForAlarm},
|
|
{"setKernelTimezone", "(II)I", (void*)android_server_AlarmManagerService_setKernelTimezone},
|
|
};
|
|
|
|
int register_android_server_AlarmManagerService(JNIEnv* env)
|
|
{
|
|
jclass clazz = env->FindClass("com/android/server/AlarmManagerService");
|
|
|
|
if (clazz == NULL)
|
|
{
|
|
LOGE("Can't find com/android/server/AlarmManagerService");
|
|
return -1;
|
|
}
|
|
|
|
return jniRegisterNativeMethods(env, "com/android/server/AlarmManagerService",
|
|
sMethods, NELEM(sMethods));
|
|
}
|
|
|
|
} /* namespace android */
|