@ -33,9 +33,10 @@
# include <cutils/properties.h>
# include <pthread.h>
# include <linux/android_alarm.h>
# include <sys/timerfd.h>
# include <linux/rtc.h>
# include <linux/time.h>
# include <sys/epoll.h>
# include <sys/timerfd.h>
# include "healthd/healthd.h"
# include "minui/minui.h"
@ -106,12 +107,6 @@ enum alarm_time_type {
RTC_TIME ,
} ;
/*
* shouldn ' t be changed after
* reading from alarm register
*/
static time_t alm_secs ;
static int alarm_get_time ( enum alarm_time_type time_type ,
time_t * secs )
{
@ -160,104 +155,88 @@ err:
return - 1 ;
}
# define ERR_SECS 2
static int alarm_is_alm_expired ( )
static void alarm_reboot ( void )
{
int rc ;
time_t rtc_secs ;
rc = alarm_get_time ( RTC_TIME , & rtc_secs ) ;
if ( rc < 0 )
return 0 ;
return ( alm_secs > = rtc_secs - ERR_SECS & &
alm_secs < = rtc_secs + ERR_SECS ) ? 1 : 0 ;
}
static int timerfd_set_reboot_time_and_wait ( time_t secs )
{
int fd ;
int ret = - 1 ;
fd = timerfd_create ( CLOCK_REALTIME_ALARM , 0 ) ;
if ( fd < 0 ) {
LOGE ( " Can't open timerfd alarm node \n " ) ;
goto err_return ;
}
struct itimerspec spec ;
memset ( & spec , 0 , sizeof ( spec ) ) ;
spec . it_value . tv_sec = secs ;
if ( timerfd_settime ( fd , 0 /* relative */ , & spec , NULL ) ) {
LOGE ( " Can't set timerfd alarm \n " ) ;
goto err_close ;
}
uint64_t unused ;
if ( read ( fd , & unused , sizeof ( unused ) ) < 0 ) {
LOGE ( " Wait alarm error \n " ) ;
goto err_close ;
}
ret = 0 ;
err_close :
close ( fd ) ;
err_return :
return ret ;
LOGI ( " alarm time is up, reboot the phone! \n " ) ;
syscall ( __NR_reboot , LINUX_REBOOT_MAGIC1 , LINUX_REBOOT_MAGIC2 ,
LINUX_REBOOT_CMD_RESTART2 , " rtc " ) ;
}
static int alarm_set_reboot_time_and_wait ( time_t secs )
{
int rc , fd ;
int rc , epollfd , nevents ;
int fd = 0 ;
struct timespec ts ;
epoll_event event , events [ 1 ] ;
struct itimerspec itval ;
epollfd = epoll_create ( 1 ) ;
if ( epollfd < 0 ) {
LOGE ( " epoll_create failed \n " ) ;
goto err ;
}
fd = open ( " /dev/alarm " , O_RDWR ) ;
fd = timerfd_create ( CLOCK_REALTIME_ALARM , 0 ) ;
if ( fd < 0 ) {
LOGE ( " Can't open alarm devfs node, trying timerfd \n " ) ;
return timerfd_set_reboot_time_and_wait ( secs ) ;
LOGE ( " timerfd_create failed \n " ) ;
goto err ;
}
/* get the elapsed realtime from boot time to now */
rc = ioctl ( fd , ANDROID_ALARM_GET_TIME (
ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP ) , & ts ) ;
event . events = EPOLLIN | EPOLLWAKEUP ;
event . data . ptr = ( void * ) alarm_reboot ;
rc = epoll_ctl ( epollfd , EPOLL_CTL_ADD , fd , & event ) ;
if ( rc < 0 ) {
LOGE ( " Unable to get elapsed realtime \n " ) ;
LOGE ( " epoll_ctl(EPOLL_CTL_ADD) failed \n " ) ;
goto err ;
}
/* calculate the elapsed time from boot time to reboot time */
ts . tv_sec + = secs ;
ts . tv_nsec = 0 ;
itval . it_value . tv_sec = secs ;
itval . it_value . tv_nsec = 0 ;
itval . it_interval . tv_sec = 0 ;
itval . it_interval . tv_nsec = 0 ;
rc = ioctl ( fd , ANDROID_ALARM_SET (
ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP ) , & ts ) ;
rc = timerfd_settime ( fd , TFD_TIMER_ABSTIME , & itval , NULL ) ;
if ( rc < 0 ) {
LOGE ( " Unable to set reboot time to %ld\n " , secs ) ;
LOGE ( " timerfd_settime failed %d\n " , rc ) ;
goto err ;
}
do {
rc = ioctl ( fd , ANDROID_ALARM_WAIT ) ;
} while ( ( rc < 0 & & errno = = EINTR ) | | ! alarm_is_alm_expired ( ) ) ;
nevents = epoll_wait ( epollfd , events , 1 , - 1 ) ;
if ( rc < = 0 ) {
if ( nevents < = 0 ) {
LOGE ( " Unable to wait on alarm \n " ) ;
goto err ;
} else {
( * ( void ( * ) ( ) ) events [ 0 ] . data . ptr ) ( ) ;
}
close ( epollfd ) ;
close ( fd ) ;
return 0 ;
err :
if ( epollfd > 0 )
close ( epollfd ) ;
if ( fd > = 0 )
close ( fd ) ;
return - 1 ;
}
/*
* 10 s the estimated time from timestamp of alarm thread start
* to timestamp of android boot completed .
*/
# define TIME_DELTA 10
/* seconds of 1 minute*/
# define ONE_MINUTE 60
static void * alarm_thread ( void * )
{
time_t rtc_secs , rb_secs ;
time_t rtc_secs , alarm _secs;
int rc ;
timespec ts ;
/*
* to support power off alarm , the time
@ -266,31 +245,39 @@ static void *alarm_thread(void *)
* earlier than the actual alarm time
* set by user
*/
rc = alarm_get_time ( ALARM_TIME , & alm_secs ) ;
LOGI ( " RTC Alarm %ld \n " , alm_secs ) ;
if ( rc < 0 | | ! alm_secs )
rc = alarm_get_time ( ALARM_TIME , & alarm_secs ) ;
if ( rc < 0 | | ! alarm_secs )
goto err ;
rc = alarm_get_time ( RTC_TIME , & rtc_secs ) ;
LOGI ( " RTC Clock %ld \n " , rtc_secs ) ;
if ( rc < 0 )
if ( rc < 0 | | ! rtc_secs )
goto err ;
LOGI ( " alarm time in rtc is %ld, rtc time is %ld \n " , alarm_secs , rtc_secs ) ;
if ( alarm_secs < = rtc_secs ) {
clock_gettime ( CLOCK_BOOTTIME , & ts ) ;
/*
* It is possible that last power off alarm time is up at this point .
* ( alarm_secs + ONE_MINUTE ) is the final alarm time to fire .
* ( rtc_secs + ts . tv_sec + TIME_DELTA ) is the estimated time of next
* boot completed to fire alarm .
* If the final alarm time is less than the estimated time of next boot
* completed to fire , that means it is not able to fire the last power
* off alarm at the right time , so just miss it .
*/
if ( alarm_secs + ONE_MINUTE < rtc_secs + ts . tv_sec + TIME_DELTA ) {
LOGE ( " alarm is missed \n " ) ;
goto err ;
}
/*
* calculate the reboot time after which
* the phone will reboot
*/
rb_secs = alm_secs - rtc_secs ;
if ( rb_secs < = 0 )
goto err ;
alarm_reboot ( ) ;
}
rc = alarm_set_reboot_time_and_wait ( rb_secs ) ;
rc = alarm_set_reboot_time_and_wait ( alarm_secs ) ;
if ( rc < 0 )
goto err ;
LOGI ( " Exit from power off charging, reboot the phone! \n " ) ;
android_reboot ( ANDROID_RB_RESTART , 0 , 0 ) ;
err :
LOGE ( " Exit from alarm thread \n " ) ;
return NULL ;