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…

Java 中的 Thread.join() 方法详解

介绍 本文基于 Java 8 进行编写&#xff0c;可能与您使用的 Java 版本有所不同&#xff0c;请注意版本差异。 在多线程编程中&#xff0c;线程的管理和协调是一个重要课题。Java 提供了多种机制来实现线程之间的协调&#xff0c;其中之一就是 Thread.join() 方法。join() 方法…

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

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

计算文件md5

在开发过程中&#xff0c;经常要验证文件是否是同一个文件&#xff0c;或者文件是否被修改&#xff0c;可以通过计算md5值来比对文件是否改变。 使用方法 md5sum 文件名 # 67ed5ca4a19a2d9682b680cb30c9be64 *aaa.mp4## 67ed5ca4a19a2d9682b680cb30c9be64 就是aaa.mp4的MD5值…

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

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

Maven的安装与配置要点和难点常见报错和解决方案

Maven的安装与配置过程可以概括为以下几个步骤: 1. 安装前提 安装JDK:Maven需要Java环境,因此首先需要安装JDK。通常建议使用与Maven兼容的JDK版本,如JDK 1.8或更高版本。 2. 下载Maven 访问Maven官网:从Maven的官方网站下载最新版本的Maven。确保选择与操作系统兼容的…

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

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

JavaScript html css 字符串对象

字符串对象 字符串所有的方法&#xff0c;都不会修改字符串本身&#xff08;字符串是不可变的&#xff09;&#xff0c;操作完成会返回一个新的字符串。 length属性 作用&#xff1a; 获取字符串长度 示例&#xff1a; <span style"background-color:#f8f8f8&qu…

阿里云ECS服务器部署javaweb项目实操

在阿里云ECS实例上部署Java Web项目涉及几个主要步骤&#xff1a;创建和配置ECS实例、安装必要的软件&#xff08;JDK、Web服务器、数据库等&#xff09;、部署Java Web应用程序以及配置防火墙和安全组。以下是详细的步骤&#xff1a; 步骤1&#xff1a;创建ECS实例 登录阿里云…

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

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

java的序列化与反序列化

一、定义 Java序列化和反序列化&#xff1a;序列化就是指把Java对象转换为字节序列的过程。&#xff08;例如将一个类转化为json类型&#xff09;反序列化就是指把字节序列恢复为Java对象的过程。 在Java实际运用中&#xff0c;,许多方面应用序列化反序列化——持久化、通信、…

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

借助图扑智慧楼宇管控可视化技术&#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;让我们看到了成年人…

深入了解Linux中的db_dump185命令

深入了解Linux中的db_dump185命令 在Linux系统中&#xff0c;db_dump185可能不是一个广为人知的命令&#xff0c;但它对于某些特定的数据库或文件系统任务来说却是一个非常有价值的工具。特别是当你与旧版的Berkeley DB数据库或类似的存储机制打交道时&#xff0c;db_dump185可…

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…