Hi tree

行有不得,反求诸己

0%

Android禁用自动休眠和锁屏

考古以前放在有道的笔记,仅作记录

休眠

所谓自动休眠,就是指用户长时间内没有跟设备进行交互,然后触发了自动息屏流程。

而按power键灭屏或者自动息屏事件都是在PowerManagerService中处理的。

具体的流程分析,// TODO

先帖两篇相关的博客:https://www.jianshu.com/p/9241f3a91095 && https://www.cnblogs.com/rainey-forrest/p/13292638.html

总之,在PowerManagerServiceupdateUserActivitySummaryLocked方法中,会计算用户没有活动的时间,当这个时间达到用户设置的timeout时,就会触发休眠流程。用户设置的休眠时间通过getScreenOffTimeoutLocked获取,在getScreenOffTimeoutLocked中,发现有一个系统最小的屏幕超时变量mMinimumScreenOffTimeoutConfig,这个值在frameworks/base/core/res/res/values/config.xml中的config_minimumScreenOffTimeout定义,所以,我们实现禁止设备自动休眠的方法为,将这个config_minimumScreenOffTimeout设置为尽可能大的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 1170fbe..e4ac8d7 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2428,7 +2428,7 @@
This value must be greater than zero, otherwise the device will immediately
fall asleep again as soon as it is awoken.
-->
- <integer name="config_minimumScreenOffTimeout">10000</integer>
+ <integer name="config_minimumScreenOffTimeout">2147483647</integer>

<!-- User activity timeout: Maximum screen dim duration in milliseconds.

锁屏

锁屏出现的时机:LockScreen is shown after reboot or after screen timeout / short press on power. // 来自源码LockPatternUtils.java中的注释

那么当我们浏览一下LockPatternUtils.java时,就会发现其中有一个isLockScreenDisabled方法,也就是说,Android系统是支持默认禁用锁屏功能的。

那么当我们看isLockScreenDisabled方法的内容时,就会发现:

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
LockPatternUtils.java

/**
* Determine if LockScreen is disabled for the current user. This is used to decide whether
* LockScreen is shown after reboot or after screen timeout / short press on power.
*
* @return true if lock screen is disabled
*/
@UnsupportedAppUsage
public boolean isLockScreenDisabled(int userId) {
if (isSecure(userId)) {
return false;
}
boolean disabledByDefault = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_disableLockscreenByDefault);
boolean isSystemUser = UserManager.isSplitSystemUser() && userId == UserHandle.USER_SYSTEM;
UserInfo userInfo = getUserManager().getUserInfo(userId);
boolean isDemoUser = UserManager.isDeviceInDemoMode(mContext) && userInfo != null
&& userInfo.isDemo();
return getBoolean(DISABLE_LOCKSCREEN_KEY, false, userId)
|| (disabledByDefault && !isSystemUser)
|| isDemoUser;
}

public final static String DISABLE_LOCKSCREEN_KEY = "lockscreen.disabled";

发现有个disabledByDefault变量,它在初始化的时候,也是从config.xml中获取的初始值,那么理论上可以通过修改config_disableLockscreenByDefault的值为true去实现禁用锁屏。

之所以说理论上,是因为我没有去试,这里需要一个有缘人验证可行性。

回过头来看这个方法的return部分,用到了两个逻辑或,也就是说,三个不同的表达式,只要有一个为true,这个方法就会返回true。

isDemoUser可能涉及到Android的多用户或者什么特殊模式,不去深究。

所以剩下一个getBoolean(DISABLE_LOCKSCREEN_KEY, false, userId)可以探索。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private boolean getBoolean(String secureSettingKey, boolean defaultValue, int userId) {
try {
return getLockSettings().getBoolean(secureSettingKey, defaultValue, userId);
} catch (RemoteException re) {
return defaultValue;
}
}


@UnsupportedAppUsage
@VisibleForTesting
public ILockSettings getLockSettings() {
if (mLockSettingsService == null) {
ILockSettings service = ILockSettings.Stub.asInterface(
ServiceManager.getService("lock_settings"));
mLockSettingsService = service;
}
return mLockSettingsService;
}

getBoolean方法中,调用了LockSettingsService.javagetBoolean方法,getLockSettings()方法中获取了ILockSettings的Binder代理对象,具体实现在LockSettingsService.java中。

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
LockSettingsService.java

@Override
public boolean getBoolean(String key, boolean defaultValue, int userId) {
checkReadPermission(key, userId);
String value = getStringUnchecked(key, null, userId);
return TextUtils.isEmpty(value) ?
defaultValue : (value.equals("1") || value.equals("true"));
}

public String getStringUnchecked(String key, String defaultValue, int userId) {
if (Settings.Secure.LOCK_PATTERN_ENABLED.equals(key)) {
long ident = Binder.clearCallingIdentity();
try {
return mLockPatternUtils.isLockPatternEnabled(userId) ? "1" : "0";
} finally {
Binder.restoreCallingIdentity(ident);
}
}

if (userId == USER_FRP) {
return getFrpStringUnchecked(key);
}

if (LockPatternUtils.LEGACY_LOCK_PATTERN_ENABLED.equals(key)) {
key = Settings.Secure.LOCK_PATTERN_ENABLED;
}

return mStorage.readKeyValue(key, defaultValue, userId);
}

getBoolean的具体实现,通过getStringUnchecked方法获取返回值。mStorageLockSettingsStorage的实例,大概是用来保存一些跟锁屏相关的设置,可能会包括PIN、Password等吧。

看到这里发现是去读某个key的值,这个key的传参为DISABLE_LOCKSCREEN_KEY,那么我们可以看一下是在哪里write的DISABLE_LOCKSCREEN_KEY的值。

直接在LockSettingsService.java里搜索DISABLE_LOCKSCREEN_KEY,write相关的共有三处,其中的一处我们发现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public LockSettingsStorage getStorage() {                   
final LockSettingsStorage storage = new LockSettingsStorage(mContext);
storage.setDatabaseOnCreateCallback(new LockSettingsStorage.Callback() {
@Override
public void initialize(SQLiteDatabase db) {
// Get the lockscreen default from a system property, if available
boolean lockScreenDisable = SystemProperties.getBoolean(
"ro.lockscreen.disable.default", false);
if (lockScreenDisable) {
storage.writeKeyValue(db, LockPatternUtils.DISABLE_LOCKSCREEN_KEY, "1", 0);
}
}
});
return storage;
}

mStorage初始化的时候,调用到这个getStorage方法,其中会根据一个属性的值,设置DISABLE_LOCKSCREEN_KEY的值

也就是说,只要ro.lockscreen.disable.default为true,DISABLE_LOCKSCREEN_KEY也会设置为1,也就是true,也就是系统默认禁用了锁屏功能。

所以我们只需要将ro.lockscreen.disable.default设置为true,就可以禁用锁屏了.

1
2
3
4
5
6
7
8
9
10
11
12
13
diff --git a/tools/buildinfo.sh b/tools/buildinfo.sh
index 9d81dee..e45a441 100755
--- a/tools/buildinfo.sh
+++ b/tools/buildinfo.sh
@@ -8,6 +8,7 @@ echo "ro.build.keys=$BUILD_KEYS"
if [ -n "$DISPLAY_BUILD_NUMBER" ] ; then
echo "ro.build.display_build_number=$DISPLAY_BUILD_NUMBER"
fi
+echo "ro.lockscreen.disable.default=true"
echo "ro.build.version.incremental=$BUILD_NUMBER"
echo "ro.build.version.sdk=$PLATFORM_SDK_VERSION"
echo "ro.build.version.preview_sdk=$PLATFORM_PREVIEW_SDK_VERSION"

注意,刷机验证的时候需要把userdata.img刷进去,不然是不会生效的。

血与泪的教训:-(

-------------------------------------------The End -------------------------------------------