Android 11 低电量自动关机失效

Android 11 低电量自动关机

在这里插入图片描述

概述

安卓系统设计了低电关机功能,旨在当手机电池电量过低时自动关机,以保护手机硬件和数据安全。该功能由以下几个部分组成:

  • 电池电量监测: 安卓系统通过 BatteryService 组件持续监测电池电量。BatteryService会从底层获取电池电量信息,并根据预设的阈值判断电池电量是否过低。
  • 低电量警告: 当电池电量低于预设的警告阈值时,BatteryService会触发低电量警告。低电量警告通常会以弹窗声音提示的形式通知用户。
  • 低电关机: 当电池电量低于预设的关机阈值时,BatteryService会触发低电关机。低电关机前,系统会提示用户保存数据关闭正在运行的应用

基于RK3568 Android 11 系统开发过程中, 移植了电源和电池相关的驱动后, 测试发现低电自动关机的功能失效了.

分析

首先, 从dumpsys 中看下当前电池的一些状态信息(PS: 新版本的内容呈现有所不同):

  • dumpsys battery

    battery
    Current Battery Service state:AC powered: falseUSB powered: falseWireless powered: falseMax charging current: 0Max charging voltage: 0Charge counter: 0status: 3health: 2present: truelevel: 0scale: 100voltage: 11current: 640temperature: 308technology: Li-ion
    
  • 处理低电关机的关键代码: frameworks/base/services/core/java/com/android/server/BatteryService.java

        private void processValuesLocked(boolean force) {boolean logOutlier = false;long dischargeDuration = 0;mBatteryLevelCritical =mHealthInfo.batteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN&& mHealthInfo.batteryLevel <= mCriticalBatteryLevel;if (mHealthInfo.chargerAcOnline) {mPlugType = BatteryManager.BATTERY_PLUGGED_AC;} else if (mHealthInfo.chargerUsbOnline) {mPlugType = BatteryManager.BATTERY_PLUGGED_USB;} else if (mHealthInfo.chargerWirelessOnline) {mPlugType = BatteryManager.BATTERY_PLUGGED_WIRELESS;} else {mPlugType = BATTERY_PLUGGED_NONE;}if (DEBUG) {Slog.d(TAG, "Processing new values: "+ "info=" + mHealthInfo+ ", mBatteryLevelCritical=" + mBatteryLevelCritical+ ", mPlugType=" + mPlugType);}// Let the battery stats keep track of the current level.try {mBatteryStats.setBatteryState(mHealthInfo.batteryStatus, mHealthInfo.batteryHealth,mPlugType, mHealthInfo.batteryLevel, mHealthInfo.batteryTemperature,mHealthInfo.batteryVoltage, mHealthInfo.batteryChargeCounter,mHealthInfo.batteryFullCharge,mHealthInfo2p1.batteryChargeTimeToFullNowSeconds);} catch (RemoteException e) {// Should never happen.}shutdownIfNoPowerLocked();shutdownIfOverTempLocked();//....................}    private void shutdownIfNoPowerLocked() {// shut down gracefully if our battery is critically low and we are not powered.// wait until the system has booted before attempting to display the shutdown dialog.if (shouldShutdownLocked()) {mHandler.post(new Runnable() {@Overridepublic void run() {if (mActivityManagerInternal.isSystemReady()) {Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);intent.putExtra(Intent.EXTRA_REASON,PowerManager.SHUTDOWN_LOW_BATTERY);intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);mContext.startActivityAsUser(intent, UserHandle.CURRENT);}}});}}private boolean shouldShutdownLocked() {if (mHealthInfo2p1.batteryCapacityLevel != BatteryCapacityLevel.UNSUPPORTED) {if (mHealthInfo2p1.batteryCapacityLevel == BatteryCapacityLevel.CRITICAL) {Slog.w(TAG, "batteryCapacityLevel is CRITICAL need Shutdown");return true;} else if (mHealthInfo2p1.batteryCapacityLevel != BatteryCapacityLevel.LOW) {return false;}}if (mHealthInfo.batteryLevel > 0) {return false;}// Battery-less devices should not shutdown.if (!mHealthInfo.batteryPresent) {return false;}// If battery state is not CHARGING, shutdown.// - If battery present and state == unknown, this is an unexpected error state.// - If level <= 0 and state == full, this is also an unexpected state// - All other states (NOT_CHARGING, DISCHARGING) means it is not charging.boolean isNotCharging = mHealthInfo.batteryStatus != BatteryManager.BATTERY_STATUS_CHARGING;if (isNotCharging) {return true;}boolean isExcessDischarge = mHealthInfo.batteryCurrent < 0;if (isExcessDischarge) {Slog.w(TAG, "batteryCurrent=" + mHealthInfo.batteryCurrent + ", isExcessDischarge need Shutdown");}return isExcessDischarge;}
    

    shouldShutdownLocked 函数的值决定是否调用关机的流程.

    关机的几个判断条件:

    1. mHealthInfo2p1.batteryCapacityLevel == BatteryCapacityLevel.CRITICAL 判断是否处于临界状态, 关不了机的原因
    2. mHealthInfo.batteryStatus != BatteryManager.BATTERY_STATUS_CHARGING; 电量为0且当前没有接入充电
    3. mHealthInfo.batteryCurrent < 0; 充电接入, 放电大于充电电流.

    小插曲-找不到的源码

    在BatteryService.java中, import了一堆health.Vx_x 的类, 搜遍了framework, device, packages没找到相关的源码.

    import android.hardware.health.V1_0.HealthInfo;
    import android.hardware.health.V2_0.IHealth;
    import android.hardware.health.V2_0.Result;
    import android.hardware.health.V2_1.BatteryCapacityLevel;
    import android.hardware.health.V2_1.Constants;
    import android.hardware.health.V2_1.IHealthInfoCallback;
    

    最终在out目录下找到:

  • ll ./out/soong/.intermediates/hardware/interfaces/health

    total 28
    drwxrwxr-x  7 anson anson 4096 123  2022 ./
    drwxrwxr-x 50 anson anson 4096 123  2022 ../
    drwxrwxr-x 11 anson anson 4096 123  2022 1.0/
    drwxrwxr-x 10 anson anson 4096 123  2022 2.0/
    drwxrwxr-x  9 anson anson 4096 123  2022 2.1/
    drwxrwxr-x  3 anson anson 4096 123  2022 storage/
    drwxrwxr-x  4 anson anson 4096 123  2022 utils/
    
  • ./out/soong/.intermediates/hardware/interfaces/health/2.1/android.hardware.health-V2.1-java_gen_java/gen/srcs/android/hardware/health/V2_1/BatteryCapacityLevel.java

    package android.hardware.health.V2_1;public final class BatteryCapacityLevel {/*** Battery capacity level is unsupported.* Battery capacity level must be set to this value if and only if the* implementation is unsupported.*/public static final int UNSUPPORTED = -1 /* -1 */;/*** Battery capacity level is unknown.* Battery capacity level must be set to this value if and only if battery* is not present or the battery capacity level is unknown/uninitialized.*/public static final int UNKNOWN = 0 /* ::android::hardware::health::V2_1::BatteryCapacityLevel.UNSUPPORTED implicitly + 1 */;/*** Battery is at critical level. The Android framework must schedule a* shutdown when it sees this value from the HAL.*/public static final int CRITICAL = 1 /* ::android::hardware::health::V2_1::BatteryCapacityLevel.UNKNOWN implicitly + 1 */;/*** Battery is low. The Android framework may limit the performance of* the device when it sees this value from the HAL.*/public static final int LOW = 2 /* ::android::hardware::health::V2_1::BatteryCapacityLevel.CRITICAL implicitly + 1 */;/*** Battery level is normal.*/public static final int NORMAL = 3 /* ::android::hardware::health::V2_1::BatteryCapacityLevel.LOW implicitly + 1 */;/*** Battery level is high.*/public static final int HIGH = 4 /* ::android::hardware::health::V2_1::BatteryCapacityLevel.NORMAL implicitly + 1 */;/*** Battery is full. It must be set to FULL if and only if battery level is* 100.*/public static final int FULL = 5 /* ::android::hardware::health::V2_1::BatteryCapacityLevel.HIGH implicitly + 1 */;public static final String toString(int o) {if (o == UNSUPPORTED) {return "UNSUPPORTED";}if (o == UNKNOWN) {return "UNKNOWN";}if (o == CRITICAL) {return "CRITICAL";}if (o == LOW) {return "LOW";}if (o == NORMAL) {return "NORMAL";}if (o == HIGH) {return "HIGH";}if (o == FULL) {return "FULL";}return "0x" + Integer.toHexString(o);}public static final String dumpBitfield(int o) {java.util.ArrayList<String> list = new java.util.ArrayList<>();int flipped = 0;if ((o & UNSUPPORTED) == UNSUPPORTED) {list.add("UNSUPPORTED");flipped |= UNSUPPORTED;}list.add("UNKNOWN"); // UNKNOWN == 0if ((o & CRITICAL) == CRITICAL) {list.add("CRITICAL");flipped |= CRITICAL;}if ((o & LOW) == LOW) {list.add("LOW");flipped |= LOW;}if ((o & NORMAL) == NORMAL) {list.add("NORMAL");flipped |= NORMAL;}if ((o & HIGH) == HIGH) {list.add("HIGH");flipped |= HIGH;}if ((o & FULL) == FULL) {list.add("FULL");flipped |= FULL;}if (o != flipped) {list.add("0x" + Integer.toHexString(o & (~flipped)));}return String.join(" | ", list);}};
  • ./out/soong/.intermediates/hardware/interfaces/health/1.0/android.hardware.health-V1.0-java-constants_gen_java/gen/android/hardware/health/V1_0/Constants.java

    
    // This file is autogenerated by hidl-gen. Do not edit manually.
    // Source: android.hardware.health@1.0
    // Location: hardware/interfaces/health/1.0/package android.hardware.health.V1_0;public class Constants {// Values declared in BatteryStatus follow.public static final int BATTERY_STATUS_UNKNOWN = 1;public static final int BATTERY_STATUS_CHARGING = 2;public static final int BATTERY_STATUS_DISCHARGING = 3;public static final int BATTERY_STATUS_NOT_CHARGING = 4;public static final int BATTERY_STATUS_FULL = 5;// Values declared in BatteryHealth follow.public static final int BATTERY_HEALTH_UNKNOWN = 1;public static final int BATTERY_HEALTH_GOOD = 2;public static final int BATTERY_HEALTH_OVERHEAT = 3;public static final int BATTERY_HEALTH_DEAD = 4;public static final int BATTERY_HEALTH_OVER_VOLTAGE = 5;public static final int BATTERY_HEALTH_UNSPECIFIED_FAILURE = 6;public static final int BATTERY_HEALTH_COLD = 7;}

    对应的源码目录:

    tree hardware/interfaces/health/
    hardware/interfaces/health/
    ├── 1.0
    │   ├── Android.bp
    │   ├── default
    │   │   ├── Android.bp
    │   │   ├── android.hardware.health@1.0-service.rc
    │   │   ├── convert.cpp
    │   │   ├── Health.cpp
    │   │   ├── Health.h
    │   │   ├── HealthService.cpp
    │   │   ├── include
    │   │   │   └── hal_conversion.h
    │   │   ├── libhealthd
    │   │   │   ├── Android.bp
    │   │   │   └── healthd_board_default.cpp
    │   │   └── README.md
    │   ├── IHealth.hal
    │   ├── types.hal
    │   └── vts
    │       └── functional
    │           ├── Android.bp
    │           └── VtsHalHealthV1_0TargetTest.cpp
    ├── 2.0
    │   ├── Android.bp
    │   ├── default
    │   │   ├── Android.bp
    │   │   ├── Health.cpp
    │   │   ├── healthd_common_adapter.cpp
    │   │   ├── HealthImplDefault.cpp
    │   │   └── include
    │   │       └── health2
    │   │           └── Health.h
    │   ├── IHealth.hal
    │   ├── IHealthInfoCallback.hal
    │   ├── README -> README.md
    │   ├── README.md
    │   ├── types.hal
    │   ├── utils
    │   │   ├── libhealthhalutils
    │   │   │   ├── Android.bp
    │   │   │   ├── HealthHalUtils.cpp
    │   │   │   └── include
    │   │   │       └── healthhalutils
    │   │   │           └── HealthHalUtils.h
    │   │   ├── libhealthservice
    │   │   │   ├── Android.bp
    │   │   │   ├── HealthServiceCommon.cpp
    │   │   │   └── include
    │   │   │       └── health2
    │   │   │           └── service.h
    │   │   ├── libhealthstoragedefault
    │   │   │   ├── Android.bp
    │   │   │   ├── include
    │   │   │   │   └── StorageHealthDefault.h
    │   │   │   └── StorageHealthDefault.cpp
    │   │   └── README.md
    │   └── vts
    │       ├── functional
    │       │   ├── Android.bp
    │       │   └── VtsHalHealthV2_0TargetTest.cpp
    │       └── OWNERS
    ├── 2.1
    │   ├── Android.bp
    │   ├── default
    │   │   ├── Android.bp
    │   │   ├── android.hardware.health@2.1-service.rc
    │   │   ├── android.hardware.health@2.1.xml
    │   │   ├── impl.cpp
    │   │   └── service.cpp
    │   ├── IHealth.hal
    │   ├── IHealthInfoCallback.hal
    │   ├── README.md
    │   ├── types.hal
    │   └── vts
    │       ├── functional
    │       │   ├── Android.bp
    │       │   └── VtsHalHealthV2_1TargetTest.cpp
    │       └── OWNERS
    ├── storage
    │   └── 1.0
    │       ├── Android.bp
    │       ├── default
    │       │   ├── Android.bp
    │       │   ├── android.hardware.health.storage@1.0-service.rc
    │       │   ├── manifest_android.hardware.health.storage@1.0.xml
    │       │   ├── service.cpp
    │       │   ├── Storage.cpp
    │       │   └── Storage.h
    │       ├── IGarbageCollectCallback.hal
    │       ├── IStorage.hal
    │       ├── types.hal
    │       └── vts
    │           └── functional
    │               ├── Android.bp
    │               ├── VtsHalHealthStorageV1_0TargetTest.config
    │               └── VtsHalHealthStorageV1_0TargetTest.cpp
    └── utils├── libhealth2impl│   ├── Android.bp│   ├── BinderHealth.cpp│   ├── HalHealthLoop.cpp│   ├── Health.cpp│   └── include│       └── health2impl│           ├── BinderHealth.h│           ├── Callback.h│           ├── HalHealthLoop.h│           └── Health.h└── libhealthloop├── Android.bp├── HealthLoop.cpp├── include│   └── health│       ├── HealthLoop.h│       └── utils.h└── utils.cpp

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/24926.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

小主机折腾记24

好久不更新&#xff0c;最近折腾的事如下 1.10块钱自提买了个半高机箱&#xff0c;15086140&#xff0c;把之前拆机的H61m-A/M32AA/DP_MB与200w航嘉电源装了进去&#xff0c;额外买了半高pcie转接了个m2位&#xff0c;江波龙64g安装了win10专业版&#xff0c;最后卖了176块钱&a…

实战分析:记录一下线上OOM排查(原创)

记录背景 公司仓库系统经常反馈出现系统使用不了503的情况&#xff0c;自动挂掉。 启动脚本添加命令 以为是程序发生OOM导致内存溢出&#xff0c;添加命令&#xff0c;发生内存溢出输出文件 -XX:HeapDumpOnOutOfMemoryError -XX:ErrorFile./errorfile.log -XX:HeapDumpPath.…

Windows无法安装到这个硬盘空间。选定的分区上启用了BitLocker驱动器加密。请在控制面板中暂停(也称为禁用)BitLocker,然后重新开始安装。

我们安装操作系统的时候&#xff0c;到了选择安装分区的地方&#xff0c;我们选中的分区提示“无法在驱动器的分区上安装Windows”&#xff0c;然后我们点击显示详细信息&#xff0c;提示如图下所示 分析原因&#xff0c;可能是之前的分区未进行格式化。但是这个时候我们无法格…

【Python预处理系列】深入理解过采样技术及其Python实现

目录 一、过采样简介 二、过采样的实现方法 三、过采样和欠采样是数据增强吗 四、Python实现SMOTE过采样 &#xff08;一) 生成不平衡数据集 &#xff08;二&#xff09; 将数据集转换为DataFrame&#xff0c;便于展示 &#xff08;三) 应用SMOTE算法进行过采样 &…

【Centos7】CentOS 7下的PyTorch安装策略:高效实践指南

【Centos7】CentOS 7下的PyTorch安装策略&#xff1a;高效实践指南 大家好 我是寸铁&#x1f44a; 总结了一篇【Centos7】CentOS 7下的PyTorch安装策略&#xff1a;高效实践指南✨ 喜欢的小伙伴可以点点关注 &#x1f49d; 前言 由于需要跑深度学习&#xff0c;要用到pytorch&a…

重塑楼宇管理:智慧管控可视化开启高效新篇章

借助图扑智慧楼宇管控可视化技术&#xff0c;实现实时监控与智能化管理&#xff0c;快速响应潜在问题&#xff0c;确保楼宇安全、节能和高效运行。

Git之解决重复输入用户名和密码(三十九)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

快速入门Linux及使用VSCode远程连接Linux服务器

在当前的技术环境中&#xff0c;Linux操作系统因其强大的功能和灵活性而广受欢迎。无论你是开发人员、系统管理员还是技术爱好者&#xff0c;学习Linux都是提升技术技能的重要一步。本文将介绍如何快速入门Linux&#xff0c;并使用Visual Studio Code&#xff08;VSCode&#x…

时光正好保剑锋的抱治百病与成年人的世界

《时光正好》&#xff1a;保剑锋的“抱治百病”与成年人的世界在繁忙的都市里&#xff0c;每个角落上演着各自的人生戏码。而在这些戏码中&#xff0c;由保剑锋主演的《时光正好》无疑成为了近期引人注目的焦点。这部电视剧以其真实而深刻的剧情&#xff0c;让我们看到了成年人…

SpringBoot+Vue实现前后端分离基本的环境搭建

目录 一、Vue项目的搭建 &#xff08;1&#xff09;基于vite创建vue项目 &#xff08;2&#xff09;引入elementplus &#xff08;3&#xff09;启动后端服务&#xff0c;并测试 二、SpringBoot项目的搭建 &#xff08;1&#xff09;通过idea创建SpringBoot项目 &#x…

有效的括号(oj题)

一、题目链接 https://leetcode.cn/problems/valid-parentheses/submissions/538110206 二、题目思路 利用栈的性质&#xff0c;后进先出 1.依次读取字符串&#xff0c;判断是否为左括号&#xff0c;如果是&#xff0c;就将其入栈。 2.如果读取的不是左括号&#xff0c;就说…

【网络教程】Iptables官方教程-学习笔记7-简单理解IPTABLES规则的作用流程

前面学习了IPTABLES的所有功能介绍后&#xff0c;一个Linux设备里的IPTABLES规则集是如何运行的&#xff0c;这里简单做个介绍。 在Linux设备里输入"iptables -nvl",得到该设备的所有防火墙规则&#xff0c;得到的结果中可以看到这个设备防火墙里所有的链以及链里的…

Git从入门到放弃

由于我的Git学的不太好&#xff0c;所以为了能够将以后我的学习笔记能够整理的更好&#xff0c;我先要系统的学习一下git&#xff0c;文章由此产生。 文章笔记源自尚硅谷Git入门到精通全套教程视频内容 1 进入官网 学习新技术的第一步需要熟悉官网&#xff0c;Git也不例外。ht…

【Python报错】已解决AttributeError: ‘Series’ object has no attribute ‘columns’

成功解决“AttributeError: ‘Series’ object has no attribute ‘columns’”错误的全面指南 一、引言 在Python的数据处理和分析中&#xff0c;Pandas库是一个不可或缺的工具。然而&#xff0c;在使用Pandas时&#xff0c;可能会遇到各种错误&#xff0c;其中之一就是“Att…

HTML静态网页成品作业(HTML+CSS)—— 24节气立夏介绍网页(1个页面)

&#x1f389;不定期分享源码&#xff0c;关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 &#x1f3f7;️本套采用HTMLCSS&#xff0c;未使用Javacsript代码&#xff0c;共有1个页面。 二、作品演示 三、代…

使用Python创建Word文档

使用Python创建Word文档 安装python-docx库创建Word文档代码效果 在这篇文章中&#xff0c;我们将介绍如何使用 Python创建一个Word文档。首先&#xff0c;我们需要安装python-docx库&#xff0c;然后通过一段简单的代码示例展示如何创建和编辑Word文档。 安装python-docx库 …

RPA影刀 | 变量的使用

1.什么是变量 2.变量的作用 作用1&#xff1a;方便后续流程调用 这里在后续流程“点击元素”中&#xff0c;就可以选中这个变量 作用2&#xff1a;区分相同属性的变量 如果要打开两个网页&#xff0c;总不能都叫web_page吧。 所以这里一个叫百度web_page&#xff0c;一个叫…

C++期末复习总结(2)

目录 1.运算符重载 2.四种运算符重载 &#xff08;1&#xff09;关系运算符的重载 &#xff08;2&#xff09; 左移运算符的重载 &#xff08;3&#xff09;下标运算符的重载 &#xff08;4&#xff09;赋值运算符的重载 3.继承的方式 4.继承的对象模型 5.基类的构造 6…

易飞销货单出货时审核库存检查

公司接到一客户因品种多而数量少&#xff0c;单一出货计划行比较多&#xff0c;而只上了生产ERP易飞&#xff0c;审核时经常会出现倒催货&#xff0c;提前做销售单&#xff0c;行数有时超30行以上&#xff0c;审核跳窗报错时也不方便查找&#xff0c;特写一外挂程序&#xff0c…

How to: Build a Custom End-User Skin Selector

This section explains how to populate a ComboBoxEdit control with DevExpress skin items. 本节介绍如何使用DevExpress皮肤项填充ComboBoxEdit控件。 To populate a combo box editor, iterate through the SkinManager.Skins collection, which returns all currently a…