Android 休眠(二)真.永久不休眠
Platform: RK3288
OS: Android 7.1.2
Kernel: 4.4.143
adb shell settings get system screen_off_timeout

一.SettingsProvider def_screen_off_timeout
1.1.frameworks\base\packages\SettingsProvider\res\values\defaults.xml
欸为什么是0x7fffffff 换算 十进制 是2147483647
ro.rk.screenoff_time 也是2147483647
整形最大取值就是 2147483647 换算成天数也就是24.85
<resources>
<bool name="def_dim_screen">true</bool>
<integer name="def_screen_off_timeout">0x7fffffff</integer>
<integer name="def_sleep_timeout">-1</integer>
1.2.frameworks\base\packages\SettingsProvider\src\com\android\providers\settings\DatabaseHelper.java
//add for factory as ro.rk.screenoff_time
loadSetting(stmt, Settings.System.SCREEN_OFF_TIMEOUT,
SystemProperties.getInt("ro.rk.screenoff_time", mContext.getResources().getInteger(R.integer.def_screen_off_timeout)));
1.3.frameworks\base\services\core\java\com\android\server\policy\PhoneWindowManager.java
a.观察 数据库 变化
class SettingsObserver extends ContentObserver {
SettingsObserver(Handler handler) {
super(handler);
}
void observe() {
// Observe all users' changes
……………………………………………………………………………………
resolver.registerContentObserver(Settings.System.getUriFor(
Settings.System.SCREEN_OFF_TIMEOUT), false, this,
UserHandle.USER_ALL);
b.updateSettings mLockScreenTimeout
public void updateSettings() {
ContentResolver resolver = mContext.getContentResolver();
boolean updateRotation = false;
synchronized (mLock) {
………………………………………………………………
// use screen off timeout setting as the timeout for the lockscreen
mLockScreenTimeout = Settings.System.getIntForUser(resolver,
Settings.System.SCREEN_OFF_TIMEOUT, 0, UserHandle.USER_CURRENT);
c.postDelayed
private void updateLockScreenTimeout() {
synchronized (mScreenLockTimeout) {
boolean enable = (mAllowLockscreenWhenOn && mAwake &&
mKeyguardDelegate != null && mKeyguardDelegate.isSecure(mCurrentUserId));
if (mLockScreenTimerActive != enable) {
if (enable) {
if (localLOGV) Log.v(TAG, "setting lockscreen timer");
mHandler.removeCallbacks(mScreenLockTimeout); // remove any pending requests
mHandler.postDelayed(mScreenLockTimeout, mLockScreenTimeout);
} else {
if (localLOGV) Log.v(TAG, "clearing lockscreen timer");
mHandler.removeCallbacks(mScreenLockTimeout);
}
mLockScreenTimerActive = enable;
}
}
}
1.4.frameworks\base\services\core\java\com\android\server\power\PowerManagerService.java
mScreenOffTimeoutSetting = Settings.System.getIntForUser(resolver,
Settings.System.SCREEN_OFF_TIMEOUT, DEFAULT_SCREEN_OFF_TIMEOUT,
UserHandle.USER_CURRENT);
获取休眠时间
private int getScreenOffTimeoutLocked(int sleepTimeout) {
int timeout = mScreenOffTimeoutSetting;
if (isMaximumScreenOffTimeoutFromDeviceAdminEnforcedLocked()) {
timeout = Math.min(timeout, mMaximumScreenOffTimeoutFromDeviceAdmin);
}
if (mUserActivityTimeoutOverrideFromWindowManager >= 0) {
timeout = (int)Math.min(timeout, mUserActivityTimeoutOverrideFromWindowManager);
}
if (sleepTimeout >= 0) {
timeout = Math.min(timeout, sleepTimeout);
}
return Math.max(timeout, mMinimumScreenOffTimeoutConfig);
}
//根据nextTimeOut延迟发送信息,信息被处理后,将重新调用updatePowerStateLocked,于是再次进入到该方法
//通过不断进入该方法,不断评估是否根据用户动作亮、熄屏等
private void updateUserActivitySummaryLocked(long now, int dirty) {
if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY
| DIRTY_WAKEFULNESS | DIRTY_SETTINGS)) != 0) {
mHandler.removeMessages(MSG_USER_ACTIVITY_TIMEOUT);
long nextTimeout = 0;
if (mWakefulness == WAKEFULNESS_AWAKE
|| mWakefulness == WAKEFULNESS_DREAMING
|| mWakefulness == WAKEFULNESS_DOZING) {
//获取进入休眠状态的时间sleepTimeout
//getSleepTimeoutLocked中会判断休眠时间和屏幕熄灭时间的关系
//如果休眠时间sleepTimeout小于屏幕熄灭时间screenOfftime,
//则休眠时间被调整为屏幕熄灭时间,因为屏幕亮屏状态下,终端不能进入休眠
final int sleepTimeout = getSleepTimeoutLocked();
//获取屏幕熄灭的时间
final int screenOffTimeout = getScreenOffTimeoutLocked(sleepTimeout);
//获取屏幕变暗的时间
final int screenDimDuration = getScreenDimDurationLocked(screenOffTimeout);
……………………………………………………
if (mUserActivitySummary != 0 && nextTimeout >= 0) {
Message msg = mHandler.obtainMessage(MSG_USER_ACTIVITY_TIMEOUT);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, nextTimeout);
}
} else {
mUserActivitySummary = 0;
}
二.永久休眠 方案一 WakeLock
2.1.WakeLock 唤醒锁
a.权限
<uses-permission android:name="android.permission.WAKE_LOCK" />
c.WakeLock 常见的锁
WakeLock 分类如下:
PARTIAL_WAKE_LOCK: 保持CPU 运转 灭屏 关闭键盘背光的情况下
PROXIMITY_SCREEN_OFF_WAKE_LOCK: 基于距离感应器熄灭屏幕。最典型的运用场景是我们贴近耳朵打电话时,屏幕会自动熄灭
SCREEN_DIM_WAKE_LOCK:保持CPU 运转,允许保持屏幕显示但有可能是灰的,允许关闭键盘灯
SCREEN_BRIGHT_WAKE_LOCK:保持CPU 运转,允许保持屏幕高亮显示,允许关闭键盘灯
FULL_WAKE_LOCK:保持CPU 运转,保持屏幕高亮显示,键盘灯也保持亮度
SCREEN_DIM_WAKE_LOCK/SCREEN_BRIGHT_WAKE_LOCK/FULL_WAKE_LOCK:这三种WakeLock都已经过时了 它们的目的是为了保持屏幕长亮 Android官方建议用getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);方式替换 因为比起申请WakeLock 这种方式更简单 还不需要特别申请android.permission.WAKE_LOCK权限
DOZE_WAKE_LOCK/DRAW_WAKE_LOCK:隐藏的分类,系统级别才会用到
WakeLock的flag如下:
ACQUIRE_CAUSES_WAKEUP:点亮屏幕 比如应用接收到通知后,屏幕亮起。
ON_AFTER_RELEASE:释放WakeLock后 屏幕不马上熄灭 保持屏幕亮起一段时间
UNIMPORTANT_FOR_LOGGING:隐藏的flag 系统级别才会用到
b.wakeLock.acquire(); wakeLock.release();
package com.gatsby.wakelockservice;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.util.Log;
public class WakeLockService extends Service {
private WakeLock wakeLock = null;
@Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
acquireWakeLock();
}
@Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
Log.d("gatsby","WakeLockService onDestroy");
releaseWakeLock();
}
// 获取电源锁
private void acquireWakeLock() {
if (null == wakeLock) {
PowerManager pm = (PowerManager) this.getSystemService(Context.POWER_SERVICE);
wakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE,
"gatsby-wakelockService-TAG");
if (null != wakeLock) {
wakeLock.acquire();
}
}
}
// 释放设备电源锁
private void releaseWakeLock() {
if (null != wakeLock) {
wakeLock.release();
wakeLock = null;
}
}
}
d.研究一下 源码 先欢迎 四年级学生森下下士 我们的老大哥 小草凡 Android 功耗分析之wakelock

先跟着老大哥 走了一遍源码
frameworks/base/core/java/android/os/PowerManager.java acquire--->acquireLocked---->PowerManagerService.acquireWakeLock frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java acquireWakeLock--->acquireWakeLockInternal---->updatePowerStateLocked---->updateSuspendBlockerLocked---->mWakeLockSuspendBlocker.acquire---->PowerManagerService$SuspendBlockerImpl.acquire---->nativeAcquireSuspendBlocker frameworks/base/services/core/jni/com_android_server_power_PowerManagerService.cpp nativeAcquireSuspendBlocker---->acquire_wake_lock
hardware\libhardware_legacy\power\power.c
12-06 12:10:48.884 457 855 I power : release_wake_lock id='PowerManagerService.WakeLocks' 12-06 12:10:59.157 457 457 I power : acquire_wake_lock lock=1 id='PowerManagerService.WakeLocks' 12-06 12:10:59.193 457 923 I power : release_wake_lock id='PowerManagerService.WakeLocks' 12-06 12:10:59.852 457 568 I power : acquire_wake_lock lock=1 id='PowerManagerService.Broadcasts' 12-06 12:10:59.854 457 568 I power : release_wake_lock id='PowerManagerService.Display' 12-06 12:11:00.347 457 457 I power : release_wake_lock id='PowerManagerService.Broadcasts' 12-06 12:11:04.196 457 587 I power : acquire_wake_lock lock=1 id='PowerManagerService.WakeLocks' 12-06 12:11:04.341 457 457 I power : release_wake_lock id='PowerManagerService.WakeLocks' 12-06 12:11:04.854 457 598 I power : acquire_wake_lock lock=1 id='KeyEvents'
/sys/power/wake_lock写入节点
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;
size_t len;
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;
}
龙套三人组:听不见!重来!/根本听不见!再说一遍!/听不见!重来/这么小声还想开军舰! 到了power这里还不算完
到 android 休眠唤醒机制分析(一) — wake_lock
static struct wake_lock xh_charge_display_lock;// 申请锁 wake_lock_init(&xh_charge_display_lock, WAKE_LOCK_SUSPEND, "xh_charge_display_lock");// WAKE_LOCK_SUSPEND 阻止进入深度休眠模式 wake_lock(&xh_charge_display_lock);//保管锁
2.2.patch
diff --git a/packages/apps/Settings/AndroidManifest.xml b/packages/apps/Settings/AndroidManifest.xml
index 52841dd..5764d40 100755
--- a/packages/apps/Settings/AndroidManifest.xml
+++ b/packages/apps/Settings/AndroidManifest.xml
@@ -86,6 +86,7 @@
<uses-permission android:name="android.permission.PEERS_MAC_ADDRESS"/>
<uses-permission android:name="android.permission.MANAGE_NOTIFICATIONS"/>
<uses-permission android:name="android.permission.DELETE_PACKAGES"/>
+ <uses-permission android:name="android.permission.WAKE_LOCK" />
<application android:label="@string/settings_label"
android:icon="@mipmap/ic_launcher_settings"
@@ -3272,6 +3273,9 @@
android:enabled="@bool/config_has_help" />
<activity
android:name="com.android.settings.display.ScreenScaleActivity"/>
+
+ <service android:name=".WakeLockService" >
+ </service>
<!-- This is the longest AndroidManifest.xml ever. -->
</application>
</manifest>
diff --git a/packages/apps/Settings/src/com/android/settings/DisplaySettings.java b/packages/apps/Settings/src/com/android/settings/DisplaySettings.java
index 2b52b39..f084af8 100755
--- a/packages/apps/Settings/src/com/android/settings/DisplaySettings.java
+++ b/packages/apps/Settings/src/com/android/settings/DisplaySettings.java
@@ -110,7 +110,8 @@ public class DisplaySettings extends SettingsPreferenceFragment implements
private String mProduct;
private ListPreference mDensityListPreference;
DisplayMetrics dm;
- private String density_olddegree;
+ private String density_olddegree;
+ private Intent wakelock_intent;
@Override
protected int getMetricsCategory() {
@@ -469,12 +470,19 @@ public class DisplaySettings extends SettingsPreferenceFragment implements
@Override
public boolean onPreferenceChange(Preference preference, Object objValue) {
final String key = preference.getKey();
- if (KEY_SCREEN_TIMEOUT.equals(key)) {
+ final Context context = preference.getContext();
+ if (KEY_SCREEN_TIMEOUT.equals(key)) {
+ wakelock_intent = new Intent(context,WakeLockService.class);
try {
int value = Integer.parseInt((String) objValue);
if (value == 0) {
value = Integer.MAX_VALUE;
- }
+ context.startService(wakelock_intent);
+ SystemProperties.set("persist.sys.wakeLock","1");
+ }else {
+ context.stopService(wakelock_intent);
+ SystemProperties.set("persist.sys.wakeLock","0");
+ }
Settings.System.putInt(getContentResolver(), SCREEN_OFF_TIMEOUT, value);
updateTimeoutPreferenceDescription(value);
} catch (NumberFormatException e) {
diff --git a/packages/apps/Settings/src/com/android/settings/HdmiReceiver.java b/packages/apps/Settings/src/com/android/settings/HdmiReceiver.java
index aff17a5..604997c 100755
--- a/packages/apps/Settings/src/com/android/settings/HdmiReceiver.java
+++ b/packages/apps/Settings/src/com/android/settings/HdmiReceiver.java
@@ -33,6 +33,11 @@ import android.widget.Toast;
import android.os.DisplayOutputManager;
import com.android.settings.R;
+import android.provider.Settings;
+import android.os.Bundle;
+import android.content.Intent;
+import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
+
public class HdmiReceiver extends BroadcastReceiver {
private final String HDMI_ACTION = "android.intent.action.HDMI_PLUG";
private final String BOOT_ACTION="android.intent.action.BOOT_COMPLETED";
@@ -47,6 +52,8 @@ public class HdmiReceiver extends BroadcastReceiver {
private SharedPreferences preferences;
private File DualModeFile = new File("/sys/class/graphics/fb0/dual_mode");
private DisplayOutputManager mDisplayManagement = null;
+ private Intent wakelock_intent;
+
@Override
public void onReceive(Context context, Intent intent) {
mcontext = context;
@@ -125,6 +132,18 @@ public class HdmiReceiver extends BroadcastReceiver {
SystemProperties.set("sys.abc_switch", "1");
//InitDualModeTask initDualModeTask=new InitDualModeTask();
//initDualModeTask.execute();
+ try {
+ long screen_off_timeout = Settings.System.getLong(context.getContentResolver(), SCREEN_OFF_TIMEOUT,30000);
+ boolean enable_wakeLock = (SystemProperties.getInt("persist.sys.wakeLock", 0) == 1);
+ Log.d("gatsby","HdmiReceiver HdmiReceiver enable_wakeLock ->"+enable_wakeLock);
+ wakelock_intent = new Intent(context,WakeLockService.class);
+ if((screen_off_timeout == Integer.MAX_VALUE) && enable_wakeLock){
+ Log.d("gatsby","HdmiReceiver HdmiReceiver");
+ context.startService(wakelock_intent);
+ }
+ }catch (NumberFormatException e) {
+ Log.e("gatsby", "could not persist screen timeout setting", e);
+ }
}
}
diff --git a/packages/apps/Settings/src/com/android/settings/WakeLockService.java b/packages/apps/Settings/src/com/android/settings/WakeLockService.java
new file mode 100755
index 0000000..8c021cd
--- /dev/null
+++ b/packages/apps/Settings/src/com/android/settings/WakeLockService.java
@@ -0,0 +1,52 @@
+package com.android.settings;
+
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.PowerManager;
+import android.os.PowerManager.WakeLock;
+import android.util.Log;
+
+public class WakeLockService extends Service {
+
+ private WakeLock wakeLock = null;
+
+ @Override
+ public IBinder onBind(Intent arg0) {
+ return null;
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ Log.d("gatsby","WakeLockService onCreate");
+ acquireWakeLock();
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ Log.d("gatsby","WakeLockService onDestroy");
+ releaseWakeLock();
+ }
+
+ private void acquireWakeLock() {
+ if (null == wakeLock) {
+ PowerManager pm = (PowerManager) this.getSystemService(Context.POWER_SERVICE);
+ wakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE,
+ "gatsby-wakelockService-TAG");
+ if (null != wakeLock) {
+ wakeLock.acquire();
+ }
+ }
+ }
+
+ private void releaseWakeLock() {
+ if (null != wakeLock) {
+ wakeLock.release();
+ wakeLock = null;
+ }
+ }
+
+}
测试 方法
am startservice -n com.android.settings/com.android.settings.WakeLockService am stopservice -n com.android.settings/com.android.settings.WakeLockService
查看锁 dumpsys power|grep -i wake
通过adb命令查看WakeLock锁的个数: dumpsys power uid=1000是系统用户

三.永久不休眠 方案二 死循环休眠

浙公网安备 33010602011771号