Android 休眠流程的一点理解

1.电源管理通过监测display的状态,当灭屏时则发起休眠的流程,调用native层的方法继续往下走。首先是在DisplayPowerController中收到MSG_UPDATE_POWER_STATE消息,随后经过一系列的回调了DisplayBlanker接口的requestDisplayState。 然后是DisplayPowerCallbacks接口的onDisplayStateChange方法在PowerManagerService中onDisplayStateChange。

        @Override
        public void onDisplayStateChange(int state) {
            // This method is only needed to support legacy display blanking behavior
            // where the display's power state is coupled to suspend or to the power HAL.
            // The order of operations matters here.
            synchronized (mLock) {
                if (mDisplayState != state) {
                    mDisplayState = state;
                    if (state == Display.STATE_OFF) {
                        if (!mDecoupleHalInteractiveModeFromDisplayConfig) {
                            setHalInteractiveModeLocked(false);
                        }
                        if (!mDecoupleHalAutoSuspendModeFromDisplayConfig) {
                            setHalAutoSuspendModeLocked(true);
                        }
                    } else {
                        if (!mDecoupleHalAutoSuspendModeFromDisplayConfig) {
                            setHalAutoSuspendModeLocked(false);
                        }
                        if (!mDecoupleHalInteractiveModeFromDisplayConfig) {
                            setHalInteractiveModeLocked(true);
                        }
                    }
                }
            }
        }


在我司的方案中,是默认的不解耦的方案。所以updatePowerStateLocked updateSuspendBlockerLocked();那里不会去启动休眠的流程,而是在display state发生change时和display的状态绑定在一起。
<bool name="config_powerDecoupleAutoSuspendModeFromDisplay">false</bool>

    <!-- Power Management: Specifies whether to decouple the auto-suspend state of the
         device from the display on/off state.

         When false, autosuspend_disable() will be called before the display is turned on
         and autosuspend_enable() will be called after the display is turned off.
         This mode provides best compatibility for devices using legacy power management
         features such as early suspend / late resume.

         When true, autosuspend_display() and autosuspend_enable() will be called
         independently of whether the display is being turned on or off.  This mode
         enables the power manager to suspend the application processor while the
         display is on.

         This resource should be set to "true" when a doze component has been specified
         to maximize power savings but not all devices support it.

         Refer to autosuspend.h for details.
    -->
    <bool name="config_powerDecoupleAutoSuspendModeFromDisplay">false</bool>

2.setHalAutoSuspendModeLocked这里并不能控制系统是否立即进入休眠,是否进入休眠和唤醒是由另外的nativeAcquireSuspendBlocker和nativeReleaseSuspendBlocker是否释放SuspendBlocker决定的。正如函数名字所言,这是一级控制开关,enable or disable,enable了才能休眠,在/sys/power/state下是应用层设置的可支持的休眠模式,像现在p的gtvs版本一直都是freeze mem。

static void nativeSetAutoSuspend(JNIEnv* /* env */, jclass /* clazz */, jboolean enable) {
    if (enable) {
        android::base::Timer t;
        autosuspend_enable();
        if (t.duration() > 100ms) {
            ALOGD("Excessive delay in autosuspend_enable() while turning screen off");
        }
    } else {
        android::base::Timer t;
        autosuspend_disable();
        if (t.duration() > 100ms) {
            ALOGD("Excessive delay in autosuspend_disable() while turning screen on");
        }
    }
}
static void nativeAcquireSuspendBlocker(JNIEnv *env, jclass /* clazz */, jstring nameStr) {
    ScopedUtfChars name(env, nameStr);
    acquire_wake_lock(PARTIAL_WAKE_LOCK, name.c_str());
}

static void nativeReleaseSuspendBlocker(JNIEnv *env, jclass /* clazz */, jstring nameStr) {
    ScopedUtfChars name(env, nameStr);
    release_wake_lock(name.c_str());
}

 


3.nativeAcquireSuspendBlocker和nativeReleaseSuspendBlocker。在BlockSuspender aquire和release的时候会对应调用这两个jni的函数,然后在里面会经由hardware/libhardware_legacy/power.c里面的两个用的很广的函数acquire_wake_lock和release_wake_lock,将对应的suspender的名称写到/sys/power/wake_lock和/sys/power/wake_unlock里面,然后由kernel来监控进行相应的唤醒和休眠的动作。以前误解应用层只是个计数的效果,忽略了这个BlockSuspender实际上会直接控制kernel开放给用户态的节点,一开始看的时候也有段时间没找到写这个很明显的PMS的锁的位置。

        @Override
        public void acquire() {
            synchronized (this) {
                mReferenceCount += 1;
                if (mReferenceCount == 1) {
                    if (DEBUG_SPEW) {
                        Slog.d(TAG, "Acquiring suspend blocker \"" + mName + "\".");
                    }
                    Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, mTraceName, 0);
                    nativeAcquireSuspendBlocker(mName);
                }
            }
        }

        @Override
        public void release() {
            synchronized (this) {
                mReferenceCount -= 1;
                if (mReferenceCount == 0) {
                    if (DEBUG_SPEW) {
                        Slog.d(TAG, "Releasing suspend blocker \"" + mName + "\".");
                    }
                    nativeReleaseSuspendBlocker(mName);
                    Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, mTraceName, 0);
                } else if (mReferenceCount < 0) {
                    Slog.wtf(TAG, "Suspend blocker \"" + mName
                            + "\" was released without being acquired!", new Throwable());
                    mReferenceCount = 0;
                }
            }
        }
enum {
    ACQUIRE_PARTIAL_WAKE_LOCK = 0,
    RELEASE_WAKE_LOCK,
    OUR_FD_COUNT
};

const char * const OLD_PATHS[] = {
    "/sys/android_power/acquire_partial_wake_lock",
    "/sys/android_power/release_wake_lock",
};

const char * const NEW_PATHS[] = {
    "/sys/power/wake_lock",
    "/sys/power/wake_unlock",
};
int
acquire_wake_lock(int lock, const char* id)
{
    initialize_fds();

//    ALOGI("acquire_wake_lock lock=%d id='%s'\n", lock, id);

    if (g_error) return g_error;

    int fd;
    ssize_t ret;

    if (lock != PARTIAL_WAKE_LOCK) {
        return -EINVAL;
    }

    fd = g_fds[ACQUIRE_PARTIAL_WAKE_LOCK];

    ret = write(fd, id, strlen(id));
    if (ret < 0) {
        return -errno;
    }

    return ret;
}

int
release_wake_lock(const char* id)
{
    initialize_fds();

//    ALOGI("release_wake_lock id='%s'\n", id);

    if (g_error) return g_error;

    ssize_t len = write(g_fds[RELEASE_WAKE_LOCK], id, strlen(id));
    if (len < 0) {
        return -errno;
    }
    return len;
}


4.接着setHalAutoSuspendModeLocked往下,会调到system/core/libsuspend下面。enable和disable最终对应auto_suspend_wakeup_count.cpp内的autosuspend_wakeup_count_enable和autosuspend_wakeup_count_disable函数。这里面是通过信号量来做同步开关的控制,enable就sem_post来打开wake_count的写控制,disable就sem_wait进行阻塞。enable的时候,会把mem写到/sys/power/state,会把sys/power/wakeup_count读出来又写回去,还是不了解为啥。

static int autosuspend_wakeup_count_enable(void) {
    LOG(VERBOSE) << "autosuspend_wakeup_count_enable";

    int ret = autosuspend_init();
    if (ret < 0) {
        LOG(ERROR) << "autosuspend_init failed";
        return ret;
    }

    ret = sem_post(&suspend_lockout);
    if (ret < 0) {
        PLOG(ERROR) << "error changing semaphore";
    }

    LOG(VERBOSE) << "autosuspend_wakeup_count_enable done";

    return ret;
}

static int autosuspend_wakeup_count_disable(void) {
    LOG(VERBOSE) << "autosuspend_wakeup_count_disable";

    if (!autosuspend_is_init) {
        return 0;  // always successful if no thread is running yet
    }

    int ret = sem_wait(&suspend_lockout);

    if (ret < 0) {
        PLOG(ERROR) << "error changing semaphore";
    }

    LOG(VERBOSE) << "autosuspend_wakeup_count_disable done";

    return ret;
}
        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);

 

5.在上面的流程中在休眠时完成了对设备节点/sys/power/state写入mem的操作,在kernel中注册了对这个设备节点操作的函数。后续唤醒源的条件满足后就可以进入休眠。

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值