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模式不再分析。