展锐USB充电图标更新流程

news2024/11/16 9:56:48

介绍

power_supply 目录下online节点是用于判断是否插入battery、ac(外部电源) 和USB 的节点,目录在sys/class/power_supply/battery(ac、usb)/online,主要用于在StatusBar 上显示充电的闪电图标。 

SystemUI层介绍

流程介绍

在SystemUI 中控制充电图标的位置在BatteryMeterDrawable.java 类中实现的

SystemUI/src/com/sprd/battery/BatteryMeterDrawable.java

@Override
public void draw(Canvas c) {
    ...
    // 这里表示有任何一个适配器(AC/USB)插入(power_supply目录下的online 节点值为1),并且状态是正在充电中(power_supply目录下status 为Charging 状态, status 的值为BATTERY_STATUS_CHARGING)
    if (plugged && level != 100
                && (mTracker.status == BatteryManager.BATTERY_STATUS_CHARGING || mCharging)) {
    ...
}

这个类相当于一个自定义的充电图标控件,在第一次加载或者调用了invalidateSelf() 方法后会调用draw() 方法重新绘制图标。

整个SystemUI 更新充电图标的流程为:

  1. BatteryServer 发送ACTION_BATTERY_CHANGED 广播向广播接收器提示Battery 发生了变化
  2. BatteryControllerImpl.java接收到此广播,调用fireBatteryLevelChanged() 方法向注册了BatteryStateChangeCallback 类回调 onBatteryLevelChanged() 方法
  3. BatteryMeterDrawable.java 调用onBatteryLevelChanged() 方法后更新充电状态,并且调用postInvalidate() 方法重绘图标

代码流程

1. BatteryService 服务发送电池更新的广播

frameworks/base/services/core/java/com/android/server/BatteryService.java

private final class HealthHalCallback extends IHealthInfoCallback.Stub
        implements HealthServiceWrapper.Callback {
    @Override public void healthInfoChanged(android.hardware.health.V2_0.HealthInfo props) {
        BatteryService.this.update(props);
    }
    ...
}

// 由Health::notifyListeners 调用过来的
private void update(android.hardware.health.V2_0.HealthInfo info) {
    synchronized (mLock) {
        mRealBatteryLevel = info.legacy.batteryLevel;
        if (!mUpdatesStopped) {
            mHealthInfo = info.legacy;
            processValuesLocked(false);
            mLock.notifyAll();
        } else {
            copy(mLastHealthInfo, info.legacy);
        }
    }
}

private void processValuesLocked(boolean force) {
    ...
    sendBatteryChangedIntentLocked(); // 发送Intent.ACTION_BATTERY_CHANGED 广播
    ...
}


private void sendBatteryChangedIntentLocked() {
    //  Pack up the values and broadcast them to everyone
    final Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED);
    intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
            | Intent.FLAG_RECEIVER_REPLACE_PENDING);
    ...
    mHandler.post(() -> ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_ALL));
}

2. BatteryControllerImpl 调用流程

BatteryControllerImpl类继承了BroadcastReceiver 类,并且监听了ACTION_BATTERY_CHANGED 广播,当收到ACTION_BATTERY_CHANGED广播后调用fireBatteryLevelChanged() 方法调用注册的回调方法

frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java

@Override
public void onReceive(final Context context, Intent intent) {
    ...
    final String action = intent.getAction();
    if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
        ...
        fireBatteryLevelChanged();
        ...
    }
    ...                                            
}

protected void fireBatteryLevelChanged() {
    synchronized (mChangeCallbacks) {
        final int N = mChangeCallbacks.size();
        for (int i = 0; i < N; i++) {
            // 调用所有注册到mChangeCallbacks中的BatteryStateChangeCallback类回调函数
            mChangeCallbacks.get(i).onBatteryLevelChanged(mLevel, mPluggedIn, mCharging);
        }
    }
}


// BatteryMeterDrawable 会通过此方法添加BatteryStateChangeCallback 回调函数
@Override
public void addCallback(BatteryController.BatteryStateChangeCallback cb) {
    synchronized (mChangeCallbacks) {
        mChangeCallbacks.add(cb);
    }
    if (!mHasReceivedBattery) return;
    cb.onBatteryLevelChanged(mLevel, mPluggedIn, mCharging);
    cb.onPowerSaveChanged(mPowerSave);
}

3. BatteryMeterDrawable 调用介绍

frameworks/base/packages/SystemUI/src/com/sprd/battery/BatteryMeterDrawable.java

public void startListening() {
    ...
    // 这里向BatteryControllerImpl 类注册了回调
    mBatteryController.addCallback(this);   
    ...
}

@Override
public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
    Log.d(TAG, "onBatteryLevelChanged level="+level+",pluggedIn="+pluggedIn+",charging="+charging);
    mLevel = level;
    mPluggedIn = pluggedIn; // 更新充电器插入状态
    mCharging = charging;
    postInvalidate(); // 重绘当前控件
}

Framework 层介绍

frameworks/base/services/core/java/com/android/server/BatteryService.java

private final class HealthHalCallback extends IHealthInfoCallback.Stub
        implements HealthServiceWrapper.Callback {
    @Override public void healthInfoChanged(android.hardware.health.V2_0.HealthInfo props) {
        BatteryService.this.update(props);
    }
    // on new service registered
    @Override public void onRegistration(IHealth oldService, IHealth newService,
            String instance) {
        if (newService == null) return;
        ...
        try {
            int r = newService.registerCallback(this); // 向IHealth hal 服务注册回调
            if (r != Result.SUCCESS) {
                Slog.w(TAG, "health: cannot register callback: " + Result.toString(r));
                return;
            }
            newService.update();
        ...
    }
}

@Override
public void onStart() {
    // 服务启动的时候会调用registerHealthCallback() 方法注册服务
    registerHealthCallback();
    mBinderService = new BinderService();
    publishBinderService("battery", mBinderService);
    mBatteryPropertiesRegistrar = new BatteryPropertiesRegistrar();
    publishBinderService("batteryproperties", mBatteryPropertiesRegistrar);
    publishLocalService(BatteryManagerInternal.class, new LocalService());
}

// 这里调用mHealthServiceWrapper.init() 方法初始化mHealthServiceWrapper
private void registerHealthCallback() {
    mHealthServiceWrapper = new HealthServiceWrapper();
    mHealthHalCallback = new HealthHalCallback();
    // IHealth is lazily retrieved.
    try {
        mHealthServiceWrapper.init(mHealthHalCallback,
                new HealthServiceWrapper.IServiceManagerSupplier() {},
                new HealthServiceWrapper.IHealthSupplier() {});
    ...
}

static final class HealthServiceWrapper {
    void init(Callback callback,
                IServiceManagerSupplier managerSupplier,
                IHealthSupplier healthSupplier)
            throws RemoteException, NoSuchElementException, NullPointerException {
        if (callback == null || managerSupplier == null || healthSupplier == null)
            throw new NullPointerException();
    
        IServiceManager manager;
    
        mCallback = callback;
        mHealthSupplier = healthSupplier;
    
        IHealth newService = null;
        for (String name : sAllInstances) {
            traceBegin("HealthInitGetService_" + name);
            try {
                newService = healthSupplier.get(name); // 获取IHealth hal 服务
            } catch (NoSuchElementException ex) {
                /* ignored, handled below */
            } finally {
                traceEnd();
            }
            if (newService != null) {
                mInstanceName = name;
                mLastService.set(newService);
                break;
            }
        }
        ...
        mCallback.onRegistration(null, newService, mInstanceName); // 调用onRegistration() 回调函数
        mHandlerThread.start();
        try {
            managerSupplier.get().registerForNotifications(
                    IHealth.kInterfaceName, mInstanceName, mNotification);
        ...
    }
    ...
}

Hal层介绍

在BatteryService.java 中使用到的IHealthInfoCallback和IHealth 都是Hal 服务,代码路径为:

  • hardware/interfaces/health/2.0/IHealth.hal
  • hardware/interfaces/health/2.0/IHealthInfoCallback.hal

Hal 服务实现路径为:

  • hardware/interfaces/health/2.0/default/Health.cpp
  • hardware/interfaces/health/2.0/default/HealthImplDefault.cpp

在BatteryService 中通过newService.registerCallback(this) 方法向IHealth 中注册了回调

接着查看我们Health::registerCallback() 方法

hardware/interfaces/health/2.0/default/Health.cpp

Return<Result> Health::registerCallback(const sp<IHealthInfoCallback>& callback) {
    ...
    {
        std::lock_guard<decltype(callbacks_lock_)> lock(callbacks_lock_);
        callbacks_.push_back(callback);  // 将callback 放到callbacks_ 中
    }
    ...
    return updateAndNotify(callback);
}

Return<Result> Health::updateAndNotify(const sp<IHealthInfoCallback>& callback) {
    std::lock_guard<decltype(callbacks_lock_)> lock(callbacks_lock_);
    std::vector<sp<IHealthInfoCallback>> storedCallbacks{std::move(callbacks_)};
    callbacks_.clear();
    if (callback != nullptr) {
        callbacks_.push_back(callback);
    }
    Return<Result> result = update(); // 接着会调用update() 方法更新电池状态信息
    callbacks_ = std::move(storedCallbacks);
    return result;
}

Return<Result> Health::update() {
    if (!healthd_mode_ops || !healthd_mode_ops->battery_update) {
        return Result::UNKNOWN;
    }
    bool chargerOnline = battery_monitor_->update(); // 调用BatteryMonitor::update() 方法更新电池状态
    healthd_battery_update_internal(chargerOnline);
    return Result::SUCCESS;
}

在之后会调用到BatteryMonitor::update() 方法中更新状态并上发状态到Framework 中

system/core/healthd/BatteryMonitor.cpp

bool BatteryMonitor::update(void) {
    bool logthis;

    initBatteryProperties(&props);

    if (!mHealthdConfig->batteryPresentPath.isEmpty())
        props.batteryPresent = getBooleanField(mHealthdConfig->batteryPresentPath);
    else
        props.batteryPresent = mBatteryDevicePresent;

    props.batteryLevel = mBatteryFixedCapacity ?
        mBatteryFixedCapacity :
        getIntField(mHealthdConfig->batteryCapacityPath);
    props.batteryVoltage = getIntField(mHealthdConfig->batteryVoltagePath) / 1000;

    if (!mHealthdConfig->batteryCurrentNowPath.isEmpty())
        props.batteryCurrent = getIntField(mHealthdConfig->batteryCurrentNowPath) / 1000;

    if (!mHealthdConfig->batteryFullChargePath.isEmpty())
        props.batteryFullCharge = getIntField(mHealthdConfig->batteryFullChargePath);

    if (!mHealthdConfig->batteryCycleCountPath.isEmpty())
        props.batteryCycleCount = getIntField(mHealthdConfig->batteryCycleCountPath);

    if (!mHealthdConfig->batteryChargeCounterPath.isEmpty())
        props.batteryChargeCounter = getIntField(mHealthdConfig->batteryChargeCounterPath);

    props.batteryTemperature = mBatteryFixedTemperature ?
        mBatteryFixedTemperature :
        getIntField(mHealthdConfig->batteryTemperaturePath);

    std::string buf;

    if (readFromFile(mHealthdConfig->batteryStatusPath, &buf) > 0)
        props.batteryStatus = getBatteryStatus(buf.c_str());

    if (readFromFile(mHealthdConfig->batteryHealthPath, &buf) > 0)
        props.batteryHealth = getBatteryHealth(buf.c_str());

    if (readFromFile(mHealthdConfig->batteryTechnologyPath, &buf) > 0)
        props.batteryTechnology = String8(buf.c_str());

    double MaxPower = 0;

    for (size_t i = 0; i < mChargerNames.size(); i++) {
        String8 path;
        path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH,
                          mChargerNames[i].string());
        if (getIntField(path)) {
            path.clear();
            path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH,
                              mChargerNames[i].string());
            switch(readPowerSupplyType(path)) {
            case ANDROID_POWER_SUPPLY_TYPE_AC:
                props.chargerAcOnline = true;
                break;
            case ANDROID_POWER_SUPPLY_TYPE_USB:
                props.chargerUsbOnline = true;
                break;
            case ANDROID_POWER_SUPPLY_TYPE_WIRELESS:
                props.chargerWirelessOnline = true;
                break;
            default:
                KLOG_WARNING(LOG_TAG, "%s: Unknown power supply type\n",
                             mChargerNames[i].string());
            }
            path.clear();
            path.appendFormat("%s/%s/current_max", POWER_SUPPLY_SYSFS_PATH,
                              mChargerNames[i].string());
            int ChargingCurrent =
                    (access(path.string(), R_OK) == 0) ? getIntField(path) : 0;

            path.clear();
            path.appendFormat("%s/%s/voltage_max", POWER_SUPPLY_SYSFS_PATH,
                              mChargerNames[i].string());

            int ChargingVoltage =
                (access(path.string(), R_OK) == 0) ? getIntField(path) :
                DEFAULT_VBUS_VOLTAGE;

            double power = ((double)ChargingCurrent / MILLION) *
                           ((double)ChargingVoltage / MILLION);
            if (MaxPower < power) {
                props.maxChargingCurrent = ChargingCurrent;
                props.maxChargingVoltage = ChargingVoltage;
                MaxPower = power;
            }
        }
    }

    ...

    healthd_mode_ops->battery_update(&props);
    return props.chargerAcOnline | props.chargerUsbOnline |
            props.chargerWirelessOnline;
}

在update() 方法里会读取/sys/class/power_supply 目录下的所有目录和节点,结果保存在props 中,通过healthd_mode_ops->battery_update() 方法上传到FW 层

healthd_mode_ops->battery_update() 方法在HealthServiceCommon.cpp 中做了初始化

hardware/interfaces/health/2.0/utils/libhealthservice/HealthServiceCommon.cpp

static struct healthd_mode_ops healthd_mode_service_2_0_ops = {
    .init = healthd_mode_service_2_0_init,
    .preparetowait = healthd_mode_service_2_0_preparetowait,
    .heartbeat = healthd_mode_service_2_0_heartbeat,
    .battery_update = healthd_mode_service_2_0_battery_update,
};

void healthd_mode_service_2_0_battery_update(struct android::BatteryProperties* prop) {
    HealthInfo info;
    convertToHealthInfo(prop, info.legacy);
    Health::getImplementation()->notifyListeners(&info);
}

在调用healthd_mode_ops->battery_update() 时,会调用到HealthServiceCommon:: healthd_mode_service_2_0_battery_update() 方法中,该方法会调用Health::getImplementation()->notifyListeners() 方法将prop数据传给Health.cpp 中,由Health调用notifyListeners() 方法调用从BatteryService 注册的回调实现数据上传给BatteryService 中

hardware/interfaces/health/2.0/default/Health.cpp

void Health::notifyListeners(HealthInfo* healthInfo) {
    ...
    std::lock_guard<decltype(callbacks_lock_)> lock(callbacks_lock_);
    for (auto it = callbacks_.begin(); it != callbacks_.end();) {
        auto ret = (*it)->healthInfoChanged(*healthInfo); // 这里就会调用BatteryService 里的healthInfoChanged() 方法
        if (!ret.isOk() && ret.isDeadObject()) {
            it = callbacks_.erase(it);
        } else {
            ++it;
        }
    }
}

在此方法中会调用BatteryService 的回调方法healthInfoChanged() 将数据传给BatteryService

Kernel 层分析

在Kernel层,如果power_supply目录下的节点更新了,会通过uenent 的方法通知上层节点修改了,接受通知的地方在healthd_common::healthd_mainloop() 中定义的

healthd_common::healthd_mainloop() 方法的初始化流程:

HealthServiceDefault::main() ->HealthServiceCommon::health_service_main() -> healthd_common::healthd_main() -> healthd_common::healthd_mainloop()

hardware/interfaces/health/2.0/default/healthd_common.cpp

static void healthd_mainloop(void) {
    int nevents = 0;
    while (1) {
        struct epoll_event events[eventct];
        int timeout = awake_poll_interval;
        int mode_timeout;

        /* Don't wait for first timer timeout to run periodic chores */
        if (!nevents) periodic_chores();

        healthd_mode_ops->heartbeat();

        mode_timeout = healthd_mode_ops->preparetowait();
        if (timeout < 0 || (mode_timeout > 0 && mode_timeout < timeout)) timeout = mode_timeout;
        nevents = epoll_wait(epollfd, events, eventct, timeout);
        if (nevents == -1) {
            if (errno == EINTR) continue;
            KLOG_ERROR(LOG_TAG, "healthd_mainloop: epoll_wait failed\n");
            break;
        }

        for (int n = 0; n < nevents; ++n) {
            if (events[n].data.ptr) (*(void (*)(int))events[n].data.ptr)(events[n].events);
        }
    }

    return;
}

healthd_mainloop() 方法会通过一直循环接收uevent 事件,当接受了事件,则调用events[n].data.ptr 方法

hardware/interfaces/health/2.0/default/healthd_common.cpp

static int healthd_init() {
    epollfd = epoll_create(EPOLL_CLOEXEC);
    if (epollfd == -1) {
        KLOG_ERROR(LOG_TAG, "epoll_create1 failed; errno=%d\n", errno);
        return -1;
    }

    healthd_mode_ops->init(&healthd_config);
    wakealarm_init();
    uevent_init();

    return 0;
}


static void uevent_init(void) {
    uevent_fd = uevent_open_socket(64 * 1024, true);

    if (uevent_fd < 0) {
        KLOG_ERROR(LOG_TAG, "uevent_init: uevent_open_socket failed\n");
        return;
    }

    fcntl(uevent_fd, F_SETFL, O_NONBLOCK);
    if (healthd_register_event(uevent_fd, uevent_event, EVENT_WAKEUP_FD))
        KLOG_ERROR(LOG_TAG, "register for uevent events failed\n");
}

int healthd_register_event(int fd, void (*handler)(uint32_t), EventWakeup wakeup) {
    struct epoll_event ev;

    ev.events = EPOLLIN;

    if (wakeup == EVENT_WAKEUP_FD) ev.events |= EPOLLWAKEUP;

    ev.data.ptr = (void*)handler;
    if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) == -1) {
        KLOG_ERROR(LOG_TAG, "epoll_ctl failed; errno=%d\n", errno);
        return -1;
    }

    eventct++;
    return 0;
}

从上面可以看到data.ptr 为uevent_event 方法

hardware/interfaces/health/2.0/default/healthd_common.cpp

#define UEVENT_MSG_LEN 2048
static void uevent_event(uint32_t /*epevents*/) {
    char msg[UEVENT_MSG_LEN + 2];
    char* cp;
    int n;

    n = uevent_kernel_multicast_recv(uevent_fd, msg, UEVENT_MSG_LEN);
    if (n <= 0) return;
    if (n >= UEVENT_MSG_LEN) /* overflow -- discard */
        return;

    msg[n] = '\0';
    msg[n + 1] = '\0';
    cp = msg;

    while (*cp) {
        if (!strcmp(cp, "SUBSYSTEM=" POWER_SUPPLY_SUBSYSTEM)) {
            healthd_battery_update(); // 通知Monitor 更新Battery 信息
            break;
        }

        /* advance to after the next \0 */
        while (*cp++)
            ;
    }
}

static void healthd_battery_update(void) {
    Health::getImplementation()->update(); // 调用Health.cpp 里面的update() 方法
}
bsp/kernel/kernel4.14/drivers/power/supply/charger-manager.c

static int charger_manager_probe(struct platform_device *pdev)
{
    ...
    charger_manager_policy_init(cm);
    ...
}


static int charger_manager_policy_init(struct charger_manager *cm)
{
    ...
    INIT_DELAYED_WORK(&(cm->policy.usb_changed_work), policy_usb_change_handler_work);
    ...
    cm->policy.usb_notify.notifier_call = policy_usb_change_callback; // 这里会注册usb 通知,当插入USB时,会调用notifier_call() 方法
    ret = usb_register_notifier(cm->policy.usb_phy, &cm->policy.usb_notify);
    ...
}

static int policy_usb_change_callback(struct notifier_block *nb,
                       unsigned long limit, void *data)
{
    struct charger_policy *info =
        container_of(nb, struct charger_policy, usb_notify);
    info->limit = limit;
    vote_debug("policy_usb_change_callback: %d\n", (uint)limit);
    schedule_delayed_work(&info->usb_changed_work, msecs_to_jiffies(100)); // 接着触发usb_changed_work() 方法, 即policy_usb_change_handler_work()
    return NOTIFY_OK;
}

static void policy_usb_change_handler_work(struct work_struct *work)
{
    ...
    cm_notify_event(info->hook_psy, CM_EVENT_CHG_START_STOP, NULL);
    ...
}

static void cm_notify_type_handle(struct charger_manager *cm, enum cm_event_types type, char *msg)
{
    ...
    power_supply_changed(cm->charger_psy);
}

power_supply_changed() 方法在power_supply_core.c 定义的

bsp/kernel/kernel4.14/drivers/power/supply/power_supply_core.c

void power_supply_changed(struct power_supply *psy)
{
    unsigned long flags;
    dev_dbg(&psy->dev, "%s\n", __func__);

    spin_lock_irqsave(&psy->changed_lock, flags);
    psy->changed = true;
    pm_stay_awake(&psy->dev);
    spin_unlock_irqrestore(&psy->changed_lock, flags);
    schedule_work(&psy->changed_work);
}
EXPORT_SYMBOL_GPL(power_supply_changed);

之后会调用power_supply_changed_work() 方法


static void power_supply_changed_work(struct work_struct *work)
{
    unsigned long flags;
    struct power_supply *psy = container_of(work, struct power_supply,
                        changed_work);

    dev_dbg(&psy->dev, "%s\n", __func__);

    spin_lock_irqsave(&psy->changed_lock, flags);

    if (likely(psy->changed)) {
        psy->changed = false;
        spin_unlock_irqrestore(&psy->changed_lock, flags);
        class_for_each_device(power_supply_class, NULL, psy,
                      __power_supply_changed_work);
        power_supply_update_leds(psy);
        // 通知注册在power_supply_notifier通知链上的所有的通知回调函数,并将psy传递过去
        atomic_notifier_call_chain(&power_supply_notifier,
                PSY_EVENT_PROP_CHANGED, psy);
        kobject_uevent(&psy->dev.kobj, KOBJ_CHANGE); // 这里会通过uevent 的方式通知用户空间
        spin_lock_irqsave(&psy->changed_lock, flags);
    }

    if (likely(!psy->changed))
        pm_relax(&psy->dev);
    spin_unlock_irqrestore(&psy->changed_lock, flags);
}
bsp/kernel/kernel4.14/lib/kobject_uevent.c

int kobject_uevent(struct kobject *kobj, enum kobject_action action)
{
    return kobject_uevent_env(kobj, action, NULL);
}
EXPORT_SYMBOL_GPL(kobject_uevent);

int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
               char *envp_ext[])
{
    ...
    if (uevent_ops && uevent_ops->uevent) {
        retval = uevent_ops->uevent(kset, kobj, env);
        if (retval) {
            pr_debug("kobject: '%s' (%p): %s: uevent() returned "
                 "%d\n", kobject_name(kobj), kobj,
                 __func__, retval);
            goto exit;
        }
    }
    ...
}

uevent_ops->uevent() 方法将会调用power_supply_sysfs::power_supply_uevent() 方法,定义的位置在power_supply_class_init() 方法中

bsp/kernel/kernel4.14/drivers/power/supply/power_supply_core.c

static int __init power_supply_class_init(void)
{
    power_supply_class = class_create(THIS_MODULE, "power_supply");
    ...
    power_supply_class->dev_uevent = power_supply_uevent; // 这个power_supply_uevent方法会去读取power_supply 目录下的所有节点信息
    ...
}

kobject_uevent_env() 函数的主要功能是根据参数组合一个字符串并发送。一个典型的字符串如下:

ACTION=change DEVPATH=/devices/qpnp-charger-eab16c00/power_supply/battery

SUBSYSTEM=power_supply POWER_SUPPLY_NAME=battery

POWER_SUPPLY_STATUS=Charging POWER_SUPPLY_HEALTH=Good

POWER_SUPPLY_PRESENT=1 POWER_SUPPLY_VOLTAGE_NOW=3751000

POWER_SUPPLY_VOLTAGE_AVG=3751000 POWER_SUPPLY_CAPACITY=14

POWER_SUPPLY_ONLINE=1 POWER_SUPPLY_CHARGE_FULL=2000000

POWER_SUPPLY_CONSTANT_CHARGE_CURRENT=500000

POWER_SUPPLY_INPUT_CURRENT_LIMIT=500000

POWER_SUPPLY_CURRENT_NOW=261000

POWER_SUPPLY_CURRENT_AVG=261000

POWER_SUPPLY_CHARGE_COUNTER=260000

POWER_SUPPLY_CHARGE_CONTROL_LIMIT=1000000

POWER_SUPPLY_CHARGE_FULL_DESIGN=2000000

POWER_SUPPLY_CAPACITY_RAW=13 POWER_SUPPLY_VOLTAGE_OCV=3675357

POWER_SUPPLY_VOLTAGE_MAX=4350000

POWER_SUPPLY_CURRENT_COUNTER_MBTK=261175

POWER_SUPPLY_SET_SHIP_MODE=-1 POWER_SUPPLY_TECHNOLOGY=Li-ion

POWER_SUPPLY_CHARGING_ENABLED=1

POWER_SUPPLY_BATTERY_CHARGING_ENABLED=1

POWER_SUPPLY_TIME_TO_FULL_NOW=12528

POWER_SUPPLY_CURRENT_NOW=261000 POWER_SUPPLY_TEMP=307

在kobject_uevent_env() 方法中,retval = add_uevent_var(env, "%s", envp_ext[i]);//将kernel想要发送的状态信息存储起来。

最终是通过netlink_broadcast_filtered向用户空间发送了uevent信息。

发送了uevent 消息,总会有一个地方接收,那么接收这个uevent 信息的在方法uevent_event里

hardware/interfaces/health/2.0/default/healthd_common.cpp

#define UEVENT_MSG_LEN 2048
static void uevent_event(uint32_t /*epevents*/) {
    char msg[UEVENT_MSG_LEN + 2];
    char* cp;
    int n;

    n = uevent_kernel_multicast_recv(uevent_fd, msg, UEVENT_MSG_LEN);
    if (n <= 0) return;
    if (n >= UEVENT_MSG_LEN) /* overflow -- discard */
        return;

    msg[n] = '\0';
    msg[n + 1] = '\0';
    cp = msg;

    while (*cp) {
        if (!strcmp(cp, "SUBSYSTEM=" POWER_SUPPLY_SUBSYSTEM)) {
            healthd_battery_update();
            break;
        }

        /* advance to after the next \0 */
        while (*cp++)
            ;
    }
}

通过uevent_kernel_multicast_recv() 方法获取uevent 通知,在通过与 "SUBSYSTEM=" POWER_SUPPLY_SUBSYSTEM 进行比较,判断是否是来自power_supply子系统的,如果是,则调用healthd_battery_update() 方法向上层发送Battery 信息。

参考

  •  Android Healthd电池服务分析
  • 基于Android Q电池服务分析
  • Battery监听流程
  • Linux下的power_supply小析
  • linux驱动DEVICE_ATTR使用、热插拔上报uevent及驱动启动一个c语言用语
  • 基于power supply信息传递的uevent机制
  • power supply是如何上报电池信息的 ​

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

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

相关文章

【ChatGPT辅助学Rust | 基础系列 | 基础语法】变量,数据类型,运算符,控制流

文章目录 简介&#xff1a;一&#xff0c;变量1&#xff0c;变量的定义2&#xff0c;变量的可变性3&#xff0c;变量的隐藏 二、数据类型1&#xff0c;标量类型2&#xff0c;复合类型 三&#xff0c;运算符1&#xff0c;算术运算符2&#xff0c;比较运算符3&#xff0c;逻辑运算…

Redis系列二:Clion+MAC+Redis环境搭建

1. ClionMACRedis-3.0-annotated环境搭建 参考&#xff1a; https://github.com/huangz1990/redis-3.0-annotated https://gitee.com/dumpcao/redis-3.0-annotated-cmake-in-clion https://tool.4xseo.com/a/12910.html 1.1 下载并导入Clion git clone https://gitee.com/dum…

基于SSM+JSP+LayUI的校园任务帮管理系统

校园帮项目 校园即时服务平台 用户角色 管理员 功能 登录、公告管理&#xff08;发布公告、停用公告&#xff09;、任务管理&#xff08;下架任务、删除任务&#xff09;、用户管理&#xff08;用户充值、限制用户&#xff09;、修改密码 用户角色 用户 功能 注册、登录…

Allied Telesis 证实 AR4050S-5G 路由器已成功通过 Splashtop On-Prem 快速处理现场数据

日本东京 —— Allied Telesis Inc. 和 NTT Comware Corporation 很高兴地宣布&#xff0c;Allied Telesis AR4050S-5G 路由器经证实已与 Splashtop On-Prem 解决方案成功集成&#xff0c;可安全快速地处理现场数据。根据测试结果&#xff0c;使用该方案&#xff0c;可以在实地…

dolphinscheduler switch+传参无坑版

dolphinscheduler 的前后传参有较多的坑&#xff0c;即便是3.0.5版本仍然有一些bug 下面是目前能无坑在3.0.5版本上使用的操作 前置任务 在界面上设置变量和参数名称 跟官方网站不一样&#xff0c;注意最后一行一定使用echo ${setValue(key$query)}的方式&#xff0c;注意引…

一次web网页设计实践——checkbox单选、复选功能的实现

由于工作内容原因近期做了一个网页&#xff0c;记录下。 需求&#xff1a; 写一个如下的页面&#xff0c;包括checkbox单选&#xff0c;checkbox多选&#xff0c;slect&#xff0c;text等控件 内容&#xff1a; 一、checkbox &#xff08;Wlan 开关&#xff09; 要求&#x…

基于Java+SpringBoot制作一个学生公寓管理小程序

制作一个学生公寓管理小程序,旨在优化和简化学生公寓的日常管理工作。该系统涵盖了各种功能模块,以满足学生住宿的需求,同时提供方便、高效的管理方式,该系统包含用户管理、卫生评比、来访登记、宿舍报修等模块。 一、小程序1.1 项目创建1.2 首页轮播图快捷导航iconfont图标…

git撤销提交,新建、删除分支汇总

目录 git 撤销中间某次提交&#xff0c;保留其他提交的方法git 撤销已经push的代码git 新建分支git 删除分支 git 撤销中间某次提交&#xff0c;保留其他提交的方法 git revert commit_id 通过git log 获取commit_id。 如果commit_id是merge节点的话&#xff0c;-m是指定具…

一种嵌入式LCD显示多国语言方法

简介 介绍一种嵌入式LCD显示多国语言方法&#xff0c;由于很多产品嵌入式资源有限&#xff0c;显示的字符也不多&#xff0c;所以可以自己制作一些字库&#xff0c;而不用字库芯片。 下面展示一种从字库取出字符的方法。 代码示例 #include <stdio.h> #include <s…

安装win版本的neo4j(2023最新版本)

安装win版本的neo4j 写在最前面安装 win版本的neo4j1. 安装JDK2.下载配置环境变量&#xff08;也可选择直接点击快捷方式&#xff0c;就可以不用配环境了&#xff09;3. 启动neo4j 测试代码遇到的问题及解决&#xff08;每次环境都太离谱了&#xff0c;各种问题&#xff09;连接…

八大排序算法--选择排序(动图理解)

选择排序 算法思路 每一次从待排序的数据元素中选出最小&#xff08;或最大&#xff09;的一个元素&#xff0c;存放在序列的起始位置&#xff0c;直到全部待排序的数据元素排完 。 选择排序的步骤&#xff1a; 1>首先在未排序序列中找到最小&#xff08;大&#xff09;元素…

原创 | 数字身份智能体的基本原理及应用前景展望

作者&#xff1a;张家林 本文约5700字&#xff0c;建议阅读10分钟 本文主要探讨自然人数字身份智能体的基本原理、关键技术及其应用前景的挑战。 数字身份智能体&#xff08;DIAs: digital identity agents&#xff09;是通过将一个实体的行为模式、个体特征等信息经过数据化、…

第3章 DOM

文档&#xff1a;DOM中的“D” 如果没有document&#xff08;文档&#xff09;, DOM也就无从谈起。当创建了一个网页并把它加载到Web浏览器中时&#xff0c;DOM就在幕后悄然而生。它把你编写的网页文档转换为一个文档对象。 对象&#xff1a;DOM中的“O” js中的对象分为三种…

Python入门【__init__ 构造方法和 __new__ 方法、类对象、类属性、类方法、静态方法、内存分析实例对象和类对象创建过程(重要)】(十四)

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱敲代码的小王&#xff0c;CSDN博客博主,Python小白 &#x1f4d5;系列专栏&#xff1a;python入门到实战、Python爬虫开发、Python办公自动化、Python数据分析、Python前后端开发 &#x1f4e7;如果文章知识点有错误…

MySQL运维 从全备sql文件中提取指定表的数据并恢复

目录 一、运行环境 二、需求说明 三、思路分析 五、具体方案 六、恢复表数据 一、运行环境 系统&#xff1a;CentOS7.3 数据库&#xff1a;MySQL 8.0.21 二、需求说明 线上有个表的数据被误操作了很多&#xff0c;无法通过bin-log进行具体的恢复。所以当前我们需要从全…

推荐几款好用的建筑项目管理软件

工程项目管理软件在现代项目管理中扮演着越来越重要的角色&#xff0c;此类软件可以帮助团队把控从“立项”到“验收”各个阶段的项目进度&#xff0c;从而达到降低项目成本&#xff0c;提高项目执行效率的目的。 作为一个在项目管理领域奋斗过6年的项目经理&#xff0c;下面给…

Java maven的下载解压配置(保姆级教学)

mamen基本概念 Maven项目对象模型(POM)&#xff0c;可以通过一小段描述信息来管理项目的构建&#xff0c;报告和文档的项目管理工具软件。 Maven 除了以程序构建能力为特色之外&#xff0c;还提供高级项目管理工具。由于 Maven 的缺省构建规则有较高的可重用性&#xff0c;所以…

神经概率语言模型

本文主要参考《A Neural Probabilistic Language Model》这是一篇很重要的语言模型论文,发表于2003年。主要贡献如下: 提出了一种基于神经网络的语言模型&#xff0c;是较早将神经网络应用于语言模型领域的工作之一&#xff0c;具有里程碑意义。采用神经网络模型预测下一个单词…

Spring框架 —— 控制反转IOC

前言 在前一篇文章中荔枝已经初步了解了Spring并通过一个入门案例了解了Spring的基本操作&#xff0c;接下来荔枝就要梳理Spring中的最为重要的知识点之一——IoC控制反转&#xff0c;控制反转和属性注入均是基于Java中的反射机制来实现的。所以学习这个知识点之前必须要学习Ja…

【无标题】使用Debate Dynamics在知识图谱上进行推理(2020)7.31

使用Debate Dynamics在知识图谱上进行推理 摘要介绍背景与相关工作我们的方法 摘要 我们提出了一种新的基于 Debate Dynamics 的知识图谱自动推理方法。 其主要思想是将三重分类任务定义为两个强化学习主体之间的辩论游戏&#xff0c;这两个主体提取论点&#xff08;知识图中…