国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

深入解析android5.1 healthd

2019-10-22 18:17: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; } 

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VEVB武林網。


注:相關教程知識閱讀請移步到Android開發頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 德清县| 云阳县| 永胜县| 玉环县| 台东市| 惠东县| 临沭县| 平塘县| 修水县| 仁寿县| 大丰市| 延长县| 牙克石市| 沙湾县| 龙川县| 东明县| 政和县| 南川市| 岱山县| 石景山区| 抚顺县| 当雄县| 高唐县| 蒙阴县| 邢台县| 云林县| 攀枝花市| 大关县| 屯昌县| 什邡市| 武川县| 扶风县| 东兰县| 西宁市| 台中市| 苍梧县| 宿迁市| 台中县| 名山县| 梅河口市| 城口县|