[Android][Reboot/Shutdown] 重启/关机 分析

server/2024/9/21 17:31:44/

在Android系统中,sys.powerctl 是一个系统属性,用于控制设备的电源状态。通过设置 sys.powerctl 属性,可以触发设备的关机或重启操作。下面详细介绍 sys.powerctl 是如何实现重启(reboot)的。

实现原理

  1. 设置系统属性: 当你通过 SystemProperties.set("sys.powerctl", "reboot") 设置 sys.powerctl 属性时,实际上是在向内核传递一个指令,告诉内核应该执行重启操作。

  2. 内核处理: 内核接收到这个系统属性的更改后,会触发相应的内核函数来处理重启请求。具体来说,内核会调用 reboot 系统调用,从而实现设备的重启。

  3. reboot 系统调用: reboot 是一个 Linux 内核提供的系统调用,用于重新启动或关闭计算机。在 Android 中,reboot 系统调用同样用于控制设备的重启或关机。

代码实现

下面是一个简化的示例,展示了如何在 Android 应用中通过设置 sys.powerctl 属性来实现重启:

import android.os.SystemProperties;public class RebootManager {public static void rebootWithReason(String reason) {// 设置 sys.powerctl 属性为 "reboot" 并附带重启原因SystemProperties.set("sys.powerctl", "reboot," + reason);}public static void performReboot() {String reason = "User requested reboot";rebootWithReason(reason);}
}

内核处理

在内核层面,sys.powerctl 属性的更改会被内核监听并处理。具体的处理逻辑如下:

  1. 系统属性更改: 当 sys.powerctl 属性被更改时,内核中的相应代码会捕获这个更改。

  2. 触发重启: 内核会根据属性的值来决定下一步的动作。如果值为 reboot,则会调用 reboot 系统调用来重启设备。

内核代码示例

在 Linux 内核中,sys.powerctl 属性的处理逻辑通常位于 /drivers/staging/android/power.c 文件中。下面是一个简化的示例,展示了如何在内核中处理 sys.powerctl 属性的更改:

static int android_power_ctl(struct android_power *ap, char *buf, size_t len)
{char *token;char *reason;token = strsep(&buf, ",");if (token && !strcmp(token, "reboot")) {reason = buf; // 获取重启原因// 触发重启do_reboot(reason);} else if (token && !strcmp(token, "shutdown")) {// 触发关机do_shutdown();}return 0;
}static ssize_t android_power_show(struct device *dev, struct device_attribute *attr, char *buf)
{return sprintf(buf, "%d\n", atomic_read(&power_state));
}static ssize_t android_power_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{android_power_ctl(NULL, (char *)buf, count);return count;
}DEVICE_ATTR(power, S_IWUSR | S_IRUGO, android_power_show, android_power_store);

在这段代码中:

  • android_power_ctl 函数负责解析 sys.powerctl 属性的值,并根据值执行相应的操作。

  • android_power_store 函数用于处理写入 sys.powerctl 属性的操作。

注意事项

  1. 权限要求:

    1. 设置 sys.powerctl 属性通常需要 root 权限。因此,只有系统应用或具有 root 权限的应用才能执行这样的操作。

  2. 安全性:

    1. 直接通过系统属性重启设备可能会带来安全风险,因此在生产环境中应谨慎使用。

  3. 兼容性:

    1. 不同的 Android 设备和内核版本可能有不同的实现细节。因此,上述代码示例仅供参考,具体实现可能因设备而异。

总结

通过设置 sys.powerctl 属性为 reboot 可以触发设备的重启操作。这一过程涉及到应用程序设置系统属性、内核捕获并处理属性更改,最终通过 reboot 系统调用实现设备重启。在实际开发中,应注意权限和安全问题,并确保代码的稳定性和兼容性。

对应到目前在研的Android项目的源码中: frameworks/base/services/core/java/com/android/server/power/ShutdownThread.java

    public static void rebootOrShutdown(final Context context, boolean reboot, String reason) {String subsysProp;subsysProp = SystemProperties.get("vendor.peripheral.shutdown_critical_list","ERROR");//If we don't have the shutdown critical subsystem list we can't//really do anything. Proceed with full system shutdown.if (!subsysProp.equals("ERROR")) {Log.i(TAG, "Shutdown critical subsyslist is :"+subsysProp+": ");Log.i(TAG, "Waiting for a maximum of " +(VENDOR_SUBSYS_MAX_WAIT_MS) + "ms");String[] subsysList = subsysProp.split(" ");int wait_count = 0;boolean okToShutdown = true;String subsysState;int subsysListLength = subsysList.length;do {okToShutdown = true;for (int i = 0; i < subsysListLength; i++) {subsysState =SystemProperties.get("vendor.peripheral." +subsysList[i] +".state","ERROR");if(subsysState.equals("ONLINE"))  {//We only want to delay shutdown while//one of the shutdown critical//subsystems still shows as 'ONLINE'.okToShutdown = false;}}if (okToShutdown == false) {SystemClock.sleep(VENDOR_SUBSYS_STATE_CHECK_INTERVAL_MS);wait_count++;}} while (okToShutdown != true &&wait_count < (VENDOR_SUBSYS_MAX_WAIT_MS/VENDOR_SUBSYS_STATE_CHECK_INTERVAL_MS));if (okToShutdown != true) {for (int i = 0; i < subsysList.length; i++) {subsysState =SystemProperties.get("vendor.peripheral." +subsysList[i] +".state","ERROR");if(subsysState.equals("ONLINE"))  {Log.w(TAG, "Subsystem " + subsysList[i]+"did not shut down within timeout");}}} else {Log.i(TAG, "Vendor subsystem(s) shutdown successful");}}if (reboot) {Log.i(TAG, "Rebooting, reason: " + reason);PowerManagerService.lowLevelReboot(reason);Log.e(TAG, "Reboot failed, will attempt shutdown instead");reason = null;} else if (SHUTDOWN_VIBRATE_MS > 0 && context != null) {// vibrate before shutting downVibrator vibrator = new SystemVibrator(context);try {vibrator.vibrate(SHUTDOWN_VIBRATE_MS, VIBRATION_ATTRIBUTES);} catch (Exception e) {// Failure to vibrate shouldn't interrupt shutdown.  Just log it.Log.w(TAG, "Failed to vibrate during shutdown.", e);}// vibrator is asynchronous so we need to wait to avoid shutting down too soon.try {Thread.sleep(SHUTDOWN_VIBRATE_MS);} catch (InterruptedException unused) {}}// Shutdown powerLog.i(TAG, "Performing low-level shutdown...");PowerManagerService.lowLevelShutdown(reason);}

frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java

    /*** Low-level function turn the device off immediately, without trying* to be clean.  Most people should use {@link ShutdownThread} for a clean shutdown.** @param reason code to pass to android_reboot() (e.g. "userrequested"), or null.*/public static void lowLevelShutdown(String reason) {if (reason == null) {reason = "";}SystemProperties.set("sys.powerctl", "shutdown," + reason);}/*** Low-level function to reboot the device. On success, this* function doesn't return. If more than 20 seconds passes from* the time a reboot is requested, this method returns.** @param reason code to pass to the kernel (e.g. "recovery"), or null.*/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 (reason.equals(PowerManager.REBOOT_RECOVERY)|| reason.equals(PowerManager.REBOOT_RECOVERY_UPDATE)) {reason = "recovery";}if (sQuiescent) {// Pass the optional "quiescent" argument to the bootloader to let it know// that it should not turn the screen/lights on.if (!"".equals(reason)) {reason += ",";}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!");}

 


http://www.ppmy.cn/server/118416.html

相关文章

【Linux】uImage头部信息详细解析

头部信息结构体 /** Legacy format image header,* all data in network byte order (aka natural aka bigendian).*/ typedef struct image_header {__be32 ih_magic; /* Image Header Magic Number 0x27051956 */__be32 ih_hcrc; /* Image…

Mysql 存储引擎

MySQL提供了多种存储引擎来管理不同类型的表&#xff0c;每种存储引擎都有其特定的特性和用途。 1.存储引擎&#xff1a; (1). InnoDB 特点&#xff1a;支持事务&#xff08;ACID&#xff09;、行级锁定、外键约束。用途&#xff1a;适用于高可靠性和高并发的事务型应用&#…

C# Tuple、ValueTuple

栏目总目录 Tuple Tuple是C# 4.0引入的一个新特性&#xff0c;主要用于存储一个固定数量的元素序列&#xff0c;且这些元素可以具有不同的类型。Tuple是一种轻量级的数据结构&#xff0c;非常适合用于临时存储数据&#xff0c;而无需定义完整的类或结构体。 优点 简便性&…

Android 后台服务之Persistent 属性

在 Android 开发中,有时我们需要后台服务持续运行,以保持应用的某些功能。例如,音乐播放器需要在后台播放音乐,或者健康应用需要持续跟踪用户的运动数据。后台服务是 Android 中的一种组件,它不与用户界面交互,能够在后台执行长时间运行的任务。由于 Android 系统的资源管…

【Linux】09.Linux 下的调试器——gdb/cgdb

一、gdb/cgdb的认识 我们在VS上调试时都是使用Debug版本的&#xff0c;但是在Linux下gcc/g默认生成的是Relaese版本&#xff0c;我们想要进行调试就要用-g选项生成Debug版本的程序。但是Linux下的gdb是一种命令行调试工具&#xff0c;因此就有了cgdb为我们提供可视化的调试界面…

【算法】差分思想:强大的算法技巧

&#x1f4e2;博客主页&#xff1a;https://blog.csdn.net/2301_779549673 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01; &#x1f4e2;本文由 JohnKi 原创&#xff0c;首发于 CSDN&#x1f649; &#x1f4e2;未来很长&#…

从底层原理上解释 clickhouse 保证完全的幂等性

在分布式系统中&#xff0c;幂等性是指某个操作被多次执行&#xff0c;其效果和结果应该和执行一次相同。ClickHouse作为一个高效的OLAP数据库&#xff0c;在其底层架构和查询引擎中&#xff0c;通过多个机制和策略来确保操作的幂等性。具体来说&#xff0c;ClickHouse的幂等性…

【设计模式-外观】

这里写自定义目录标题 定义UML图角色作用代码使用场景 定义 为子系统中一组相关接口提供一致界面&#xff0c;定义一个高级接口&#xff0c;使得子系统更加容易使用。 UML图 角色作用 外观&#xff08;Facade&#xff09;角色&#xff1a;这是外观模式的核心&#xff0c;它知…