android手机进入reboot,android 静默重启 QUIESCENT REBOOT

背景

项目中需要处理Android的原生开机动画,一定条件下还需要做到静默重启(android系统启动进入到桌面前,屏幕保持完全没有亮度的状态)。因为项目使用的rom是MTK平台支持,一开始并不知道Android 的QUIESCENT_REBOOT模式,所以自己想办法实现了此功能,详细见博客:基于Q的Android开机动画。因为后续Linux启用了SELinux增强了权限限制,原有的方案因为权限限制了文件的执行和读写,需要进行比较大的变动。后来,学习了下Android 的QUIESCENT_REBOOT模式,并把它用到了项目中解决了问题。这里介绍下QUIESCENT_REBOOT模式原理。

Android Quiescent的原理和流程

一、powerManager.reboot(PowerManager.REBOOT_QUIESCENT) 来静默重启(本地测试可以通过命令行触发svc power reboot quiescent)

1、代码:frameworks/base/core/java/android/os/PowerManager.java

public void reboot(String reason) {

try {

// mService是PowerManagerService

mService.reboot(false, reason, true);

} catch (RemoteException e) {

throw e.rethrowFromSystemServer();

}

}1

2

3

4

5

6

7

8

2、代码frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java

// True if the lights should stay off until an explicit user action.

// 这个标记记录是否静默重启

private static boolean sQuiescent;

@Override // Binder call

public void reboot(boolean confirm, String reason, boolean wait) {

mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);

......

final long ident = Binder.clearCallingIdentity();

try {

shutdownOrRebootInternal(HALT_MODE_REBOOT, confirm, reason, wait);

} finally {

Binder.restoreCallingIdentity(ident);

}

}

private void shutdownOrRebootInternal(final @HaltMode int haltMode, final boolean confirm,

final String reason, boolean wait) {

// lowLevelReboot会去解析reason并存储到SystemProperties

if (mHandler == null || !mSystemReady) {

if (RescueParty.isAttemptingFactoryReset()) {

// If we're stuck in a really low-level reboot loop, and a

// rescue party is trying to prompt the user for a factory data

// reset, we must GET TO DA CHOPPA!

PowerManagerService.lowLevelReboot(reason);

} else {

throw new IllegalStateException("Too early to call shutdown() or reboot()");

}

}

// 调用ShutdownThread重启

Runnable runnable = new Runnable() {

@Override

public void run() {

synchronized (this) {

if (haltMode == HALT_MODE_REBOOT_SAFE_MODE) {

ShutdownThread.rebootSafeMode(getUiContext(), confirm);

} else if (haltMode == HALT_MODE_REBOOT) {

ShutdownThread.reboot(getUiContext(), reason, confirm);

} else {

ShutdownThread.shutdown(getUiContext(), reason, confirm);

}

}

}

};

......

}

public static void lowLevelReboot(String reason) {

if (reason == null) {

reason = "";

}

// If the reason is "quiescent", it means that the boot process should proceed

// without turning on the screen/lights.

// The "quiescent" property is sticky, meaning that any number

// of subsequent reboots should honor the property until it is reset.

if (reason.equals(PowerManager.REBOOT_QUIESCENT)) {

sQuiescent = true;

reason = "";

} else if (reason.endsWith("," + PowerManager.REBOOT_QUIESCENT)) {

sQuiescent = true;

reason = reason.substring(0,

reason.length() - PowerManager.REBOOT_QUIESCENT.length() - 1);

}

if (sQuiescent) {

// Pass the optional "quiescent" argument to the bootloader to let it know

// that it should not turn the screen/lights on.

reason = reason + ",quiescent";

}

// 这里会存储到系统参数

SystemProperties.set("sys.powerctl", "reboot," + reason);

try {

Thread.sleep(20 * 1000L);

} catch (InterruptedException e) {

Thread.currentThread().interrupt();

}

Slog.wtf(TAG, "Unexpected return from lowLevelReboot!");

}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

76

77

78

79

80

81

sQuiescent记录是否静默重启,lowLevelReboot会去解析reason并设置sQuiescent为true,同时把reason存储到SystemProperties,最后调用ShutdownThread带着reason传参。

3、代码frameworks/base/services/core/java/com/android/server/power/ShutdownThread.java

这个类中主要是根据一些条件做了一些单独处理,例如recovery等可能还会展示弹窗,这里有兴趣的可以根据代码路径自行观看,静默重启这个类中没有用到。

4、前边说到了SystemProperties.set(“sys.powerctl”, “reboot,” + reason),这里很重要。静默重启会把这个值存储到内核特定的启动参数,这个启动参数在下次重启时会被系统拿到。这里内部就涉及SystemProperties原理和源代码了,不特意分析,知道大概用做啥。

5、同时,内核还会解析reason,存储另一个SystemProperties;大概的流程是lk 中读到 rtc 的 Quiescent 标志位,则不显示开机logo,并且在 cmdline 中添加 androidboot.quiescent=1;lk -> kernel -> init,init 会解析 cmdline,并把其中的 androidboot.quiescent=1 解析出来,并设置成 ro.boot.quiescent=1,这样后续 Android 所有地方都能知道此次是 quiescent 开机。

6、bootanimation (frameworks/base/cmds/bootanimation) 中,读到 ro.boot.quiescent=1,则不显示开机动画

代码:frameworks/base/cmds/bootanimation/BootAnimationUtil.cpp

bool bootAnimationDisabled() {

45 char value[PROPERTY_VALUE_MAX];

46 property_get("debug.sf.nobootanimation", value, "0");

47 if (atoi(value) > 0) {

48 return true;

49 }

50

51 property_get("ro.boot.quiescent", value, "0");

52 return atoi(value) > 0;

53}1

2

3

4

5

6

7

8

9

10

代码:frameworks/base/cmds/bootanimation/bootanimation_main.cpp

36int main()

37{

38 setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_DISPLAY);

39

// 如果noBootAnimation,不展示开机动画

40 bool noBootAnimation = bootAnimationDisabled();

41 ALOGI_IF(noBootAnimation, "boot animation disabled");

42 if (!noBootAnimation) {

43

44 sp proc(ProcessState::self());

45 ProcessState::self()->startThreadPool();

46

47 // create the boot animation object (may take up to 200ms for 2MB zip)

48 sp boot = new BootAnimation(audioplay::createAnimationCallbacks());

49

50 waitForSurfaceFlinger();

51

52 boot->run("BootAnimation", PRIORITY_DISPLAY);

53

54 ALOGV("Boot animation set up. Joining pool.");

55

56 IPCThreadState::self()->joinThreadPool();

57 }

58 return 0;

59}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

7、这里还会涉及开机log的隐藏,在kernal层根据存储在内核的启动参数作为判断,隐藏logo或者亮度。这里大概属于猜测,具体有兴趣的可以自己深入研究。

解决项目中问题

项目中除了要隐藏开机动画,还需要把亮度调为最低。

1、需要把开机默认设置调度的代码给屏蔽掉

代码:frameworks/base/services/core/java/com/android/server/display/DisplayManagerService.java

@VisibleForTesting

DisplayManagerService(Context context, Injector injector) {

super(context);

......

PowerManager pm = mContext.getSystemService(PowerManager.class);

// 注释掉的为源代码,这里会取一个默认160的亮度并设置

//mGlobalDisplayBrightness = pm.getDefaultScreenBrightnessSetting();

// 这里根据静默的参数,增加判断

if (SystemProperties.getInt("ro.boot.quiescent", 0) == 0) {

mGlobalDisplayBrightness = pm.getDefaultScreenBrightnessSetting();

}

......

}1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

2、因为除了这个地方会设置默认亮度,系统起来后还会被android层重新设置亮度,就恢复到正常亮度了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值