/** Disable automatic suspend and remove wakelocks mce might hold * * This function should be called just before mce process terminates * so that we do not leave the system in a non-functioning state */ static void mce_cleanup_wakelocks(void) { /* We are on exit path -> block suspend for good */ wakelock_block_suspend_until_exit(); wakelock_unlock("mce_display_on"); wakelock_unlock("mce_input_handler"); }
/** Disable automatic suspend and remove wakelocks mce might hold * * This function should be called just before mce process terminates * so that we do not leave the system in a non-functioning state */ static void mce_cleanup_wakelocks(void) { /* We are on exit path -> block suspend for good */ wakelock_block_suspend_until_exit(); wakelock_unlock("mce_display_on"); wakelock_unlock("mce_input_handler"); wakelock_unlock("mce_cpu_keepalive"); wakelock_unlock("mce_display_stm"); wakelock_unlock("mce_powerkey_stm"); wakelock_unlock("mce_proximity_stm"); wakelock_unlock("mce_bluez_wait"); wakelock_unlock("mce_led_breathing"); wakelock_unlock("mce_lpm_off"); wakelock_unlock("mce_tklock_notify"); }
static int android_wakelock_release(struct wakelock *lock) { if (lock == NULL) return -EINVAL; DBG("lock %p name %s acquisitions %d", lock, lock->name, lock->acquisitions); if (!lock->acquisitions) { ofono_warn("Attempted to release already released lock %s", lock->name); return -EINVAL; } if (lock->acquisitions > 1) { lock->acquisitions--; DBG("lock %s released acquisitions %d", lock->name, lock->acquisitions); return 0; } if (wakelock_unlock(lock->name) < 0) return -EIO; lock->acquisitions = 0; DBG("lock %s was released", lock->name); return 0; }
/** Set keepalive state * * @param active true to start keepalive, false to end keepalive */ static void cka_state_set(bool active) { static bool keepalive_is_active = false; static bool flagged = false; static tick_t started = 0; if( keepalive_is_active != active ) { tick_t now = cka_tick_get_current(); if( (keepalive_is_active = active) ) { #ifdef ENABLE_WAKELOCKS wakelock_lock(cpu_wakelock, -1); #endif started = now; mce_log(LL_DEVEL, "keepalive started"); } else { tick_t dur = now - started; if( dur > KEEPALIVE_STATE_WARN_LIMIT_MS ) { mce_log(LL_CRIT, "long keepalive stopped after %"PRId64" ms", dur); } else { mce_log(LL_DEVEL, "keepalive stopped after %"PRId64" ms", dur); } flagged = false; #ifdef ENABLE_WAKELOCKS wakelock_unlock(cpu_wakelock); #endif } } else if( keepalive_is_active && !flagged ) { tick_t now = cka_tick_get_current(); tick_t dur = now - started; if( dur > KEEPALIVE_STATE_WARN_LIMIT_MS ) { flagged = true; mce_log(LL_CRIT, "long keepalive active after %"PRId64" ms", dur); } } }
/** Handle triggering of cpu-keepalive timer * * Releases cpu keepalive wakelock and thus allows the system to * enter late suspend according to other policies. * * @param data (not used) * * @return FALSE (to stop then timer from repeating) */ static gboolean cpu_keepalive_timer_cb(gpointer data) { (void)data; if( timer_id != 0 ) { mce_log(LL_NOTICE, "cpu-keepalive ended"); timer_id = 0; #ifdef ENABLE_WAKELOCKS wakelock_unlock(cpu_wakelock); #endif } return FALSE; }
/** Transfer resume-due-to-rtc-input wakelock from dsme to mce * * @param dbus_name name of the client issuing the request */ static void cpu_keepalive_wakeup(const gchar *dbus_name) { // FIXME: we should check that the dbus_name == DSME (void)dbus_name; /* Time of wakeup received */ wakeup_started = cpu_keepalive_get_time(); /* Timeout for the 1st keepalive message to come through */ wakeup_timeout = wakeup_started + MCE_RTC_WAKEUP_1ST_TIMEOUT_SECONDS; cpu_keepalive_rethink(); mce_log(LL_NOTICE, "rtc wakeup finished"); #ifdef ENABLE_WAKELOCKS wakelock_unlock(rtc_wakelock); #endif }
/** Evaluate need for suspend blocking */ static void mia_keepalive_rethink(void) { static bool have_lock = false; bool need_lock = (mia_keepalive_id != 0); if( have_lock == need_lock ) goto EXIT; mce_log(LL_DEBUG, "inactivity notify wakelock: %s", need_lock ? "OBTAIN" : "RELEASE"); if( (have_lock = need_lock) ) wakelock_lock("mce_inactivity_notify", -1); else wakelock_unlock("mce_inactivity_notify"); EXIT: return; }
/** Transfer resume-due-to-rtc-input wakelock from dsme to mce * * @param dbus_name name of the client issuing the request */ static void cka_clients_handle_wakeup(const gchar *dbus_name) { // FIXME: we should check that the dbus_name == DSME (void)dbus_name; /* Time of wakeup received */ cka_clients_wakeup_started = cka_tick_get_current(); /* Timeout for the 1st keepalive message to come through */ cka_clients_wakeup_timeout = cka_tick_get_timeout(cka_clients_wakeup_started, MCE_RTC_WAKEUP_1ST_TIMEOUT_S); cka_state_rethink(); mce_log(LL_NOTICE, "rtc wakeup finished"); #ifdef ENABLE_WAKELOCKS wakelock_unlock(rtc_wakelock); #endif }
/** * Callback for successful chunk I/O * * @param source The source of the activity * @param condition The I/O condition * @param data The iomon structure * @return Depending on error policy this function either exits * or returns TRUE */ static gboolean io_chunk_cb(GIOChannel *source, GIOCondition condition, gpointer data) { iomon_struct *iomon = data; gchar *buffer = NULL; gsize bytes_want = 4096; gsize bytes_read = 0; gsize chunks_read = 0; gsize chunks_done = 0; GIOStatus io_status; GError *error = NULL; gboolean status = TRUE; /* Silence warnings */ (void)condition; if (iomon == NULL) { mce_log(LL_CRIT, "iomon == NULL!"); status = FALSE; goto EXIT; } iomon->latest_io_condition = 0; /* Seek to the beginning of the file before reading if needed */ if (iomon->rewind == TRUE) { g_io_channel_seek_position(source, 0, G_SEEK_SET, &error); if( error ) { mce_log(LL_ERR, "%s: seek error: %s", iomon->file, error->message); } /* Reset errno, * to avoid false positives down the line */ errno = 0; g_clear_error(&error); } if( iomon->chunk_size < bytes_want ) { bytes_want -= bytes_want % iomon->chunk_size; } else { bytes_want = iomon->chunk_size; } buffer = g_malloc(bytes_want); #ifdef ENABLE_WAKELOCKS /* Since the locks on kernel side are released once all * events are read, we must obtain the userspace lock * before reading the available data */ wakelock_lock("mce_input_handler", -1); #endif io_status = g_io_channel_read_chars(source, buffer, bytes_want, &bytes_read, &error); /* If the read was interrupted, ignore */ if (io_status == G_IO_STATUS_AGAIN) { g_clear_error(&error); } if( bytes_read % iomon->chunk_size ) { mce_log(LL_WARN, "Incomplete chunks read from: %s", iomon->file); } /* Process the data, and optionally ignore some of it */ if( (chunks_read = bytes_read / iomon->chunk_size) ) { gchar *chunk = buffer; for( ; chunks_done < chunks_read ; chunk += iomon->chunk_size ) { ++chunks_done; if (iomon->callback(chunk, iomon->chunk_size) != TRUE) { continue; } /* if possible, seek to the end of file */ if (iomon->seekable) { g_io_channel_seek_position(iomon->iochan, 0, G_SEEK_END, &error); } /* in any case ignore rest of the data already read */ break; } } mce_log(LL_INFO, "%s: status=%s, data=%d/%d=%d+%d, skipped=%d", iomon->file, io_status_name(io_status), bytes_read, (int)iomon->chunk_size, chunks_read, bytes_read % (int)iomon->chunk_size, chunks_read - chunks_done); #ifdef ENABLE_WAKELOCKS /* Release the lock after we're done with processing it */ wakelock_unlock("mce_input_handler"); #endif g_free(buffer); /* Were there any errors? */ if (error != NULL) { mce_log(LL_ERR, "Error when reading from %s: %s", iomon->file, error->message); if ((error->code == G_IO_CHANNEL_ERROR_FAILED) && (errno == ENODEV) && (iomon->seekable)) { errno = 0; g_clear_error(&error); g_io_channel_seek_position(iomon->iochan, 0, G_SEEK_END, &error); if( error ) { mce_log(LL_ERR, "%s: seek error: %s", iomon->file, error->message); } } else { status = FALSE; } /* Reset errno, * to avoid false positives down the line */ errno = 0; g_clear_error(&error); } else if ((bytes_read == 0) && (io_status != G_IO_STATUS_EOF) && (io_status != G_IO_STATUS_AGAIN)) { mce_log(LL_ERR, "Empty read from %s", iomon->file); } EXIT: if ((status == FALSE) && (iomon != NULL) && (iomon->error_policy == MCE_IO_ERROR_POLICY_EXIT)) { // FIXME: this is not how one should exit from mainloop mce_quit_mainloop(); exit(EXIT_FAILURE); } return TRUE; }