深入解析android5.1 healthd

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;
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

您可能感兴趣的文章:

  • Android实现侦听电池状态显示、电量及充电动态显示的方法
  • Android获取手机电池电量用法实例
  • Android编程之电池电量信息更新的方法(基于BatteryService实现)
  • Android查看电池电量的方法(基于BroadcastReceiver)
  • Android监听电池状态实例代码
  • Android编程实现对电池状态的监视功能示例
  • Android电池电量跳变
  • Android4.4开发之电池低电量告警提示原理与实现方法分析
  • Android电池电量监听的示例代码
  • Android实现电池管理系统
(0)

相关推荐

  • Android监听电池状态实例代码

    如果要监听电池的状态改变,需要动态注册:android.intent.action.BATTERY_CHANGED,收到Action后可以根据对应的Key获取你需要的信息,更详细信息可以参考以下例子中的BatteryChangedReceiver类 具体代码如下所示: package com.example.charginganimation; import android.app.Activity; import android.content.BroadcastReceiver; impor

  • Android实现电池管理系统

    一.Android 电池服务 Android电池服务,用来监听内核上报的电池事件,并将最新的电池数据上报给系统,系统收到新数据后会去更新电池显示状态.剩余电量等信息.如果收到过温报警和低电报警,系统会自动触发关机流程,保护电池和机器不受到危害. Android电池服务的启动和运行流程: Android 电池服务的源码结构 Framework\base\services\java\com\android\server         ├── SystemServer.java           

  • Android编程之电池电量信息更新的方法(基于BatteryService实现)

    本文实例讲述了Android编程之电池电量信息更新的方法.分享给大家供大家参考,具体如下: 电池的信息,电压,温度,充电状态等等,都是由BatteryService来提供的.BatteryService是跑在system_process当中,在系统初始化的时候启动,如下 在SystemServer.java中可以看到启动BatteryService的代码: Log.i(TAG, "Starting Battery Service."); BatteryService battery =

  • Android查看电池电量的方法(基于BroadcastReceiver)

    本文实例讲述了Android查看电池电量的方法.分享给大家供大家参考,具体如下: 程序如下: import android.app.Activity; import android.app.Dialog; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; impor

  • Android实现侦听电池状态显示、电量及充电动态显示的方法

    本文实例讲述了Android实现侦听电池状态显示.电量及充电动态显示的方法,是Android应用程序开发中非常常用的重要功能.分享给大家供大家参考之用.具体方法如下: 使用android系统的电池侦听和系统的电池图片如下: 引入源代码中的两个xml文件(这里我在android2.2的jar包中找不到,所以才引入,源代码路径:C:\android-sdk-windows\platforms\android-8\data\res\drawable),之后会发现stat_sys_battery.xml

  • Android电池电量监听的示例代码

    监听电池状态只需要接收Intent.ACTION_BATTERY_CHANGED的广播即可,当电池状态发生变化时会发出广播. 1.运行状态如下图: 1.充电中的状态 2.未充电时的状态 2.实现代码如下,各个状态通过名字就很容易知道意思,BatteryManager类中定义了电池状态. public class MainActivity extends Activity { private static final String TAG = "MainActivity"; privat

  • Android编程实现对电池状态的监视功能示例

    本文实例讲述了Android编程实现对电池状态的监视功能.分享给大家供大家参考,具体如下: 最近在开发一个与GPS相关的项目,因为其中涉及到了GPS的使用,众所周知,GPS是相当耗电的,因此就想着怎么能知道当前的电量,并且在电量达到一个下限的时候,及时提醒给用户,以根据情况关闭GPS,节省电量,以备电话急用,后来查资料,看API,终于找到了方法,怎么来监视电量,根据电量的变化来获取当前的电量多少,并且根据其它状态综合对手机进行管理,以达到管理最优的状态. 下面是代码: private Broad

  • Android4.4开发之电池低电量告警提示原理与实现方法分析

    本文实例讲述了Android4.4电池低电量告警提示原理与实现方法.分享给大家供大家参考,具体如下: 之前版本的电池电量低是通过发送 intent ACTION_BATTERY_LOW来实现的,而在android4.4中,通过发送intent ACTION_BATTERY_CHANGED,也就是电池电量只要变化就检查是否需要低电量告警,并且实现挪到了PowerUI中. 路径: frameworks/base/packages/SystemUI/src/com/android/systemui/p

  • Android电池电量跳变

    问题情形: 1.电量跳变到50% 2.电池ID脚接地 3.温度脚来判断电池是否在位 推测原因: 判断电池在位的方法: qpnp-linear-charger.c enum bpd_type{ BPD_TYPE_BAT_ID="bpd_id", BPD_TYPE_BAT_THM="bpd_thm", BPD_TYPE_BAT_THE_BAT_ID="bpd_thm_id", } 先在设备树查找bpd是否有值 of_property_read_str

  • Android获取手机电池电量用法实例

    本文实例讲述了Android获取手机电池电量用法.分享给大家供大家参考.具体如下: 原理概述: 手机电池电量的获取在应用程序的开发中也很常用,Android系统中手机电池电量发生变化的消息是通过Intent广播来实现的,常用的Intent的Action有  Intent.ACTION_BATTERY_CHANGED(电池电量发生改变时).Intent.ACTION_BATTERY_LOW(电池电量达到下限时).和Intent.ACTION_BATTERY_OKAY(电池电量从低恢复到高时). 当

随机推荐