static void _activity_print(struct timespec *from, struct timespec *now) { struct timespec diff; int diff_ms; pthread_mutex_lock(&activity_mutex); GList *iter; for (iter = activity_roster->head; iter != NULL; iter = iter->next) { Activity *a = (Activity*)iter->data; // now > activity.end_time if (ClockTimeIsGreater(from, &a->end_time)) { continue; } // end_time - now ClockDiff(&diff, &a->end_time, now); diff_ms = diff.tv_sec * 1000 + diff.tv_nsec / 1000000; SLEEPDLOG(LOG_INFO, "(%s) for %d ms, expiry in %d ms", a->activity_id, a->duration_ms, diff_ms); } pthread_mutex_unlock(&activity_mutex); }
/** * @brief Log the client's response for the current shutdown voting process */ static void client_vote_print(const char *key, ShutdownClient *client, void *data) { SLEEPDLOG(LOG_INFO, " %s %s %s @ %fs", client->id, client->name, shutdown_reply_to_string(client->ack_shutdown), client->elapsed); }
/** * @brief Stop an activity * * @param activity_id of the activity than needs to be stopped * * @param activity_id */ void PwrEventActivityStop(const char *activity_id) { SLEEPDLOG(LOG_INFO, "%s: (%s)", __FUNCTION__, activity_id); _activity_stop(activity_id); ScheduleIdleCheck(0, false); }
static void client_list_print(GHashTable *client_table) { int size = g_hash_table_size(client_table); SLEEPDLOG(LOG_INFO, "clients:"); if (size > 0) { g_hash_table_foreach(client_table, (GHFunc)client_vote_print, NULL); } else { SLEEPDLOG(LOG_INFO, " No clients registered."); } }
/** * @brief Check the client response for the "shutdownApplications" signal. We get to this state either when * a client ACKs or we have timed out. */ static bool state_shutdown_apps_process(ShutdownEvent *event, ShutdownState *next) { bool timeout = false; switch (event->id) { case kShutdownEventAck: client_vote(event->client, true); break; case kShutdownEventTimeout: timeout = true; break; default: break; } int readiness = shutdown_apps_ready(); if (readiness > 0 || timeout) { if (timeout) { SLEEPDLOG(LOG_CRIT, "Shutdown apps timed out: "); } client_list_print(sClientList->applications); g_source_remove(shutdown_apps_timeout_id); *next = kPowerShutdownServices; return true; } else if (readiness < 0) { *next = kPowerShutdownNone; return false; } else { *next = kPowerShutdownAppsProcess; return false; } }
/** * @brief Start an activity by the name of 'activity_id'. * * @param activity_id Should be in format com.domain.reverse-serial. * @param duration_ms * * @return false if the activity could not be created... (activities may be frozen). */ bool PwrEventActivityStart(const char *activity_id, int duration_ms) { bool retVal; retVal = _activity_start(activity_id, duration_ms); SLEEPDLOG(LOG_INFO, "%s: (%s) for %dms => %s", __FUNCTION__, activity_id, duration_ms, retVal ? "true" : "false"); if (retVal) { /* Force IdleCheck to run in case this activity is the same as the current "long pole" activity but with a shorter life. */ ScheduleIdleCheck(0, false); } return retVal; }
/** * @brief Remove all expired activities... * This assumes the list is sorted. * * @param now */ void PwrEventActivityRemoveExpired(struct timespec *now) { pthread_mutex_lock(&activity_mutex); GList *iter; for (iter = activity_roster->head; iter != NULL; ) { Activity *a = (Activity*)iter->data; // remove expired if (_activity_expired(a, now)) { GList *current_iter = iter; iter = iter->next; if (a->duration_ms >= ACTIVITY_HIGH_DURATION_MS) { LSError lserror; LSErrorInit(&lserror); SLEEPDLOG(LOG_WARNING, "%s Long activity %s of duration %d ms expired... sending RDX report.", __FUNCTION__, a->activity_id, a->duration_ms); } _activity_stop_activity(a); g_queue_delete_link(activity_roster, current_iter); } else { break; } } pthread_mutex_unlock(&activity_mutex); }
static void shutdown_state_dispatch(ShutdownEvent *event) { ShutdownState next_state = gCurrentState->state; bool running = true; while (running) { running = gCurrentState->function(event, &next_state); _assert(next_state >= gCurrentState->state); if (next_state != gCurrentState->state) { SLEEPDLOG(LOG_DEBUG, "Shutdown: entering state: %s @ %fs", kStateMachine[next_state].name, g_timer_elapsed(shutdown_timer, NULL)); } gCurrentState = &kStateMachine[next_state]; } }
int main(int argc, char **argv) { bool retVal; // FIXME integrate this into TheOneInit() LOGInit(); LOGSetHandler(LOGSyslog); signal(SIGTERM, term_handler); signal(SIGINT, term_handler); if (!g_thread_supported ()) g_thread_init (NULL); mainloop = g_main_loop_new(NULL, FALSE); /** * initialize the lunaservice and we want it before all the init * stuff happening. */ LSError lserror; LSErrorInit(&lserror); retVal = LSRegisterPalmService("com.palm.sleep", &psh, &lserror); if (!retVal) { goto ls_error; } retVal = LSGmainAttachPalmService(psh, mainloop, &lserror); if (!retVal) { goto ls_error; } private_sh = LSPalmServiceGetPrivateConnection(psh); retVal = LSCall(private_sh,"luna://com.palm.lunabus/signal/addmatch","{\"category\":\"/com/palm/power\"," "\"method\":\"USBDockStatus\"}", ChargerStatus, NULL, NULL, &lserror); if (!retVal) { SLEEPDLOG(LOG_CRIT,"Error in registering for luna-signal \"chargerStatus\""); goto ls_error; } int ret = nyx_device_open(NYX_DEVICE_SYSTEM, "Main", &nyxSystem); if(ret != NYX_ERROR_NONE) { SLEEPDLOG(LOG_CRIT,"Sleepd: Unable to open the nyx device system"); abort(); } TheOneInit(); LSCall(private_sh,"luna://com.palm.power/com/palm/power/chargerStatusQuery","{}",ChargerStatus,NULL,NULL,&lserror); SLEEPDLOG(LOG_INFO,"Sleepd daemon started\n"); g_main_loop_run(mainloop); end: g_main_loop_unref(mainloop); return 0; ls_error: SLEEPDLOG(LOG_CRIT,"Fatal - Could not initialize sleepd. Is LunaService Down?. %s", lserror.message); LSErrorFree(&lserror); goto end; }
/** * @brief Sends a "/alarm" message to the service associated with this alarm. * * {"alarmId":1,"fired":true,"key":"appkey"} * * @param alarm */ static void fire_alarm(_Alarm *alarm) { bool retVal; char buf_alarm[STD_ASCTIME_BUF_SIZE]; struct tm tm_alarm; time_t rtctime = 0; gmtime_r(&alarm->expiry, &tm_alarm); asctime_r(&tm_alarm, buf_alarm); nyx_system_query_rtc_time(GetNyxSystemDevice(),&rtctime); SLEEPDLOG(LOG_INFO, "Alarm (%s %s %s) fired at %s (rtc %ld)", alarm->serviceName, alarm->applicationName, alarm->key, buf_alarm, rtctime); GString *payload = g_string_sized_new(255); g_string_append_printf(payload, "{\"alarmId\":%d,\"fired\":true", alarm->id); if (alarm->key) { g_string_append_printf(payload, ",\"key\":\"%s\"", alarm->key); } if (alarm->applicationName && strcmp(alarm->applicationName, "") != 0) { g_string_append_printf(payload, ",\"applicationName\":\"%s\"", alarm->applicationName); } g_string_append_printf(payload, "}"); LSError lserror; LSErrorInit(&lserror); if (alarm->serviceName && strcmp(alarm->serviceName, "") != 0) { char *uri = g_strdup_printf("luna://%s/alarm", alarm->serviceName); retVal = LSCall(GetLunaServiceHandle(), uri, payload->str, NULL, NULL, NULL, &lserror); if (!retVal) { LSErrorPrint(&lserror, stderr); LSErrorFree(&lserror); } g_free(uri); } if (alarm->message) { retVal = LSMessageReply(GetLunaServiceHandle(), alarm->message, payload->str, &lserror); if (!retVal) { LSErrorPrint(&lserror, stderr); LSErrorFree(&lserror); } } g_string_free(payload, TRUE); }
/** * @brief Remove an alarm by id. * * {"alarmId":1} * * Response: * * {"returnValue":true} * * @param sh * @param message * @param ctx * * @retval */ static bool alarmRemove(LSHandle *sh, LSMessage *message, void *ctx) { LSError lserror; LSErrorInit(&lserror); bool found = false; bool retVal; const char *payload = LSMessageGetPayload(message); struct json_object *object = json_tokener_parse(payload); if (is_error(object)) { goto malformed_json; } SLEEPDLOG(LOG_DEBUG, "%s: %s", __FUNCTION__, LSMessageGetPayload(message)); int alarmId = json_object_get_int(json_object_object_get(object, "alarmId")); GSequenceIter *iter = g_sequence_get_begin_iter(gAlarmQueue->alarms); while (!g_sequence_iter_is_end (iter)) { _Alarm *alarm = (_Alarm*)g_sequence_get(iter); GSequenceIter *next = g_sequence_iter_next(iter); if (alarm && alarm->id == alarmId) { char *timeout_key = g_strdup_printf("%s-%d", alarm->key, alarm->id); _timeout_clear("com.palm.sleep", timeout_key, false /*public_bus*/); g_free(timeout_key); g_sequence_remove(iter); found = true; } iter = next; } const char *response; if (found) { alarm_write_db(); response = "{\"returnValue\":true}"; } else { response = "{\"returnValue\":false}"; } retVal = LSMessageReply(sh, message, response, &lserror); if (!retVal) { LSErrorPrint(&lserror,stderr); LSErrorFree(&lserror); } goto cleanup; malformed_json: LSMessageReplyErrorBadJSON(sh, message); goto cleanup; cleanup: if (!is_error(object)) json_object_put(object); return true; }
/** * @brief Set a calendar event. * * luna://com.palm.sleep/time/alarmAddCalendar * * Message: * Set alarm to expire at a fixed calendar time in UTC. Response will be sent * as a call to "luna://com.palm.X/alarm". * * {"key":"calendarAlarm", "serviceName":"com.palm.X", * "date":"01-02-2009", "time":"13:40:03"} * * Subscribing indicates that you want the alarm message as a response to * the current call. * * {"subscribe":true, "key":"calendarAlarm", "serviceName":"com.palm.X", * "date":"01-02-2009", "time":"13:40:03"} * * Response: * * Alarm is sucessfully registered for calendar date * {"alarmId":1} * * Subscribe case: * {"alarmId":1,"subscribed":true} * {"alarmId":1,"fired":true} * * Alarm failed to be registered: * * {"returnValue":false, ...} * {"returnValue":false,"serivceName":"com.palm.sleep", * "errorText":"com.palm.sleep is not running"} * * @param sh * @param message * @param ctx * * @retval */ static bool alarmAddCalendar(LSHandle *sh, LSMessage *message, void *ctx) { int alarm_id; struct json_object *object; const char *key, *serviceName, *applicationName, *cal_date, *cal_time; struct tm gm_time; bool subscribe; bool retVal = false; time_t alarm_time = 0; LSError lserror; LSErrorInit(&lserror); object = json_tokener_parse(LSMessageGetPayload(message)); if ( is_error(object) ) { goto malformed_json; } SLEEPDLOG(LOG_DEBUG, "%s: %s", __FUNCTION__, LSMessageGetPayload(message)); serviceName = json_object_get_string( json_object_object_get(object, "serviceName")); applicationName = LSMessageGetApplicationID(message); key = json_object_get_string(json_object_object_get(object, "key")); cal_date = json_object_get_string( json_object_object_get(object, "date")); cal_time = json_object_get_string( json_object_object_get(object, "time")); if (!cal_date || !cal_time) { goto invalid_format; } int hour, min, sec; int month, day, year; if (sscanf(cal_time, "%02d:%02d:%02d", &hour, &min, &sec) != 3) { goto invalid_format; } if (sscanf(cal_date, "%02d-%02d-%04d", &month, &day, &year) != 3) { goto invalid_format; } if (hour < 0 || hour > 24 || min < 0 || min > 60 || sec < 0 || sec > 60 || month < 1 || month > 12 || day < 1 || day > 31 || year < 0) { goto invalid_format; } SLEEPDLOG(LOG_INFO, "%s: (%s %s %s) at %s %s", __FUNCTION__, serviceName, applicationName, key, cal_date, cal_time); struct json_object *subscribe_json = json_object_object_get(object, "subscribe"); subscribe = json_object_get_boolean(subscribe_json); memset(&gm_time, 0, sizeof(struct tm)); gm_time.tm_hour = hour; gm_time.tm_min = min; gm_time.tm_sec = sec; gm_time.tm_mon = month - 1; // month-of-year [0-11] gm_time.tm_mday = day; // day-of-month [1-31] gm_time.tm_year = year - 1900; /* timegm converts time(GMT) -> seconds since epoch */ alarm_time = timegm(&gm_time); if (alarm_time < 0) { goto invalid_format; } retVal = alarm_queue_new(key, true, alarm_time, serviceName, applicationName, subscribe, message, &alarm_id); if (!retVal) goto error; /***************** * Use new timeout API */ { char *timeout_key = g_strdup_printf("%s-%d", key, alarm_id); _AlarmTimeout timeout; _timeout_create(&timeout, "com.palm.sleep", timeout_key, "luna://com.palm.sleep/time/internalAlarmFired", "{}", false /*public bus*/, true /*wakeup*/, "" /*activity_id*/, 0 /*activity_duration_ms*/, true /*calendar*/, alarm_time); retVal = _timeout_set(&timeout); g_free(timeout_key); if (!retVal) goto error; } /*****************/ /* Send alarm id of sucessful alarm add. */ GString *reply = g_string_sized_new(512); g_string_append_printf(reply, "{\"alarmId\":%d", alarm_id); if (subscribe_json) { g_string_append_printf(reply, ",\"subscribed\":%s", subscribe ? "true":"false"); } g_string_append_printf(reply, "}"); retVal = LSMessageReply(sh, message, reply->str, &lserror); g_string_free(reply, TRUE); goto cleanup; error: retVal = LSMessageReply(sh, message, "{\"returnValue\":false," "\"errorText\":\"Unknown error\"}", &lserror); goto cleanup; invalid_format: retVal = LSMessageReply(sh, message, "{\"returnValue\":false," "\"errorText\":\"Invalid format for alarm time.\"}", &lserror); goto cleanup; malformed_json: LSMessageReplyErrorBadJSON(sh, message); goto cleanup; cleanup: if (!is_error(object)) json_object_put(object); if (!retVal && LSErrorIsSet(&lserror)) { LSErrorPrint(&lserror, stderr); LSErrorFree(&lserror); } return true; }
/** * @brief Set alarm to fire in a fixed time in the future. * * luna://com.palm.sleep/time/alarmAdd * * Set alarm to expire in T+5hrs. Response will be sent * as a call to "luna://com.palm.X/alarm". * * {"key":"calendarAlarm", "serviceName":"com.palm.X", * "relative_time":"05:00:00"} * * Subscribing indicates that you want the alarm message as a response to * the current call. * * {"subscribe":true, "key":"calendarAlarm", "serviceName":"com.palm.X", * "relative_time":"05:00:00"} * * Alarm is sucessfully registered. * {"alarmId":1} * * Alarm failed to be registered: * * {"returnValue":false, ...} * {"returnValue":false,"serivceName":"com.palm.sleep", * "errorText":"com.palm.sleep is not running"} * * @param sh * @param message * @param ctx * * @retval */ static bool alarmAdd(LSHandle *sh, LSMessage *message, void *ctx) { time_t alarm_time = 0; int rel_hour, rel_min, rel_sec; const char *key, *serviceName, *applicationName, *rel_time; bool subscribe; struct json_object *object; int alarm_id; bool retVal = false; LSError lserror; LSErrorInit(&lserror); time_t rtctime = 0; object = json_tokener_parse(LSMessageGetPayload(message)); if ( is_error(object) ) { goto malformed_json; } SLEEPDLOG(LOG_DEBUG, "%s: %s", __FUNCTION__, LSMessageGetPayload(message)); serviceName = json_object_get_string( json_object_object_get(object, "serviceName")); applicationName = LSMessageGetApplicationID(message); key = json_object_get_string(json_object_object_get(object, "key")); rel_time = json_object_get_string( json_object_object_get(object, "relative_time")); if (!rel_time) { goto invalid_format; } if (sscanf(rel_time, "%02d:%02d:%02d", &rel_hour, &rel_min, &rel_sec) != 3) { goto invalid_format; } nyx_system_query_rtc_time(GetNyxSystemDevice(),&rtctime); SLEEPDLOG(LOG_INFO, "%s: (%s %s %s) in %s (rtc %ld)", __FUNCTION__, serviceName, applicationName, key, rel_time, rtctime); struct json_object *subscribe_json = json_object_object_get(object, "subscribe"); subscribe = json_object_get_boolean(subscribe_json); alarm_time = rtc_wall_time(); alarm_time += rel_sec; alarm_time += rel_min * 60; alarm_time += rel_hour * 60 * 60; retVal = alarm_queue_new(key, false, alarm_time, serviceName, applicationName, subscribe, message, &alarm_id); if (!retVal) goto error; /***************** * Use new timeout API */ { char *timeout_key = g_strdup_printf("%s-%d", key, alarm_id); _AlarmTimeout timeout; _timeout_create(&timeout, "com.palm.sleep", timeout_key, "luna://com.palm.sleep/time/internalAlarmFired", "{}", false /*public bus*/, true /*wakeup*/, "" /*activity_id*/, 0 /*activity_duration_ms*/, false /*calendar*/, alarm_time); retVal = _timeout_set(&timeout); g_free(timeout_key); if (!retVal) goto error; } /*****************/ /* Send alarm id of sucessful alarm add. */ GString *reply = g_string_sized_new(512); g_string_append_printf(reply, "{\"alarmId\":%d", alarm_id); if (subscribe_json) { g_string_append_printf(reply, ",\"subscribed\":%s", subscribe ? "true":"false"); } g_string_append_printf(reply, "}"); retVal = LSMessageReply(sh, message, reply->str, &lserror); g_string_free(reply, TRUE); goto cleanup; error: retVal = LSMessageReply(sh, message, "{\"returnValue\":false," "\"errorText\":\"Unknown error\"}", &lserror); goto cleanup; invalid_format: retVal = LSMessageReply(sh, message, "{\"returnValue\":false," "\"errorText\":\"Invalid format for alarm time.\"}", &lserror); goto cleanup; malformed_json: LSMessageReplyErrorBadJSON(sh, message); goto cleanup; cleanup: if (!is_error(object)) json_object_put(object); if (!retVal && LSErrorIsSet(&lserror)) { LSErrorPrint(&lserror, stderr); LSErrorFree(&lserror); } return true; }