___2017

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理
  328 随笔 :: 18 文章 :: 15 评论 :: 18万 阅读
1
2
3
4
5
6
受不了xxxx恶心人的行为,遂搬迁至博客园。
始发:2016-12-16 13:11:41
 
版本信息:
Linux:3.10
Android:4.4

 

一、PowerManagerService

引起休眠动作(进入休眠前执行一些必要的操作)的事件有两个:

  • PowerKey事件,通过JNI调用PowerManagerService中的goToSleepFromNative()方法
  • Timeout,指【设置->显示->休眠】中设置的Timeout数值

Android休眠在PowerManagerService中的流程如下图:

图示:最终都会调用到updatePowerStateLocked()方法,在更新一些标志的状态、发送休眠通知后,调用updateSuspendBlockerLocked()执行休眠锁的释放动作

 

二、PowerManagerService中Timeout处理流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
/**
 * PowerManagerService设置了很多的标志位,用来标识某个事件的状态是否发生改变,比如:
 * DIRTY_SETTINGS,一旦系统设置发生变化,DIRTY_SETTINGS位就会被设置,
 * 处理函数检测到DIRTY_SETTINGS被置位,就进行相应的动作
 * dirty:包含了所有发生变化的标志
 */
private void updateUserActivitySummaryLocked(long now, int dirty) {
    // Update the status of the user activity timeout timer.
    if ((dirty & (DIRTY_USER_ACTIVITY | DIRTY_WAKEFULNESS | DIRTY_SETTINGS)) != 0) {
        // 1、消息队列中含有尚未处理的MSG_USER_ACTIVITY_TIMEOUT,就移除,避免重复进入休眠操作
        mHandler.removeMessages(MSG_USER_ACTIVITY_TIMEOUT);
  
        long nextTimeout = 0;
        // 2、mWakefulness != WAKEFULNESS_ASLEEP:当前醒着
        if (mWakefulness != WAKEFULNESS_ASLEEP) {
            // 3、获取Timeout的值,比如30s
            final int screenOffTimeout = getScreenOffTimeoutLocked();
            // 屏幕在熄灭前,会先变暗一段时间,这段时间叫DimDuration,计算方式:
            // SCREEN_DIM_DURATION = 7s,MAXIMUM_SCREEN_DIM_RATIO = 0.2
            // Math.min(SCREEN_DIM_DURATION, (int)(screenOffTimeout * MAXIMUM_SCREEN_DIM_RATIO))
            // 4、获取DimDuration的值,30s x 0.2 = 6s
            final int screenDimDuration = getScreenDimDurationLocked(screenOffTimeout);
  
            mUserActivitySummary = 0;
            // 5、mLastUserActivityTime >= mLastWakeTime: 用户最后使用机器的时间在上次唤醒时间之后
            if (mLastUserActivityTime >= mLastWakeTime) {
                // nextTimeout:此处指到屏幕Dim的时间间隔
                // 6、nextTimeout的时间:BASE + 30 - 6 = BASE + 24
                nextTimeout = mLastUserActivityTime
                        + screenOffTimeout - screenDimDuration;
                if (now < nextTimeout) {
                    // now在屏幕Dim之前,说明屏幕亮着,设置flag
                    mUserActivitySummary |= USER_ACTIVITY_SCREEN_BRIGHT;
                } else {
                    // extTimeout:此处指到屏幕熄灭的时间间隔
                    //7、nextTimeout的时间:BASE + 30 = BASE + 30
                    nextTimeout = mLastUserActivityTime + screenOffTimeout;
                    // 8、now处于屏幕Dim之后、屏幕熄灭之前设置DIM flag
                    if (now < nextTimeout) {
                        mUserActivitySummary |= USER_ACTIVITY_SCREEN_DIM;
                    }
                }
            }
            if (mUserActivitySummary == 0
                    && mLastUserActivityTimeNoChangeLights >= mLastWakeTime) {
                nextTimeout = mLastUserActivityTimeNoChangeLights + screenOffTimeout;
                if (now < nextTimeout
                        && mDisplayPowerRequest.screenState
                                != DisplayPowerRequest.SCREEN_STATE_OFF) {
                    mUserActivitySummary = mDisplayPowerRequest.screenState
                            == DisplayPowerRequest.SCREEN_STATE_BRIGHT ?
                            USER_ACTIVITY_SCREEN_BRIGHT : USER_ACTIVITY_SCREEN_DIM;
                }
            }
            // mUserActivitySummary发生了改变
            if (mUserActivitySummary != 0) {
                Message msg = mHandler.obtainMessage(MSG_USER_ACTIVITY_TIMEOUT);
                Slog.i(TAG, "updateUserActivitySummaryLocked, send MSG_USER_ACTIVITY_TIMEOUT");
                msg.setAsynchronous(true);
                mHandler.sendMessageAtTime(msg, nextTimeout);
            }
        } else {
            mUserActivitySummary = 0;
        }
    }
}

 

SG_USER_ACTIVITY_TIMEOUT事件处理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
private final class PowerManagerHandler extends Handler {
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
        case MSG_USER_ACTIVITY_TIMEOUT:
            handleUserActivityTimeout();
            break;
    }
}
  
/**
 * Called when a user activity timeout has occurred.
 * Simply indicates that something about user activity has changed so that the new
 * state can be recomputed when the power state is updated.
 */
private void handleUserActivityTimeout() { // runs on handler thread
    mDirty |= DIRTY_USER_ACTIVITY;
    updatePowerStateLocked();
}

  

三、PowerManagerService中休眠锁的获取/释放

这部分代码清晰,直接看下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
private void updatePowerStateLocked() {
    if (!mSystemReady || mDirty == 0) {
        return;
    }
    // Phase 0: Basic state updates.
 
    // Phase 1: Update wakefulness.
 
    // Phase 2: Update dreams and display power state.
 
    // Phase 3: Send notifications, if needed.
 
    // Phase 4: Update suspend blocker.
    // Because we might release the last suspend blocker here, we need to make sure
    // we finished everything else first!
    updateSuspendBlockerLocked();
}
 
/**
 * Updates the suspend blocker that keeps the CPU alive.
 */
private void updateSuspendBlockerLocked() {
    final boolean needWakeLockSuspendBlocker = ((mWakeLockSummary & WAKE_LOCK_CPU) != 0);
    final boolean needDisplaySuspendBlocker = needDisplaySuspendBlocker();
 
    // First acquire suspend blockers if needed.
    if (needWakeLockSuspendBlocker && !mHoldingWakeLockSuspendBlocker) {
        mWakeLockSuspendBlocker.acquire();
        mHoldingWakeLockSuspendBlocker = true;
    }
    if (needDisplaySuspendBlocker && !mHoldingDisplaySuspendBlocker) {
        mDisplaySuspendBlocker.acquire();
        mHoldingDisplaySuspendBlocker = true;
    }
 
    // Then release suspend blockers if needed.
    if (!needWakeLockSuspendBlocker && mHoldingWakeLockSuspendBlocker) {
        mWakeLockSuspendBlocker.release();
        mHoldingWakeLockSuspendBlocker = false;
    }
    if (!needDisplaySuspendBlocker && mHoldingDisplaySuspendBlocker) {
        mDisplaySuspendBlocker.release();
        mHoldingDisplaySuspendBlocker = false;
    }
}
 
private final class SuspendBlockerImpl implements SuspendBlocker {
    private final String mName;
    private int mReferenceCount;
 
    public SuspendBlockerImpl(String name) {
        mName = name;
    }
 
    @Override
    public void acquire() {
        synchronized (this) {
            mReferenceCount += 1;
            if (mReferenceCount == 1) {
                nativeAcquireSuspendBlocker(mName);
            }
        }
    }
 
    @Override
    public void release() {
        synchronized (this) {
            mReferenceCount -= 1;
            if (mReferenceCount == 0) {
  
                nativeReleaseSuspendBlocker(mName);
            }
        }
    }
}

  

休眠锁的获取和释放,最终通过JNI方式读写/sys/power/wake_lock、/sys/power/wake_unlock

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
// 1、JNI接口
com_android_server_power_PowerManagerService.cpp (frameworks\base\services\jni)
static void nativeAcquireSuspendBlocker(JNIEnv *env, jclass clazz, jstring nameStr) {
    ScopedUtfChars name(env, nameStr);
    acquire_wake_lock(PARTIAL_WAKE_LOCK, name.c_str());
}
 
// 2、定义要操作的文件
power.c (hardware\libhardware_legacy\power)
const char *const NEW_PATHS[] = {
    "/sys/power/wake_lock",
    "/sys/power/wake_unlock",
};
 
// 3、初始化设备节点
static inline void initialize_fds(void)
{
    if (g_initialized == 0) {
        if(open_file_descriptors(NEW_PATHS) < 0)
            open_file_descriptors(OLD_PATHS);
        g_initialized = 1;
    }
}
 
static int open_file_descriptors(const char * const paths[])
{
    int i;
    for (i=0; i<OUR_FD_COUNT; i++) {
        int fd = open(paths[i], O_RDWR);
        if (fd < 0) {
            fprintf(stderr, "fatal error opening \"%s\"\n", paths[i]);
            g_error = errno;
            return -1;
        }
        g_fds[i] = fd;
    }
 
    g_error = 0;
    return 0;
}
 
// 4、id即为锁的名字,之后就是读写设备
int acquire_wake_lock(int lock, const char* id)
{
    initialize_fds();
 
    if (g_error) return g_error;
 
    int fd;
 
    if (lock == PARTIAL_WAKE_LOCK) {
        fd = g_fds[ACQUIRE_PARTIAL_WAKE_LOCK];
    } else {
        return EINVAL;
    }
 
    return write(fd, id, strlen(id));
}

 

posted on   yin'xiang  阅读(748)  评论(0编辑  收藏  举报
编辑推荐:
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示