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
    
    

相关推荐

  1. Android 10.0 系统framework修改电量关机值为2%

    2024-06-09 01:12:03       37 阅读
  2. Android R framework修改电量关机值为2%

    2024-06-09 01:12:03       15 阅读
  3. Android12 关机流程

    2024-06-09 01:12:03       40 阅读
  4. Python实现电脑自动关机

    2024-06-09 01:12:03       7 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-06-09 01:12:03       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-06-09 01:12:03       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-06-09 01:12:03       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-06-09 01:12:03       20 阅读

热门阅读

  1. UML 统一建模语言简介

    2024-06-09 01:12:03       10 阅读
  2. 面试 Redis 八股文十问十答第四期

    2024-06-09 01:12:03       10 阅读
  3. Lua 时间工具类

    2024-06-09 01:12:03       8 阅读
  4. Ratchet websocket token 验证

    2024-06-09 01:12:03       9 阅读
  5. Composition API函数

    2024-06-09 01:12:03       10 阅读
  6. Python入门Git:探索版本控制的奥秘

    2024-06-09 01:12:03       12 阅读