Android Healthd電池服務分析

  • 2019 年 12 月 11 日
  • 筆記

healthd

healthd是Android4.4之後提出來的,監聽來自kernel的電池事件,並向上傳遞電池數據給framework層的BatteryService。BatteryService計算電池電量顯示,剩餘電量,電量級別以及繪製充電動畫等資訊,其程式碼位於/system/core/healthd。

android/system/core/healthd/  Android.mk          BatteryMonitor.h                BatteryPropertiesRegistrar.h  healthd.cpp  healthd_mode_android.cpp  images  BatteryMonitor.cpp  BatteryPropertiesRegistrar.cpp  healthd_board_default.cpp     healthd.h    healthd_mode_charger.cpp

下面一張圖清晰的表示了Android電池系統框架

healthd服務入口:android/system/core/healthd/healthd.cpp 中main函數。

int main(int argc, char **argv) {      int ch;      int ret;        klog_set_level(KLOG_LEVEL);          //healthd_mode_ops是一個關於充電狀態的結構體變數,      healthd_mode_ops = &android_ops;//開機充電時,指向android_ops        if (!strcmp(basename(argv[0]), "charger")) {          healthd_mode_ops = &charger_ops; //      } else {          while ((ch = getopt(argc, argv, "cr")) != -1) {              switch (ch) {              case 'c':                  healthd_mode_ops = &charger_ops; //關機狀態下的充電                  break;              case 'r':                  healthd_mode_ops = &recovery_ops;//recovery下的操作                  break;              case '?':              default:                  KLOG_ERROR(LOG_TAG, "Unrecognized healthd option: %cn",                             optopt);                  exit(1);              }          }      }        ret = healthd_init(); //healthed初始化      if (ret) {          KLOG_ERROR("Initialization failed, exitingn");          exit(2);      }        healthd_mainloop(); //主循環      KLOG_ERROR("Main loop terminated, exitingn");      return 3;  }

在main函數中,首先根據傳入的參數不同區分:開機充電、recovery、關機充電。這三種情況,然後指定不同的healthd_mode_ops回調函數。因此有必要貼出來這三個重要的回調。

///////////////////////////////////////////////////////////////////////////三個相關的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,  };    static struct healthd_mode_ops charger_ops = {             關機充電      .init = healthd_mode_charger_init,      .preparetowait = healthd_mode_charger_preparetowait,      .heartbeat = healthd_mode_charger_heartbeat,      .battery_update = healthd_mode_charger_battery_update,  };    static struct healthd_mode_ops recovery_ops = {            recover相關的      .init = healthd_mode_nop_init,      .preparetowait = healthd_mode_nop_preparetowait,      .heartbeat = healthd_mode_nop_heartbeat,      .battery_update = healthd_mode_nop_battery_update,  };

接著往下看healthd_init()

static int healthd_init() {      epollfd = epoll_create(MAX_EPOLL_EVENTS);//創建一個epoll變數      if (epollfd == -1) {          KLOG_ERROR(LOG_TAG,                     "epoll_create failed; errno=%dn",                     errno);          return -1;      }      //和板子級別的初始化,裡面其實是一個空函數,什麼也沒做      healthd_board_init(&healthd_config);      //根據系統所處的模式,有三種情況的init,開機充電,關機充電,recovery      healthd_mode_ops->init(&healthd_config);      //wakealarm定時器初始化      wakealarm_init();      //uevent事件初始化,用以監聽電池的uevent事件。      uevent_init();      //BatteryMonitor初始化。      gBatteryMonitor = new BatteryMonitor();//創建batteryMonitor對象      gBatteryMonitor->init(&healthd_config);//初始化batteryMonitor,打開/sys/class/power_supply,                                             //遍歷該節點下的電池參數初始化healthd的config參數      return 0;  }

healthd_mode_ops->init(&healthd_config);根據main函數中傳入的參數 有三種模式,Android,charger,recovery。

android模式

void healthd_mode_android_init(struct healthd_config* /*config*/) {      ProcessState::self()->setThreadPoolMaxThreadCount(0);//獲取執行緒池最大執行緒數      IPCThreadState::self()->disableBackgroundScheduling(true);//禁止後台調用      IPCThreadState::self()->setupPolling(&gBinderFd);//將gBinderFd加入到epoll中        if (gBinderFd >= 0) {          //將binder_event事件註冊到gBinderfd文件節點用以監聽Binder事件。          if (healthd_register_event(gBinderFd, binder_event))              KLOG_ERROR(LOG_TAG,                         "Register for binder events failedn");      }        gBatteryPropertiesRegistrar = new BatteryPropertiesRegistrar();      //將batteryProperties註冊到ServiceManager中      gBatteryPropertiesRegistrar->publish();  }

charger模式就是關機充電模式,Android層只跑一個healthd服務用來顯示充電動畫和電量百分比。

charger模式    void healthd_mode_charger_init(struct healthd_config* config) //做充電動畫相關的設置  {      int ret;      struct charger *charger = &charger_state;      int i;      int epollfd;        dump_last_kmsg();        LOGW("--------------- STARTING CHARGER MODE ---------------n");        ret = ev_init(input_callback, charger);      if (!ret) {          epollfd = ev_get_epollfd();          healthd_register_event(epollfd, charger_event_handler);      }        ret = res_create_display_surface("charger/battery_fail", &charger->surf_unknown);      if (ret < 0) {          LOGE("Cannot load battery_fail imagen");          charger->surf_unknown = NULL;      }        charger->batt_anim = &battery_animation; //指定充電動畫相關的屬性        gr_surface* scale_frames;      int scale_count;      ret = res_create_multi_display_surface("charger/battery_scale", &scale_count, &scale_frames);//讀取充電動畫資源      if (ret < 0) {          LOGE("Cannot load battery_scale imagen");          charger->batt_anim->num_frames = 0;          charger->batt_anim->num_cycles = 1;      } else if (scale_count != charger->batt_anim->num_frames) {          LOGE("battery_scale image has unexpected frame count (%d, expected %d)n",               scale_count, charger->batt_anim->num_frames);          charger->batt_anim->num_frames = 0;          charger->batt_anim->num_cycles = 1;      } else {          for (i = 0; i < charger->batt_anim->num_frames; i++) {  //讀取資源成功,存放起來              charger->batt_anim->frames[i].surface = scale_frames[i];          }      }        ev_sync_key_state(set_key_callback, charger);        charger->next_screen_transition = -1;      charger->next_key_check = -1;      charger->next_pwr_check = -1;      healthd_config = config;  }
//接著到wakealarm_init  static void wakealarm_init(void) {      //創建一個月wakealarm對應的定時器描述符      wakealarm_fd = timerfd_create(CLOCK_BOOTTIME_ALARM, TFD_NONBLOCK);      if (wakealarm_fd == -1) {          KLOG_ERROR(LOG_TAG, "wakealarm_init: timerfd_create failedn");          return;      }      //將wakealarm事件註冊到wakealarm_fd文件節點上以監聽wakealarm事件。      if (healthd_register_event(wakealarm_fd, wakealarm_event))          KLOG_ERROR(LOG_TAG,                     "Registration of wakealarm event failedn");      //設置alarm喚醒間隔      wakealarm_set_interval(healthd_config.periodic_chores_interval_fast);  }

如果是關機充電模式,則healthd_mode_ops->heartbeat(); 執行的是healthd_mode_charger_heartbeat()函數

void healthd_mode_charger_heartbeat()  {      struct charger *charger = &charger_state;      int64_t now = curr_time_ms();      int ret;        handle_input_state(charger, now);      //處理按鍵相關的事情,長按開機      handle_power_supply_state(charger, now);        /* do screen update last in case any of the above want to start       * screen transitions (animations, etc)       */      update_screen_state(charger, now); //繪製充電動畫  }
frameworks/base/services/core/java/com/android/server/BatteryService.java  //將電池監聽註冊到底層  public void onStart() {      IBinder b = ServiceManager.getService("batteryproperties");      final IBatteryPropertiesRegistrar batteryPropertiesRegistrar =              IBatteryPropertiesRegistrar.Stub.asInterface(b);      try {          //註冊電池監聽,當底層電池電量發生變化調用此監聽,並調用update。          batteryPropertiesRegistrar.registerListener(new BatteryListener());      } catch (RemoteException e) {          // Should never happen.      }        publishBinderService("battery", new BinderService());      publishLocalService(BatteryManagerInternal.class, new LocalService());  }  //當底層有資訊時,會調用update更新BatteryService中相關值。      private void update(BatteryProperties props) {          synchronized (mLock) {              if (!mUpdatesStopped) {                  mBatteryProps = props;                  // Process the new values.                  processValuesLocked(false);              } else {                  mLastBatteryProps.set(props);              }          }      }
private void processValuesLocked(boolean force) {          boolean logOutlier = false;          long dischargeDuration = 0;          //獲取電池電量是否低於critical界限。          mBatteryLevelCritical = (mBatteryProps.batteryLevel <= mCriticalBatteryLevel);          //獲取電池充電狀態,AC,USB,無線,以及什麼都沒接。          if (mBatteryProps.chargerAcOnline) {              mPlugType = BatteryManager.BATTERY_PLUGGED_AC;          } else if (mBatteryProps.chargerUsbOnline) {              mPlugType = BatteryManager.BATTERY_PLUGGED_USB;          } else if (mBatteryProps.chargerWirelessOnline) {              mPlugType = BatteryManager.BATTERY_PLUGGED_WIRELESS;          } else {              mPlugType = BATTERY_PLUGGED_NONE;          }            if (DEBUG) {              Slog.d(TAG, "Processing new values: "                      + "chargerAcOnline=" + mBatteryProps.chargerAcOnline                      + ", chargerUsbOnline=" + mBatteryProps.chargerUsbOnline                      + ", chargerWirelessOnline=" + mBatteryProps.chargerWirelessOnline                      + ", batteryStatus=" + mBatteryProps.batteryStatus                      + ", batteryHealth=" + mBatteryProps.batteryHealth                      + ", batteryPresent=" + mBatteryProps.batteryPresent                      + ", batteryLevel=" + mBatteryProps.batteryLevel                      + ", batteryTechnology=" + mBatteryProps.batteryTechnology                      + ", batteryVoltage=" + mBatteryProps.batteryVoltage                      + ", batteryTemperature=" + mBatteryProps.batteryTemperature                      + ", mBatteryLevelCritical=" + mBatteryLevelCritical                      + ", mPlugType=" + mPlugType);          }            // Let the battery stats keep track of the current level.          try {              mBatteryStats.setBatteryState(mBatteryProps.batteryStatus, mBatteryProps.batteryHealth,                      mPlugType, mBatteryProps.batteryLevel, mBatteryProps.batteryTemperature,                      mBatteryProps.batteryVoltage);          } catch (RemoteException e) {              // Should never happen.          }          //低電關機          shutdownIfNoPowerLocked();          //電池溫度過高關機          shutdownIfOverTempLocked();            if (force || (mBatteryProps.batteryStatus != mLastBatteryStatus ||                  mBatteryProps.batteryHealth != mLastBatteryHealth ||                  mBatteryProps.batteryPresent != mLastBatteryPresent ||                  mBatteryProps.batteryLevel != mLastBatteryLevel ||                  mPlugType != mLastPlugType ||                  mBatteryProps.batteryVoltage != mLastBatteryVoltage ||                  mBatteryProps.batteryTemperature != mLastBatteryTemperature ||                  mInvalidCharger != mLastInvalidCharger)) {              //適配器插入狀態有更改              if (mPlugType != mLastPlugType) {                  if (mLastPlugType == BATTERY_PLUGGED_NONE) {                      // discharging -> charging                        // There's no value in this data unless we've discharged at least once and the                      // battery level has changed; so don't log until it does.                      if (mDischargeStartTime != 0 && mDischargeStartLevel != mBatteryProps.batteryLevel) {                          dischargeDuration = SystemClock.elapsedRealtime() - mDischargeStartTime;                          logOutlier = true;                          EventLog.writeEvent(EventLogTags.BATTERY_DISCHARGE, dischargeDuration,                                  mDischargeStartLevel, mBatteryProps.batteryLevel);                          // make sure we see a discharge event before logging again                          mDischargeStartTime = 0;                      }                  } else if (mPlugType == BATTERY_PLUGGED_NONE) {                      // charging -> discharging or we just powered up                      mDischargeStartTime = SystemClock.elapsedRealtime();                      mDischargeStartLevel = mBatteryProps.batteryLevel;                  }              }              //電池狀態更新              if (mBatteryProps.batteryStatus != mLastBatteryStatus ||                      mBatteryProps.batteryHealth != mLastBatteryHealth ||                      mBatteryProps.batteryPresent != mLastBatteryPresent ||                      mPlugType != mLastPlugType) {                  EventLog.writeEvent(EventLogTags.BATTERY_STATUS,                          mBatteryProps.batteryStatus, mBatteryProps.batteryHealth, mBatteryProps.batteryPresent ? 1 : 0,                          mPlugType, mBatteryProps.batteryTechnology);              }              if (mBatteryProps.batteryLevel != mLastBatteryLevel) {                  // Don't do this just from voltage or temperature changes, that is                  // too noisy.                  EventLog.writeEvent(EventLogTags.BATTERY_LEVEL,                          mBatteryProps.batteryLevel, mBatteryProps.batteryVoltage, mBatteryProps.batteryTemperature);              }              if (mBatteryLevelCritical && !mLastBatteryLevelCritical &&                      mPlugType == BATTERY_PLUGGED_NONE) {                  // We want to make sure we log discharge cycle outliers                  // if the battery is about to die.                  dischargeDuration = SystemClock.elapsedRealtime() - mDischargeStartTime;                  logOutlier = true;              }                if (!mBatteryLevelLow) {                  // Should we now switch in to low battery mode?                  if (mPlugType == BATTERY_PLUGGED_NONE                          && mBatteryProps.batteryLevel <= mLowBatteryWarningLevel) {                      mBatteryLevelLow = true;                  }              } else {                  // Should we now switch out of low battery mode?                  if (mPlugType != BATTERY_PLUGGED_NONE) {                      mBatteryLevelLow = false;                  } else if (mBatteryProps.batteryLevel >= mLowBatteryCloseWarningLevel)  {                      mBatteryLevelLow = false;                  } else if (force && mBatteryProps.batteryLevel >= mLowBatteryWarningLevel) {                      // If being forced, the previous state doesn't matter, we will just                      // absolutely check to see if we are now above the warning level.                      mBatteryLevelLow = false;                  }              }              //發送電池狀態變換廣播              sendIntentLocked();                // Separate broadcast is sent for power connected / not connected              // since the standard intent will not wake any applications and some              // applications may want to have smart behavior based on this.              if (mPlugType != 0 && mLastPlugType == 0) {                  mHandler.post(new Runnable() {                      @Override                      public void run() {                          Intent statusIntent = new Intent(Intent.ACTION_POWER_CONNECTED);                          statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);                          mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);                      }                  });              }              else if (mPlugType == 0 && mLastPlugType != 0) {                  mHandler.post(new Runnable() {                      @Override                      public void run() {                          Intent statusIntent = new Intent(Intent.ACTION_POWER_DISCONNECTED);                          statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);                          mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);                      }                  });              }              //低電量電池事件通知              if (shouldSendBatteryLowLocked()) {                  mSentLowBatteryBroadcast = true;                  mHandler.post(new Runnable() {                      @Override                      public void run() {                          Intent statusIntent = new Intent(Intent.ACTION_BATTERY_LOW);                          statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);                          mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);                      }                  });              } else if (mSentLowBatteryBroadcast && mLastBatteryLevel >= mLowBatteryCloseWarningLevel) {                  mSentLowBatteryBroadcast = false;                  mHandler.post(new Runnable() {                      @Override                      public void run() {                          Intent statusIntent = new Intent(Intent.ACTION_BATTERY_OKAY);                          statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);                          mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);                      }                  });              }                // Update the battery LED              mLed.updateLightsLocked();                // This needs to be done after sendIntent() so that we get the lastest battery stats.              if (logOutlier && dischargeDuration != 0) {                  logOutlierLocked(dischargeDuration);              }                mLastBatteryStatus = mBatteryProps.batteryStatus;              mLastBatteryHealth = mBatteryProps.batteryHealth;              mLastBatteryPresent = mBatteryProps.batteryPresent;              mLastBatteryLevel = mBatteryProps.batteryLevel;              mLastPlugType = mPlugType;              mLastBatteryVoltage = mBatteryProps.batteryVoltage;              mLastBatteryTemperature = mBatteryProps.batteryTemperature;              mLastBatteryLevelCritical = mBatteryLevelCritical;              mLastInvalidCharger = mInvalidCharger;          }      }

recovery模式不再分析。