This post briefs about the source code flow of how early suspend mechanism in power managerment works in Android. This code references are with respect to Android open source code. $ vim frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java private void setHalAutoSuspendModeLocked(boolean enable) { if (enable != mHalAutoSuspendModeEnabled) { if (DEBUG) { Slog.d(TAG, "Setting HAL auto-suspend mode to " + enable); } mHalAutoSuspendModeEnabled = enable; Trace.traceBegin(Trace.TRACE_TAG_POWER, "setHalAutoSuspend(" + enable + ")"); try { mNativeWrapper.nativeSetAutoSuspend(enable); } finally { Trace.traceEnd(Trace.TRACE_TAG_POWER); } } } $ vim frameworks/base/services/core/jni/com_android_server_power_PowerManagerService.cpp static void nativeSetAutoSuspend(JNIEnv* /* env */, jclass /* clazz */, jboolean enable) { if (enable) { android::base::Timer t; enableAutoSuspend(); if (t.duration() > 100ms) { ALOGD("Excessive delay in autosuspend_enable() while turning screen off"); } } else { android::base::Timer t; disableAutoSuspend(); if (t.duration() > 100ms) { ALOGD("Excessive delay in autosuspend_disable() while turning screen on"); } } } static JNINativeMethod gPowerManagerServiceMethods[] = { { "nativeSetAutoSuspend", "(Z)V", (void*) nativeSetAutoSuspend }, } int register_android_server_PowerManagerService(JNIEnv* env) { int res = jniRegisterNativeMethods(env, "com/android/server/power/PowerManagerService", gPowerManagerServiceMethods, NELEM(gPowerManagerServiceMethods)); (void) res; // Faked use when LOG_NDEBUG.

Implementation details

LOG_FATAL_IF(res < 0, "Unable to register native methods."); // Callbacks jclass clazz; FIND_CLASS(clazz, "com/android/server/power/PowerManagerService"); GET_METHOD_ID(gPowerManagerServiceClassInfo.userActivityFromNative, clazz, "userActivityFromNative", "(JII)V"); // Initialize for (int i = 0; i <= USER_ACTIVITY_EVENT_LAST; i++) { gLastEventTime[i] = LLONG_MIN; } gPowerManagerServiceObj = NULL; return 0; } $ vim system/core/libsuspend/autosuspend.c static int autosuspend_init(void) { if (autosuspend_ops != NULL) { return 0; } autosuspend_ops = autosuspend_wakeup_count_init(); if (autosuspend_ops == NULL) { ALOGE("failed to initialize autosuspend"); return -1; } ALOGV("autosuspend initialized"); return 0; } int autosuspend_enable(void) { int ret; ret = autosuspend_init(); if (ret) { return ret; } ALOGV("autosuspend_enable"); if (autosuspend_enabled) { return 0; } ret = autosuspend_ops->enable(); if (ret) { return ret; } autosuspend_enabled = true; return 0; } $ vim system/core/libsuspend/autosuspend_wakeup_count.cpp #define BASE_SLEEP_TIME 100000 #define MAX_SLEEP_TIME 60000000 static int state_fd = -1; static int wakeup_count_fd; using android::base::ReadFdToString; using android::base::Trim; using android::base::WriteStringToFd; static pthread_t suspend_thread; static sem_t suspend_lockout; static constexpr char sleep_state[] = "mem"; static void (*wakeup_func)(bool success) = NULL; static int sleep_time = BASE_SLEEP_TIME; static constexpr char sys_power_state[] = "/sys/power/state"; static constexpr char sys_power_wakeup_count[] = "/sys/power/wakeup_count"; static bool autosuspend_is_init = false; static void update_sleep_time(bool success) { if (success) { sleep_time = BASE_SLEEP_TIME; return; } // double sleep time after each failure up to one minute sleep_time = MIN(sleep_time * 2, MAX_SLEEP_TIME); } static void* suspend_thread_func(void* arg __attribute__((unused))) { bool success = true; while (true) { update_sleep_time(success); usleep(sleep_time); success = false; LOG(VERBOSE) << "read wakeup_count"; lseek(wakeup_count_fd, 0, SEEK_SET); std::string wakeup_count; if (!ReadFdToString(wakeup_count_fd, &wakeup_count)) { PLOG(ERROR) << "error reading from " << sys_power_wakeup_count; continue; } wakeup_count = Trim(wakeup_count); if (wakeup_count.empty()) { LOG(ERROR) << "empty wakeup count"; continue; } LOG(VERBOSE) << "wait"; int ret = sem_wait(&suspend_lockout); if (ret < 0) { PLOG(ERROR) << "error waiting on semaphore"; continue; } LOG(VERBOSE) << "write " << wakeup_count << " to wakeup_count"; if (WriteStringToFd(wakeup_count, wakeup_count_fd)) { LOG(VERBOSE) << "write " << sleep_state << " to " << sys_power_state; success = WriteStringToFd(sleep_state, state_fd); void (*func)(bool success) = wakeup_func; if (func != NULL) { (*func)(success); } } else { PLOG(ERROR) << "error writing to " << sys_power_wakeup_count; } LOG(VERBOSE) << "release sem"; ret = sem_post(&suspend_lockout); if (ret < 0) { PLOG(ERROR) << "error releasing semaphore"; } } return NULL; } static int init_state_fd(void) { if (state_fd >= 0) { return 0; } int fd = TEMP_FAILURE_RETRY(open(sys_power_state, O_CLOEXEC | O_RDWR)); if (fd < 0) { PLOG(ERROR) << "error opening " << sys_power_state; return -1; } state_fd = fd; LOG(INFO) << "init_state_fd success"; return 0; } static int autosuspend_init(void) { if (autosuspend_is_init) { return 0; } int ret = init_state_fd(); if (ret < 0) { return -1; } wak

Gotchas and common issues

  • Permission checks - verify user access rights and sudo privileges before executing system-level operations.

  • Environment configuration - double-check path variables and dependency versions to prevent runtime failures.

  • Backup safeguards - maintain configuration backups before applying system or database modifications.

Following these steps ensures clean configuration and reliable execution for how early suspend works in android.