Android 11 低电量自动关机失效

Android 11 低电量自动关机

在这里插入图片描述

概述

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

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

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

分析

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

  • dumpsys battery

    battery
    Current Battery Service state:
      AC powered: false
      USB powered: false
      Wireless powered: false
      Max charging current: 0
      Max charging voltage: 0
      Charge counter: 0
      status: 3
      health: 2
      present: true
      level: 0
      scale: 100
      voltage: 11
      current: 640
      temperature: 308
      technology: 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() {
                    @Override
                    public 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 == 0
            if ((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
    
    

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

关于修改Python中pip默认安装路径的终极方法

别想了&#xff0c;终极方法就是手动复制&#xff0c;不过我可以给你参考一下手动复制的方法 关于手动移动pip安装包的方法 别想了&#xff0c;终极方法就是手动复制&#xff0c;不过我可以给你参考一下手动复制的方法一、首先确认一下pip默认安装路径二、再确认一下需要移动到…

王道408数据结构CH3_栈、队列

概述 3.栈、队列和数组 3.1 栈 3.1.1 基本操作 3.1.2 顺序栈 #define Maxsize 50typedef struct{ElemType data[Maxsize];int top; }SqStack;3.1.3 链式栈 typedef struct LinkNode{ElemType data;struct LinkNode *next; }*LiStack;3.2 队列 3.2.1 基本操作 3.2.2 顺序存储…

java异常处理知识点总结

一.前提知识 首先当运行出错的时候&#xff0c;有两种情况&#xff0c;一种叫做“错误”&#xff0c;另一种叫做“异常”。错误指的是运行过程中遇到了硬件或操作系统出错&#xff0c;这种情况程序员是没办法处理的&#xff0c;因为这是硬件和系统的问题&#xff0c;不能靠代码…

linux中dd命令以及如何测试读写速度

dd命令详解 dd命令是一个在Unix和类Unix系统中非常常用的命令行工具&#xff0c;它主要用于复制文件和转换文件数据。下面我会详细介绍一些dd命令的常见用法和功能&#xff1a; 基本语法 dd命令的基本语法如下&#xff1a; bash Copy Code dd [option]...主要选项和参数 if…

Meta Llama 3 RMSNorm(Root Mean Square Layer Normalization)

Meta Llama 3 RMSNorm&#xff08;Root Mean Square Layer Normalization&#xff09; flyfish 目录 Meta Llama 3 RMSNorm&#xff08;Root Mean Square Layer Normalization&#xff09;先看LayerNorm和BatchNorm举个例子计算 LayerNormRMSNorm 的整个计算过程实际代码实现结…

OpenAI发表研究论文 介绍了一种逆向工程AI模型工作原理的方法

ChatGPT 开发商 OpenAI 构建人工智能的方法本周遭到了前员工的抨击&#xff0c;他们指责该公司利用可能有害的技术冒不必要的风险。今天&#xff0c;OpenAI 发布了一篇新的研究论文&#xff0c;目的显然是为了表明它在通过提高模型的可解释性来应对人工智能风险方面的认真态度。…

跨区域文件管控过程中 如何保障安全和效率?

跨区域文件管控是指在跨越不同地域或区域的情况下对文件进行管理和控制的过程。这种控制可能涉及多个方面&#xff0c;包括安全性、合规性和管理效率等。 为了有效进行跨区域文件管控&#xff0c;组织通常需要采取一系列策略和措施&#xff0c;例如&#xff1a; 1、加密和安全…

西门子学习笔记10 - MCGS和西门子1200进行通讯设置

1、博图软件的设置 1、修改PLC的ip地址为192.168.1.1 2、打开put&#xff0c;get通讯功能 3、设置通讯变量&#xff0c;可以是M区也可以是DB块的数据 2、MCGSE组态环境设置 1、新建项目&#xff0c;在设备窗口界面进入设备窗口 2、添加设备如下 3、双击进入配置界面 4、添加变…

把 FolkMQ 内嵌到 SpringBoot2 项目里(比如 “诺依” 啊)

FolkMQ &#xff08;消息中间件&#xff09;支持内嵌、单机、集群、多重集群等多种部署方式。 内嵌版&#xff0c;就相当于 H2 或 SQLite 数据库一样。给一些小项目&#xff08;或者特别需求&#xff09;带来了方便。大项目&#xff0c;则可以使用独立部署的 “单机版” 或 “…

原花青素优化定向壳聚糖微通道的简单免疫调控结构设计

引用信息 文 章&#xff1a;A facile Immunoregulatory Constructional Design by Proanthocyanidin Optimizing Directional Chitosan Microchannel 期 刊&#xff1a;Small&#xff08;影响因子&#xff1a;13.3&#xff09; 发表时间&#xff1a;29/02/2024 作 …

软件游戏找不到d3dx9_43.dll怎么办,三分钟教你解决此问题

在现代科技发展的时代&#xff0c;电脑已经成为我们生活中不可或缺的一部分。然而&#xff0c;在使用电脑的过程中&#xff0c;我们可能会遇到一些问题&#xff0c;其中之一就是电脑缺失d3dx943.dll文件。这个问题可能会影响到我们的正常使用&#xff0c;因此了解其原因和解决方…

AI Agentic Design Patterns with AutoGen(下):工具使用、代码编写、多代理群聊

文章目录 四、工具使用: 国际象棋游戏4.1 准备工具4.2 创建两个棋手代理和棋盘代理4.3 注册工具到代理4.4 创建对话流程&#xff0c;开始对话4.5 增加趣味性&#xff1a;加入闲聊 五、代码编写&#xff1a;财务分析5.1导入和配置代码执行器5.2 创建 代码执行/编写 代理5.3 定义…

IO进程线程(七)代码替换函数、守护进程

文章目录 一、代码替换函数&#xff08;一&#xff09;system函数&#xff08;二&#xff09;exec函数族 二、守护进程&#xff08;一&#xff09;创建1. 脱离父进程影响2. 脱离原会话组和进程组的影响3.修改进程工作目录4. 修改进程创建文件的掩码5. 关闭从父进程继承的文件描…

YB2416 SOP8封装30V耐压 低成本3A电流同步降压车充芯片

YB2416 SOP-8 SOP8封装30V耐压 输出电流3A 输出电压可调 输出限流调节 外部线补功能车充IC 过流打隔保护 YB2416A50 SOP-8 30V 3A 固定5V 输出 5%高恒流精度 欠压过流过温保护 YB2416是支持高电压输入的同步降压电源管理芯片&#xff0c;在 4~30V 的宽输入电压范围内可实现3A的…

http和https数据传输与协议区分

目录 1. 数据传输安全性2. 端口号3. URL 前缀4. SSL/TLS 证书5. 性能6. SEO 和用户信任7. 应用场景总结 HTTP&#xff08;HyperText Transfer Protocol&#xff09;和 HTTPS&#xff08;HyperText Transfer Protocol Secure&#xff09;是用于在客户端&#xff08;如浏览器&…

Java基础_异常

Java基础_异常 异常体系介绍编译时异常和运行时异常异常的作用异常的处理方式JVM默认的处理方式自己处理&#xff08;捕获异常&#xff09;try...catch灵魂四问Throwable的成员方法 抛出处理 综合练习自定义异常来源Gitee地址 异常体系介绍 异常是什么&#xff1f; 程序中可能出…

输入偏置电流是什么?

输入失调电流与输入补偿电流概念一样&#xff08;input offset current&#xff09;&#xff1a;同相减去反相输入端偏置电流的差值。这是由生产工艺导致同相与反相端的电流大小方向都会有所不同。 第一种情况&#xff1a;同相输入端减去反相输入端 第一种情况&#xff1a;同相…

windows环境安装多版本jdk与环境切换

1&#xff1a;JDK官网下载 2&#xff1a;安装目录 3&#xff1a;在系统环境变量新添加JAVA_HOME_8和JAVA_HOME_21 4&#xff1a;设置默认使用jdk21&#xff0c;如果需要切换&#xff0c;就更改JAVA_HOME的变量值 5&#xff1a;在环境变量path添加&#xff0c;%JAVA_HOME%\bin和…

Vue3学习第二天记录

Vue3学习第二天记录 背景说明截图记录一个简单的JS文件Vue3的watch()函数Vue3的toRef()/toRefs()函数前端数据类型的分类前端写一个对外暴露的函数前端的...语法Vue3中watch()函数的总结Vue3中watchEffect()函数Vue3中watch()函数的坑Vue3中computed()函数 背景 最近在学习尚硅…

Vue2学习(04)

目录 一、组件的三大组成部分 二、组件的样式冲突scoped 三、scoped原理 ​编辑 四、data是一个函数 五、组件通信 六、props详解 七、非父子通信 1.eventbus事件总线(可以一传多)--->作用是在非父子组件之间&#xff0c;进行简易的消息传递&#xff08;复杂场景---&…