Android Healthd電池服務分析


healthd

healthd是安卓4.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電池系統框架

image

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: %c\n",
                           optopt);
                exit(1);
            }
        }
    }
 
    ret = healthd_init(); //healthed初始化
    if (ret) {
        KLOG_ERROR("Initialization failed, exiting\n");
        exit(2);
    }
 
    healthd_mainloop(); //主循環
    KLOG_ERROR("Main loop terminated, exiting\n");
    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=%d\n",
                   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 failed\n");
    }
 
    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 image\n");
        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 image\n");
        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 failed\n");
        return;
    }
	//將wakealarm事件注冊到wakealarm_fd文件節點上以監聽wakealarm事件。
    if (healthd_register_event(wakealarm_fd, wakealarm_event))
        KLOG_ERROR(LOG_TAG,
                   "Registration of wakealarm event failed\n");
    //設置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模式不再分析。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM