深入分析android5.1 healthd

来源:互联网 发布:凯撒博尔吉亚 知乎 编辑:程序博客网 时间:2024/06/07 01:08

healthd主要是读取电池节点的信息,传给BatteryService。或者在关机充电等使用。注意healthd中使用的是kernel的log。

下面先从main函数分析

int main(int argc, char **argv) {    int ch;    int ret;    klog_set_level(KLOG_LEVEL);    healthd_mode_ops = &android_ops;    if (!strcmp(basename(argv[0]), "charger")) {//解析输入参数如果是charger的使用charger_ops,这里就不做介绍        healthd_mode_ops = &charger_ops;    } else {        while ((ch = getopt(argc, argv, "cr")) != -1) {//分析输入命令,各个命令对应不同的charger_ops            switch (ch) {            case 'c':                healthd_mode_ops = &charger_ops;                break;            case 'r':                healthd_mode_ops = &recovery_ops;                break;            case '?':            default:                KLOG_ERROR(LOG_TAG, "Unrecognized healthd option: %c\n",                           optopt);                exit(1);            }        }    }    ret = healthd_init();//healthd做初始化    if (ret) {        KLOG_ERROR("Initialization failed, exiting\n");        exit(2);    }    healthd_mainloop();//主函数    KLOG_ERROR("Main loop terminated, exiting\n");    return 3;}

如果是正常开机,不走关机充电等,healthd_mode_ops = &android_ops;而这里面具体的函数在后面进行详细的介绍。

static struct healthd_mode_ops android_ops = {    .init = healthd_mode_android_init,    .preparetowait = healthd_mode_android_preparetowait,    .heartbeat = healthd_mode_nop_heartbeat,    .battery_update = healthd_mode_android_battery_update,};

下面分析下healthd_init函数,heathd使用了epoll进行IO复用。

static int healthd_init() {    epollfd = epoll_create(MAX_EPOLL_EVENTS);    if (epollfd == -1) {        KLOG_ERROR(LOG_TAG,                   "epoll_create failed; errno=%d\n",                   errno);        return -1;    }    healthd_board_init(&healthd_config);    healthd_mode_ops->init(&healthd_config);    wakealarm_init();    uevent_init();    gBatteryMonitor = new BatteryMonitor();    gBatteryMonitor->init(&healthd_config);    return 0;}


这里的healthd_mode_ops->init的函数是android_ops 的healthd_mode_android_init函数,这里主要是将binder通信的fd也加入epoll,而不像普通binder进程最后使用IPCThreadState::self()->joinThreadPool。这样所有的fd全在epoll管理,只用了一个线程

int healthd_mode_android_preparetowait(void) {    IPCThreadState::self()->flushCommands();    return -1;}static void binder_event(uint32_t /*epevents*/) {    IPCThreadState::self()->handlePolledCommands();}void healthd_mode_android_init(struct healthd_config* /*config*/) {    ProcessState::self()->setThreadPoolMaxThreadCount(0);    IPCThreadState::self()->disableBackgroundScheduling(true);    IPCThreadState::self()->setupPolling(&gBinderFd);    if (gBinderFd >= 0) {        if (healthd_register_event(gBinderFd, binder_event))            KLOG_ERROR(LOG_TAG,                       "Register for binder events failed\n");    }    gBatteryPropertiesRegistrar = new BatteryPropertiesRegistrar();    gBatteryPropertiesRegistrar->publish();}

gBatteryPropertiesRegistrar->publish将"batteryproperties"这个Service加入到ServiceManager中

void BatteryPropertiesRegistrar::publish() {    defaultServiceManager()->addService(String16("batteryproperties"), this);}

接下来再来看下wakealarm_init

static void wakealarm_init(void) {    wakealarm_fd = timerfd_create(CLOCK_BOOTTIME_ALARM, TFD_NONBLOCK);    if (wakealarm_fd == -1) {        KLOG_ERROR(LOG_TAG, "wakealarm_init: timerfd_create failed\n");        return;    }    if (healthd_register_event(wakealarm_fd, wakealarm_event))        KLOG_ERROR(LOG_TAG,                   "Registration of wakealarm event failed\n");    wakealarm_set_interval(healthd_config.periodic_chores_interval_fast);}

wakealarm_init设置alarm唤醒的interval,再来看下时间处理函数

static void wakealarm_event(uint32_t /*epevents*/) {    unsigned long long wakeups;    if (read(wakealarm_fd, &wakeups, sizeof(wakeups)) == -1) {//出错结束        KLOG_ERROR(LOG_TAG, "wakealarm_event: read wakealarm fd failed\n");        return;    }KLOG_ERROR(LOG_TAG, "wakealarm_event\n");    periodic_chores();}
static void periodic_chores() {    healthd_battery_update();}
void healthd_battery_update(void) {    // Fast wake interval when on charger (watch for overheat);    // slow wake interval when on battery (watch for drained battery).KLOG_ERROR(LOG_TAG, "healthd_battery_update enter\n");   int new_wake_interval = gBatteryMonitor->update() ?//调用主要的update函数,根据返回值,如果当前在充电返回true       healthd_config.periodic_chores_interval_fast ://时间设置1分钟           healthd_config.periodic_chores_interval_slow;KLOG_ERROR(LOG_TAG, "healthd_battery_update after\n");    if (new_wake_interval != wakealarm_wake_interval)            wakealarm_set_interval(new_wake_interval);    // During awake periods poll at fast rate.  If wake alarm is set at fast    // rate then just use the alarm; if wake alarm is set at slow rate then    // poll at fast rate while awake and let alarm wake up at slow rate when    // asleep.    if (healthd_config.periodic_chores_interval_fast == -1)        awake_poll_interval = -1;    else        awake_poll_interval =            new_wake_interval == healthd_config.periodic_chores_interval_fast ?//当前时间是一分钟,epoll为永远阻塞,否则为1分钟                -1 : healthd_config.periodic_chores_interval_fast * 1000;}

接下来再来看看uEvent的,

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))        KLOG_ERROR(LOG_TAG,                   "register for uevent events failed\n");}

看看uevent_event的处理函数,获取uevent后主要判断是否是电源系统的,如果是调用healthd_battery_update函数

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;KLOG_ERROR(LOG_TAG, "uevent_event\n");    while (*cp) {        if (!strcmp(cp, "SUBSYSTEM=" POWER_SUPPLY_SUBSYSTEM)) {//是这个子系统的调用healthd_battery_update函数            healthd_battery_update();            break;        }        /* advance to after the next \0 */        while (*cp++)            ;    }}


下面分析下healthd_mainloop这个主函数,主函数主要是epoll函数监听3个fd,有事件就处理。

static void healthd_mainloop(void) {    while (1) {        struct epoll_event events[eventct];        int nevents;        int timeout = awake_poll_interval;        int mode_timeout;        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);//epoll_wait等待各个fd的事件,timeout为超时时间KLOG_ERROR(LOG_TAG, "kangchen healthd_mainloop epoll_wait\n");        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)//遍历各个fd的事件上来,每个处理函数处理                (*(void (*)(int))events[n].data.ptr)(events[n].events);        }        if (!nevents)//当什么事件没有的时候,是因为epoll超时设置走下来的,这时候也要update下            periodic_chores();        healthd_mode_ops->heartbeat();    }    return;}


init函数主要将healthd_config 对象传入,并且将里面的成员的一些地址信息去初始化保存起来。主要是保存一些地址信息,以及充电方式。

void BatteryMonitor::init(struct healthd_config *hc) {    String8 path;    char pval[PROPERTY_VALUE_MAX];    mHealthdConfig = hc;//将外面传进来的heathdconfig的指针赋给成员变量    DIR* dir = opendir(POWER_SUPPLY_SYSFS_PATH);//打开地址 /sys/class/power_supply    if (dir == NULL) {        KLOG_ERROR(LOG_TAG, "Could not open %s\n", POWER_SUPPLY_SYSFS_PATH);    } else {        struct dirent* entry;        while ((entry = readdir(dir))) {            const char* name = entry->d_name;            if (!strcmp(name, ".") || !strcmp(name, ".."))                continue;            char buf[20];            // Look for "type" file in each subdirectory            path.clear();            path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH, name);            switch(readPowerSupplyType(path)) {//读取各个目录下type的值,比如/sys/class/power_supply/battery 下type的值为Battery,在readPowerSupplyType读取并且转化为ANDROID_POWER_SUPPLY_TYPE_BATTERY            case ANDROID_POWER_SUPPLY_TYPE_AC:                if (mHealthdConfig->acChargeHeathPath.isEmpty()) {                    path.clear();                    path.appendFormat("%s/%s/health", POWER_SUPPLY_SYSFS_PATH,                                      name);                    if (access(path, R_OK) == 0)                        mHealthdConfig->acChargeHeathPath = path;//配置路径                }                path.clear();                path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH, name);                if (access(path.string(), R_OK) == 0)                    mChargerNames.add(String8(name));//chargername 就是当前目录名字:ac                break;            case ANDROID_POWER_SUPPLY_TYPE_USB://usb 类似ac                if (mHealthdConfig->usbChargeHeathPath.isEmpty()) {                    path.clear();                    path.appendFormat("%s/%s/health", POWER_SUPPLY_SYSFS_PATH,                                      name);                    if (access(path, R_OK) == 0)                        mHealthdConfig->usbChargeHeathPath = path;                }                path.clear();                path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH, name);                if (access(path.string(), R_OK) == 0)                    mChargerNames.add(String8(name));                break;            case ANDROID_POWER_SUPPLY_TYPE_WIRELESS://类似                path.clear();                path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH, name);                if (access(path.string(), R_OK) == 0)                    mChargerNames.add(String8(name));                break;            case ANDROID_POWER_SUPPLY_TYPE_BATTERY://battery                mBatteryDevicePresent = true;                if (mHealthdConfig->batteryStatusPath.isEmpty()) {                    path.clear();                    path.appendFormat("%s/%s/status", POWER_SUPPLY_SYSFS_PATH,                                      name);                    if (access(path, R_OK) == 0)                        mHealthdConfig->batteryStatusPath = path;                }                if (mHealthdConfig->batteryHealthPath.isEmpty()) {                    path.clear();                    path.appendFormat("%s/%s/health", POWER_SUPPLY_SYSFS_PATH,                                      name);                    if (access(path, R_OK) == 0)                        mHealthdConfig->batteryHealthPath = path;                }                if (mHealthdConfig->batteryPresentPath.isEmpty()) {                    path.clear();                    path.appendFormat("%s/%s/present", POWER_SUPPLY_SYSFS_PATH,                                      name);                    if (access(path, R_OK) == 0)                        mHealthdConfig->batteryPresentPath = path;                }                if (mHealthdConfig->batteryCapacityPath.isEmpty()) {                    path.clear();                    path.appendFormat("%s/%s/capacity", POWER_SUPPLY_SYSFS_PATH,                                      name);                    if (access(path, R_OK) == 0)                        mHealthdConfig->batteryCapacityPath = path;                }                if (mHealthdConfig->batteryVoltagePath.isEmpty()) {                    path.clear();                    path.appendFormat("%s/%s/voltage_now",                                      POWER_SUPPLY_SYSFS_PATH, name);                    if (access(path, R_OK) == 0) {                        mHealthdConfig->batteryVoltagePath = path;                    } else {                        path.clear();                        path.appendFormat("%s/%s/batt_vol",                                          POWER_SUPPLY_SYSFS_PATH, name);                        if (access(path, R_OK) == 0)                            mHealthdConfig->batteryVoltagePath = path;                    }                }                if (mHealthdConfig->batteryCurrentNowPath.isEmpty()) {                    path.clear();                    path.appendFormat("%s/%s/current_now",                                      POWER_SUPPLY_SYSFS_PATH, name);                    if (access(path, R_OK) == 0)                        mHealthdConfig->batteryCurrentNowPath = path;                }                if (mHealthdConfig->batteryCurrentAvgPath.isEmpty()) {                    path.clear();                    path.appendFormat("%s/%s/current_avg",                                      POWER_SUPPLY_SYSFS_PATH, name);                    if (access(path, R_OK) == 0)                        mHealthdConfig->batteryCurrentAvgPath = path;                }                if (mHealthdConfig->batteryChargeCounterPath.isEmpty()) {                    path.clear();                    path.appendFormat("%s/%s/charge_counter",                                      POWER_SUPPLY_SYSFS_PATH, name);                    if (access(path, R_OK) == 0)                        mHealthdConfig->batteryChargeCounterPath = path;                }                if (mHealthdConfig->batteryTemperaturePath.isEmpty()) {                    path.clear();                    path.appendFormat("%s/%s/temp", POWER_SUPPLY_SYSFS_PATH,                                      name);                    if (access(path, R_OK) == 0) {                        mHealthdConfig->batteryTemperaturePath = path;                    } else {                        path.clear();                        path.appendFormat("%s/%s/batt_temp",                                          POWER_SUPPLY_SYSFS_PATH, name);                        if (access(path, R_OK) == 0)                            mHealthdConfig->batteryTemperaturePath = path;                    }                }                if (mHealthdConfig->batteryTechnologyPath.isEmpty()) {                    path.clear();                    path.appendFormat("%s/%s/technology",                                      POWER_SUPPLY_SYSFS_PATH, name);                    if (access(path, R_OK) == 0)                        mHealthdConfig->batteryTechnologyPath = path;                }                break;            case ANDROID_POWER_SUPPLY_TYPE_UNKNOWN:                break;            }        }        closedir(dir);    }    if (!mChargerNames.size())        KLOG_ERROR(LOG_TAG, "No charger supplies found\n");    if (!mBatteryDevicePresent) {//主要由battery该成员变量就为true        KLOG_WARNING(LOG_TAG, "No battery devices found\n");        hc->periodic_chores_interval_fast = -1;        hc->periodic_chores_interval_slow = -1;    } else {        if (mHealthdConfig->batteryStatusPath.isEmpty())            KLOG_WARNING(LOG_TAG, "BatteryStatusPath not found\n");。。。。。。。。。。。。。//这里都是一些警告    }    if (property_get("ro.boot.fake_battery", pval, NULL) > 0                                               && strtol(pval, NULL, 10) != 0) {        mBatteryFixedCapacity = FAKE_BATTERY_CAPACITY;        mBatteryFixedTemperature = FAKE_BATTERY_TEMPERATURE;    }}

下面就是update函数,将数据封装在BatteryProperties 中,并且通过healthd_mode_ops->battery_update把BatteryProperties 发给上层。

bool BatteryMonitor::update(void) {    bool logthis;    props.chargerAcOnline = false;    props.chargerUsbOnline = false;    props.chargerWirelessOnline = false;    props.batteryStatus = BATTERY_STATUS_UNKNOWN;    props.batteryHealth = BATTERY_HEALTH_UNKNOWN;//都是从之前配置的mHealthd中取地址,读取节点信息,保存到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;    props.batteryTemperature = mBatteryFixedTemperature ?        mBatteryFixedTemperature :        getIntField(mHealthdConfig->batteryTemperaturePath);    const int SIZE = 128;    char buf[SIZE];    String8 btech;    if (readFromFile(mHealthdConfig->batteryStatusPath, buf, SIZE) > 0)        props.batteryStatus = getBatteryStatus(buf);    if (readFromFile(mHealthdConfig->batteryHealthPath, buf, SIZE) > 0)        props.batteryHealth = getBatteryHealth(buf);    if (readFromFile(mHealthdConfig->batteryTechnologyPath, buf, SIZE) > 0)        props.batteryTechnology = String8(buf);    if (readFromFile(mHealthdConfig->acChargeHeathPath, buf, SIZE) > 0)        props.acChargeHeath= String8(buf);    if (readFromFile(mHealthdConfig->usbChargeHeathPath, buf, SIZE) > 0)        props.usbChargeHeath= String8(buf);    unsigned int i;    for (i = 0; i < mChargerNames.size(); i++) {//遍历之前保存的各个充电方式        String8 path;        path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH,                          mChargerNames[i].string());//路径就是每个目录下的online字段,比如/sys/class/power_supply/usb 下的online        if (readFromFile(path, buf, SIZE) > 0) {            if (buf[0] != '0') {//读取online里面的内容,如果当前在usb线上充电,那么usb下online里面的内容为1                path.clear();                path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH,                                  mChargerNames[i].string());//这里看看是哪个type的                switch(readPowerSupplyType(path)) {                case ANDROID_POWER_SUPPLY_TYPE_AC:                    props.chargerAcOnline = true;                    break;                case ANDROID_POWER_SUPPLY_TYPE_USB://将其值赋成true                    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());                }            }        }    }    logthis = !healthd_board_battery_update(&props);    if (logthis) {        char dmesgline[256];        if (props.batteryPresent) {            snprintf(dmesgline, sizeof(dmesgline),                 "battery l=%d v=%d t=%s%d.%d h=%d st=%d",                 props.batteryLevel, props.batteryVoltage,                 props.batteryTemperature < 0 ? "-" : "",                 abs(props.batteryTemperature / 10),                 abs(props.batteryTemperature % 10), props.batteryHealth,                 props.batteryStatus);            if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {                int c = getIntField(mHealthdConfig->batteryCurrentNowPath);                char b[20];                snprintf(b, sizeof(b), " c=%d", c / 1000);                strlcat(dmesgline, b, sizeof(dmesgline));            }        } else {            snprintf(dmesgline, sizeof(dmesgline),                 "battery none");        }        KLOG_WARNING(LOG_TAG, "%s chg=%s%s%s\n", dmesgline,                     props.chargerAcOnline ? "a" : "",                     props.chargerUsbOnline ? "u" : "",                     props.chargerWirelessOnline ? "w" : "");    }    healthd_mode_ops->battery_update(&props);//将数据传到上层的BatteryService    return props.chargerAcOnline | props.chargerUsbOnline |//返回当前是否属于充电            props.chargerWirelessOnline;}

接下来看看healthd_mode_ops->battery_update是怎么把数据传到上层的

void healthd_mode_android_battery_update(    struct android::BatteryProperties *props) {    if (gBatteryPropertiesRegistrar != NULL)        gBatteryPropertiesRegistrar->notifyListeners(*props);    return;}

上层会通过binder通信,注册一个回调到BatteryPropertiesRegistrar

void BatteryPropertiesRegistrar::registerListener(const sp<IBatteryPropertiesListener>& listener) {    {        if (listener == NULL)            return;        Mutex::Autolock _l(mRegistrationLock);        // check whether this is a duplicate        for (size_t i = 0; i < mListeners.size(); i++) {            if (mListeners[i]->asBinder() == listener->asBinder()) {                return;            }        }        mListeners.add(listener);        listener->asBinder()->linkToDeath(this);    }    healthd_battery_update();}

而update函数就是调用了notifyListeners遍历各个listener传到上层BatteryService

void BatteryPropertiesRegistrar::notifyListeners(struct BatteryProperties props) {    Mutex::Autolock _l(mRegistrationLock);    for (size_t i = 0; i < mListeners.size(); i++) {        mListeners[i]->batteryPropertiesChanged(props);    }}

再来看看BatteryService中,在onStart中通过ServiceManager,和batteryproperties这个Service通信,将BatteryListener这个listenter注册到batteryproperties中去

    @Override    public void onStart() {        IBinder b = ServiceManager.getService("batteryproperties");        final IBatteryPropertiesRegistrar batteryPropertiesRegistrar =                IBatteryPropertiesRegistrar.Stub.asInterface(b);        try {            batteryPropertiesRegistrar.registerListener(new BatteryListener());        } catch (RemoteException e) {            // Should never happen.        }        publishBinderService("battery", new BinderService());        publishLocalService(BatteryManagerInternal.class, new LocalService());    }

再来看看BatteryListener 的batteryPropertiesChanged接口,当下面调这个接口,就会调用BatteryService的update函数,然后就是BatteryService的一些主要流程就不分析了。

    private final class BatteryListener extends IBatteryPropertiesListener.Stub {        @Override        public void batteryPropertiesChanged(BatteryProperties props) {            final long identity = Binder.clearCallingIdentity();            try {                BatteryService.this.update(props);            } finally {                Binder.restoreCallingIdentity(identity);            }       }    }


BatteryService接受healthd的数据都是被动的,healthd穿过来的。有没有主动去healthd查询的。

在BatteryManager中就有主动去healthd查询的,代码如下

    private long queryProperty(int id) {        long ret;        if (mBatteryPropertiesRegistrar == null) {            IBinder b = ServiceManager.getService("batteryproperties");//获取batteryproperties Service            mBatteryPropertiesRegistrar =                IBatteryPropertiesRegistrar.Stub.asInterface(b);//接口转化下            if (mBatteryPropertiesRegistrar == null)                return Long.MIN_VALUE;        }        try {            BatteryProperty prop = new BatteryProperty();            if (mBatteryPropertiesRegistrar.getProperty(id, prop) == 0)//prop是输出                ret = prop.getLong();            else                ret = Long.MIN_VALUE;        } catch (RemoteException e) {            ret = Long.MIN_VALUE;        }        return ret;    }

再到healthd看看对应的接口

status_t BatteryPropertiesRegistrar::getProperty(int id, struct BatteryProperty *val) {    return healthd_get_property(id, val);}

status_t healthd_get_property(int id, struct BatteryProperty *val) {    return gBatteryMonitor->getProperty(id, val);}
java的BatteryProperty对象对应到这边是指针
status_t BatteryMonitor::getProperty(int id, struct BatteryProperty *val) {    status_t ret = BAD_VALUE;    val->valueInt64 = LONG_MIN;    switch(id) {    case BATTERY_PROP_CHARGE_COUNTER://根据不同ID,返回不同值        if (!mHealthdConfig->batteryChargeCounterPath.isEmpty()) {            val->valueInt64 =                getIntField(mHealthdConfig->batteryChargeCounterPath);            ret = NO_ERROR;        } else {            ret = NAME_NOT_FOUND;        }        break;    case BATTERY_PROP_CURRENT_NOW:        if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {            val->valueInt64 =                getIntField(mHealthdConfig->batteryCurrentNowPath);            ret = NO_ERROR;        } else {            ret = NAME_NOT_FOUND;        }        break;    case BATTERY_PROP_CURRENT_AVG:        if (!mHealthdConfig->batteryCurrentAvgPath.isEmpty()) {            val->valueInt64 =                getIntField(mHealthdConfig->batteryCurrentAvgPath);            ret = NO_ERROR;        } else {            ret = NAME_NOT_FOUND;        }        break;    case BATTERY_PROP_CAPACITY:        if (!mHealthdConfig->batteryCapacityPath.isEmpty()) {            val->valueInt64 =                getIntField(mHealthdConfig->batteryCapacityPath);            ret = NO_ERROR;        } else {            ret = NAME_NOT_FOUND;        }        break;    case BATTERY_PROP_ENERGY_COUNTER:        if (mHealthdConfig->energyCounter) {            ret = mHealthdConfig->energyCounter(&val->valueInt64);        } else {            ret = NAME_NOT_FOUND;        }        break;    default:        break;    }    return ret;}




1 0
原创粉丝点击