Android学习14--charger(TODO)

发布于:2024-12-06 ⋅ 阅读:(94) ⋅ 点赞:(0)

(TODO)

android.hardware.health-service.qti

最近正好在做关机充电这个,就详细看看吧。还是本着保密的原则,项目里的代码也不能直接用,这里就用的Github的。https://github.com/aosp-mirror

具体位置是:https://github.com/aosp-mirror/platform_system_core/tree/main/healthd

核心代码压缩包只有3M,比起AOSP整包的极度臃肿真是对比强烈。 

首先还是看BP,编译的产物是charger,但是在新版AOSP中服务却不是这个名字。

cc_binary {
    name: "charger",
    defaults: ["charger_defaults"],
    recovery_available: true,
    srcs: [
        "charger.cpp",
        "charger_utils.cpp",
    ],
    shared_libs: [
        "android.hardware.health@2.0",
        "android.hardware.health@2.1",
    ],

    target: {
        recovery: {
            // No UI and libsuspend for recovery charger.
            cflags: [
                "-DCHARGER_FORCE_NO_UI=1",
            ],
            exclude_shared_libs: [
                "libpng",
            ],
            exclude_static_libs: [
                "libhealthd_draw",
                "libhealthd_charger",
                "libhealthd_charger_ui",
                "libminui",
                "libsuspend",
            ],
        }
    }
}

 模块里面有个测试程序,可以看看整个模块的用法。

int main(int /*argc*/, char** /*argv*/) {
    const char* dumpFile = "/data/local/tmp/dump.txt";

    auto config = std::make_unique<healthd_config>();
    InitHealthdConfig(config.get());
    healthd_board_init(config.get());
    sp<IHealth> passthrough = new TestHealth(std::move(config));

    std::thread bgThread([=] {
        android::ChargerHidl charger(passthrough);
        charger.StartLoop();
    });

    // wait for healthd_init to finish
    if (!getUpdateNotifier().waitFor(1000 /* wait ms */, true /* updated */)) {
        LOG_THIS("Time out.");
        exit(1);
    }

    passthrough->debug(createHidlHandle(dumpFile), {} /* options */);

    std::string content = openToString(dumpFile);
    int status = expectContains(content, {
        "status: 4",
        "health: 6",
        "present: 1",
        "level: 47",
        "voltage: 45",
        "temp: 987",
        "current now: 99000",
        "current avg: 98000",
        "charge counter: 600",
        "current now: 99",
        "cycle count: 77",
        "Full charge: 3515547"
    });

    if (status == 0) {
        LOG_THIS("Test success.");
    } else {
        LOG_THIS("Actual dump:\n%s", content.c_str());
    }

    exit(status);  // force bgThread to exit
}

可以看到,就是

android::ChargerHidl charger(passthrough);

charger.StartLoop();

在Android的HIDL(HAL Interface Definition Language)框架中,StartLoop是一个用于启动HIDL服务端线程循环的方法。它允许HIDL服务端在一个独立的线程中运行,以便可以接收和处理来自客户端的请求。具体来说,StartLoop方法会创建一个线程池,并在这个线程池中运行,使得服务端可以异步处理多个客户端请求

整个其实是一个提供Hidl接口的服务。提供的接口如下:

AIDL implementation HIDL implementation
Health::getChargeCounterUah Health::getChargeCounter
Health::getCurrentNowMicroamps Health::getCurrentNow
Health::getCurrentAverageMicroamps Health::getCurrentAverage
Health::getCapacity Health::getCapacity
Health::getChargeStatus Health::getChargeStatus
Health::getEnergyCounterNwh Health::getEnergyCounter
Health::getDiskStats Health::getDiskStats
Health::getStorageInfo Health::getStorageInfo
Health::BinderEvent BinderHealth::BinderEvent
Health::dump Health::debug
Health::ShouldKeepScreenOn Health::shouldKeepScreenOn
Health::UpdateHealthInfo Health::UpdateHealthInfo

类的定义如下:

namespace android {

// An implementation of Charger backed by HIDL implementation. Uses HIDL health
// HAL's HalHealthLoop.
class ChargerHidl : public ::android::ChargerConfigurationInterface,
                    public ::android::hardware::health::V2_1::implementation::HalHealthLoop {
    using HalHealthLoop = ::android::hardware::health::V2_1::implementation::HalHealthLoop;
    using HealthInfo_2_1 = android::hardware::health::V2_1::HealthInfo;

  public:
    explicit ChargerHidl(const sp<android::hardware::health::V2_1::IHealth>& service);
    std::optional<bool> ChargerShouldKeepScreenOn() override;
    bool ChargerIsOnline() override { return HalHealthLoop::charger_online(); }
    void ChargerInitConfig(healthd_config* config) override { return HalHealthLoop::Init(config); }
    int ChargerRegisterEvent(int fd, BoundFunction func, EventWakeup wakeup) override {
        return HalHealthLoop::RegisterEvent(fd, func, wakeup);
    }
    bool ChargerEnableSuspend() override;
    // HealthLoop overrides
    void Heartbeat() override { charger_->OnHeartbeat(); }
    int PrepareToWait() override { return charger_->OnPrepareToWait(); }
    void Init(struct healthd_config* config) override { charger_->OnInit(config); }
    // HalHealthLoop overrides
    void OnHealthInfoChanged(const HealthInfo_2_1& health_info) override;

  private:
    sp<android::hardware::health::V2_1::IHealth> service_;
    std::unique_ptr<Charger> charger_;
};

主要的定义还是在Charger类中。。。

在 AOSP 中,charger 模块主要负责设备在关机状态下的充电管理,以及开机时与电池管理相关的逻辑。以下将详细介绍其代码组成和流程:


1. 代码组成

charger模块的实现包括以下几个部分:

1.1 核心代码路径

AOSP 的 charger 模块主要位于以下路径中:

  • system/core/healthd/
    • 包含 charger 的主要代码,负责实现关机充电逻辑。
  • system/core/init/
    • 涉及关机充电模式的初始化部分。
  • kernel/drivers/power/
    • 电池与充电相关的驱动程序,直接与硬件交互。

1.2 关键文件

以下是 charger 相关的关键文件和其作用:

  • healthd/healthd_charger.cpp
    • 主要实现关机充电模式的功能。
    • 包括电池状态监控、屏幕显示逻辑等。
  • healthd/healthd.cpp
    • 负责电池状态的采集和报告。
  • healthd/BatteryMonitor.cpp
    • 用于从电池驱动程序读取数据,如电量、电压、温度等。
  • init/
    • charger 模式的启动和关闭由 init 进程管理。

1.3 驱动程序代码

与充电相关的硬件驱动代码位于:

  • drivers/power/supply/
    • 包含与电池和充电器的交互逻辑,如 PMIC 驱动。
    • 关键文件示例:
      • battery.c:用于获取电池状态。
      • charger-manager.c:负责充电管理。

2. 模块的工作流程

2.1 关机充电模式的启动流程

当设备关机后插入充电器时,charger 模块负责进入关机充电模式。流程如下:

  1. 检测是否插入充电器

    • healthd 通过 uevent 检测电源插入事件(通过 /sys/class/power_supply/)。
    • 如果检测到充电器连接,设备不会完全关机,而是进入charger模式。
  2. 启动关机充电程序

    • init 进程读取设备参数并启动 charger
      • 判断 /sys/class/power_supply/battery/ 中的状态,如 POWER_SUPPLY_STATUS 是否为 Charging
      • 执行 charger 程序(healthd 的关机模式)。
  3. 进入 charger 主循环

    • healthd_charger.cppmain() 函数负责充电逻辑:
      • 初始化 BatteryMonitor,读取电池状态。
      • 绘制充电动画(或显示简单的充电图标)。
      • 根据电池状态,调整显示的充电状态(如充电百分比或完成)。

2.2 运行时的充电流程

在设备正常运行时,charger 的主要功能是监控电池状态,并通过 BatteryService 报告给系统。

  1. BatteryMonitor 获取电池信息

    • /sys/class/power_supply/battery/ 读取电池的属性,如:
      • 电量:capacity
      • 状态:statusChargingDischarging 等)
      • 温度:temp
      • 电压:voltage_now
    • 使用 BatteryProperties 类存储这些信息。
  2. 更新电池状态

    • BatteryService 通过 binder 通信,将电池状态提供给系统。
    • 系统 UI(如状态栏的电池图标)使用这些数据更新显示。
  3. 充电动画

    • 在关机充电模式下,charger 模块会调用绘图逻辑(如 GraphicBuffer)来显示充电进度动画。

2.3 重要流程细节

启动检测流程

代码文件:healthd_charger.cpp

  1. 初始化:
    • 通过 BatteryMonitor 初始化电池状态监控。
    • 检查 /sys/class/power_supply/ 目录,加载相关文件。
  2. 进入主循环:
    • 每隔一段时间(默认 1 秒),读取电池状态。
    • 如果检测到电池充满或拔掉电源,退出 charger 模式。
电池状态更新

代码文件:BatteryMonitor.cpp

  1. 从硬件读取状态:
    • 通过 sysfsuevent 机制,获取充电器和电池的状态。
    • 调用 healthd_mode_charger_battery_update() 更新状态。
  2. 状态变化通知:
    • 通知 charger 主循环更新显示内容。

3. 显示逻辑

关机充电模式下,charger 模块会显示充电动画,逻辑位于:

  • healthd_draw.cpp:用于绘制充电动画。
  • 主要步骤:
    1. 初始化显示设备(如 /dev/fb0 或 DRM)。
    2. 加载充电动画的图片资源。
    3. 根据电池充电状态更新显示内容。

4. 示例代码分析

以下是一个简化的流程代码片段:

void ChargerModeMainLoop() {
    BatteryMonitor batteryMonitor;

    // 初始化电池监控
    batteryMonitor.Init();

    while (true) {
        // 获取电池状态
        BatteryProperties props = batteryMonitor.GetBatteryProperties();

        // 检测是否充电完成
        if (props.status == BATTERY_STATUS_FULL) {
            ShowChargingComplete();
            break;
        }

        // 更新充电动画
        UpdateChargingAnimation(props.capacity);

        // 延迟一段时间
        sleep(1);
    }
}

5. 常见问题排查

  • 关机充电模式不启动
    • 检查 init.rc 中是否正确配置了 charger
    • 确保 /sys/class/power_supply/ 下的节点存在且返回正确的状态。
  • 充电动画不显示
    • 检查 /dev/fb0 或 DRM 是否正常初始化。
    • 确保 charger 模块加载了正确的图片资源。
  • 电池状态不准确
    • 确认驱动程序是否正确读取硬件信息。
    • 检查 BatteryMonitor 的逻辑是否与硬件匹配。

通过以上分析可以看到,AOSP 中的 charger 模块功能涵盖了关机充电模式管理、运行时电池状态更新和 UI 显示等内容。完整的实现需要驱动层、系统服务层和应用层的协同工作。

代码中对于C++的高级应用还是很熟的。

template <typename T>
class Atomic {
  public:
    Atomic(T&& init) : mValue(std::move(init)) {}
    void set(T&& newVal) {
        {
            std::lock_guard<std::mutex> lock(mMutex);
            mValue = std::move(newVal);
        }
        mChanged.notify_all();
    }
    bool waitFor(long ms, const T& expectVal) {
        std::unique_lock<std::mutex> lock(mMutex);
        return mChanged.wait_for(lock, std::chrono::milliseconds(ms),
                                 [this, &expectVal] { return mValue == expectVal; });
    }
  private:
    std::mutex mMutex;
    std::condition_variable mChanged;
    T mValue;
};

Atomic<bool>& getUpdateNotifier() {
    static Atomic<bool> val(false);
    return val;
}

参考:

https://source.android.com/docs/core/perf/health?hl=zh-cn


网站公告

今日签到

点亮在社区的每一天
去签到