android5.1手机在充电的时候,并且在锁屏界面的时候会显示还剩多少时间电池充满电。我们就这个机制进行下深入分析:
首先对电池的变化都会监听BatteryService发出的Intent.ACTION_BATTERY_CHANGED广播,因此在framework目录下全局搜索,结果发现在./base/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java这个目录下,也就是keyguard中有对这个广播的监控
在KeyguardUpdateMonitor.java这个文件中
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (DEBUG) Log.d(TAG, "received broadcast " + action);
if (Intent.ACTION_TIME_TICK.equals(action)
|| Intent.ACTION_TIME_CHANGED.equals(action)
|| Intent.ACTION_TIMEZONE_CHANGED.equals(action)) {
mHandler.sendEmptyMessage(MSG_TIME_UPDATE);
} else if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {//监听电池变化的广播
final int status = intent.getIntExtra(EXTRA_STATUS, BATTERY_STATUS_UNKNOWN);
final int plugged = intent.getIntExtra(EXTRA_PLUGGED, 0);
final int level = intent.getIntExtra(EXTRA_LEVEL, 0);
final int health = intent.getIntExtra(EXTRA_HEALTH, BATTERY_HEALTH_UNKNOWN);
final Message msg = mHandler.obtainMessage(
MSG_BATTERY_UPDATE, new BatteryStatus(status, level, plugged, health));
mHandler.sendMessage(msg);//发消息
}
接下来我们搜索下MSG_BATTERY_UPDATE这个消息,
private void handleBatteryUpdate(BatteryStatus status) {
if (DEBUG) Log.d(TAG, "handleBatteryUpdate");
final boolean batteryUpdateInteresting = isBatteryUpdateInteresting(mBatteryStatus, status);
mBatteryStatus = status;
if (batteryUpdateInteresting) {
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
cb.onRefreshBatteryInfo(status);//接下来我们就搜一下谁定义了onRefreshBatteryInfo这个接口
}
}
}
}
结果在KeyguardIndicationController.java这个文件中
KeyguardUpdateMonitorCallback mUpdateMonitor = new KeyguardUpdateMonitorCallback() {
@Override
public void onRefreshBatteryInfo(KeyguardUpdateMonitor.BatteryStatus status) {
boolean isChargingOrFull = status.status == BatteryManager.BATTERY_STATUS_CHARGING
|| status.status == BatteryManager.BATTERY_STATUS_FULL;
mPowerPluggedIn = status.isPluggedIn() && isChargingOrFull;
mPowerCharged = status.isCharged();
updateIndication();
}
};
接下来看下updateIndication
private void updateIndication() {
if (mVisible) {
mTextView.switchIndication(computeIndication());
}
}
接下来就是看下如何计算电池剩余时间的
private String computeIndication() {
if (!TextUtils.isEmpty(mTransientIndication)) {
return mTransientIndication;
}
if (mPowerPluggedIn) {//当在充电时
return computePowerIndication();
}
return mRestingIndication;
}
private String computePowerIndication() {
if (mPowerCharged) {
return mContext.getResources().getString(R.string.keyguard_charged);
}
// Try fetching charging time from battery stats.
try {//剩余时间通过BatteryStatsService获取
long chargingTimeRemaining = mBatteryInfo.computeChargeTimeRemaining();
if (chargingTimeRemaining > 0) {
String chargingTimeFormatted = Formatter.formatShortElapsedTimeRoundingUpToMinutes(
mContext, chargingTimeRemaining);
return mContext.getResources().getString(
R.string.keyguard_indication_charging_time, chargingTimeFormatted);
}
} catch (RemoteException e) {
Log.e(TAG, "Error calling IBatteryStats: ", e);
}
// Fall back to simple charging label.
return mContext.getResources().getString(R.string.keyguard_plugged_in);
}
下面是mBatteryInfo的赋值
mBatteryInfo = IBatteryStats.Stub.asInterface(
ServiceManager.getService(BatteryStats.SERVICE_NAME));
然后看BatteryStatsService中的computeChargeTimeRemaining代码
public long computeChargeTimeRemaining() {
synchronized (mStats) {
long time = mStats.computeChargeTimeRemaining(SystemClock.elapsedRealtime());
return time >= 0 ? (time/1000) : time;
}
}
其中mStats是在BatteryStatsService构造的时候新建的:
BatteryStatsService(File systemDir, Handler handler) {
mStats = new BatteryStatsImpl(systemDir, handler);
}
最后我们就来分析下BatteryStatsImpl中的computeChargeTimeRemaining函数:
@Override
public long computeChargeTimeRemaining(long curTime) {
if (mOnBattery) {//当处于用电池的状态直接退出
// Not yet working.
Slog.e(TAG, "mOnBattery");
return -1;
}
/* Broken
int curLevel = mCurrentBatteryLevel;
int plugLevel = mDischargePlugLevel;
if (plugLevel < 0 || curLevel < (plugLevel+1)) {
return -1;
}
long duration = computeBatteryRealtime(curTime, STATS_SINCE_UNPLUGGED);
if (duration < 1000*1000) {
return -1;
}
long usPerLevel = duration/(curLevel-plugLevel);
return usPerLevel * (100-curLevel);
*/
if (mNumChargeStepDurations < 1) {
Slog.e(TAG, "mNumChargeStepDurations");
return -1;
}//mChargeStepDurations是一个数组,保存着每一个level对应的时间,而mNumChargeStepDurations是现在总的一个level
long msPerLevel = computeTimePerLevel(mChargeStepDurations, mNumChargeStepDurations);
if (msPerLevel <= 0) {
Slog.e(TAG, "msPerLevel");
return -1;
}
Slog.e(TAG, "return time remianing" + (msPerLevel * (100-mCurrentBatteryLevel)) * 1000);
return (msPerLevel * (100-mCurrentBatteryLevel)) * 1000;//因此msperlevel代表每一个level需要多少时间,100-mCurrentBatteryLevel代表需要充电的电量
}
再来看看
private long computeTimePerLevel(long[] steps, int numSteps) {
// For now we'll do a simple average across all steps.
if (numSteps <= 0) {
return -1;
}
long total = 0;
for (int i=0; i<numSteps; i++) {
total += steps[i] & STEP_LEVEL_TIME_MASK;//高位保存的别的信息,需要将它去除
}
return total / numSteps;//所有的level的时间和除以总的level,就是每个level的平均时间
但是现在的关键mChargeStepDurations,和mNumChargeStepDurations这两个成员变量如何获得。
当在BatteryService更新电池信息的时候,如下:会调用BatteryStatsService的setBatteryState函数
try {
mBatteryStats.setBatteryState(mBatteryProps.batteryStatus, mBatteryProps.batteryHealth,
mPlugType, mBatteryProps.batteryLevel, mBatteryProps.batteryTemperature,
mBatteryProps.batteryVoltage);
} catch (RemoteException e) {
// Should never happen.
}
而在BatteryStatsService的setBatteryState函数中:检查下权限然后调用了BatteryStatsImpl的setBatteryState函数
public void setBatteryState(int status, int health, int plugType, int level,
int temp, int volt) {
enforceCallingPermission();
mStats.setBatteryState(status, health, plugType, level, temp, volt);
}
接下来我们来看下核心函数:
public void setBatteryState(int status, int health, int plugType, int level,
int temp, int volt) {
synchronized(this) {
final boolean onBattery = plugType == BATTERY_PLUGGED_NONE;
final long uptime = SystemClock.uptimeMillis();
final long elapsedRealtime = SystemClock.elapsedRealtime();
int oldStatus = mHistoryCur.batteryStatus;
if (!mHaveBatteryLevel) {
mHaveBatteryLevel = true;
// We start out assuming that the device is plugged in (not
// on battery). If our first report is now that we are indeed
// plugged in, then twiddle our state to correctly reflect that
// since we won't be going through the full setOnBattery().
if (onBattery == mOnBattery) {
if (onBattery) {
mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
} else {
mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
}
}
oldStatus = status;
}
if (onBattery) {
mDischargeCurrentLevel = level;
if (!mRecordingHistory) {
mRecordingHistory = true;
startRecordingHistory(elapsedRealtime, uptime, true);
}
} else if (level < 96) {
if (!mRecordingHistory) {
mRecordingHistory = true;
startRecordingHistory(elapsedRealtime, uptime, true);
}
}
mCurrentBatteryLevel = level;
if (mDischargePlugLevel < 0) {
mDischargePlugLevel = level;
}
if (onBattery != mOnBattery) {
mHistoryCur.batteryLevel = (byte)level;
mHistoryCur.batteryStatus = (byte)status;
mHistoryCur.batteryHealth = (byte)health;
mHistoryCur.batteryPlugType = (byte)plugType;
mHistoryCur.batteryTemperature = (short)temp;
mHistoryCur.batteryVoltage = (char)volt;
setOnBatteryLocked(elapsedRealtime, uptime, onBattery, oldStatus, level);
} else {
boolean changed = false;
if (mHistoryCur.batteryLevel != level) {
mHistoryCur.batteryLevel = (byte)level;
changed = true;
}
if (mHistoryCur.batteryStatus != status) {
mHistoryCur.batteryStatus = (byte)status;
changed = true;
}
if (mHistoryCur.batteryHealth != health) {
mHistoryCur.batteryHealth = (byte)health;
changed = true;
}
if (mHistoryCur.batteryPlugType != plugType) {
mHistoryCur.batteryPlugType = (byte)plugType;
changed = true;
}
if (temp >= (mHistoryCur.batteryTemperature+10)
|| temp <= (mHistoryCur.batteryTemperature-10)) {
mHistoryCur.batteryTemperature = (short)temp;
changed = true;
}
if (volt > (mHistoryCur.batteryVoltage+20)
|| volt < (mHistoryCur.batteryVoltage-20)) {
mHistoryCur.batteryVoltage = (char)volt;
changed = true;
}
if (changed) {
addHistoryRecordLocked(elapsedRealtime, uptime);
}
long modeBits = (((long)mInitStepMode) << STEP_LEVEL_INITIAL_MODE_SHIFT)
| (((long)mModStepMode) << STEP_LEVEL_MODIFIED_MODE_SHIFT)
| (((long)(level&0xff)) << STEP_LEVEL_LEVEL_SHIFT);//主要在高位存储一些模式与我们的关系不大
if (onBattery) {
if (mLastDischargeStepLevel != level && mMinDischargeStepLevel > level) {
mNumDischargeStepDurations = addLevelSteps(mDischargeStepDurations,
mNumDischargeStepDurations, mLastDischargeStepTime,
mLastDischargeStepLevel - level, modeBits, elapsedRealtime);
mLastDischargeStepLevel = level;
mMinDischargeStepLevel = level;
mLastDischargeStepTime = elapsedRealtime;
mInitStepMode = mCurStepMode;
mModStepMode = 0;
}
} else {
if (mLastChargeStepLevel != level && mMaxChargeStepLevel < level) {
mNumChargeStepDurations = addLevelSteps(mChargeStepDurations,
mNumChargeStepDurations, mLastChargeStepTime,
level - mLastChargeStepLevel, modeBits, elapsedRealtime);
mLastChargeStepLevel = level;
mMaxChargeStepLevel = level;
mLastChargeStepTime = elapsedRealtime;//将mLastChargeStepTime 赋成当前时间值
mInitStepMode = mCurStepMode;
mModStepMode = 0;
}
}
}
if (!onBattery && status == BatteryManager.BATTERY_STATUS_FULL) {
// We don't record history while we are plugged in and fully charged.
// The next time we are unplugged, history will be cleared.
mRecordingHistory = DEBUG;
}
}
}
再对应下面的addLevelSteps函数,入参numStepLevels是level-mLastChargeStepLevel也就是代表这侧充了多少电,
private static int addLevelSteps(long[] steps, int stepCount, long lastStepTime,
int numStepLevels, long modeBits, long elapsedRealtime) {
if (lastStepTime >= 0 && numStepLevels > 0) {
long duration = elapsedRealtime - lastStepTime;//这次充电用了多少时间
for (int i=0; i<numStepLevels; i++) {将计算每个电池level的消耗的时间
System.arraycopy(steps, 0, steps, 1, steps.length-1);//这个函数的意思是将数组steps从位置0,长度steps.length-1,复制到位置1
long thisDuration = duration / (numStepLevels-i);
duration -= thisDuration;
if (thisDuration > STEP_LEVEL_TIME_MASK) {
thisDuration = STEP_LEVEL_TIME_MASK;
}
steps[0] = thisDuration | modeBits;//这个是将一些模式信息存在高位,与我们不是很相关
}
stepCount += numStepLevels;
if (stepCount > steps.length) {
stepCount = steps.length;
}
}
return stepCount;
}
有可能比较难理解,我们直接举个例子
比如我们充了5格电,用了30s,当i=0,thisDuration = 30 / 5 = 6,step[0] = 6;当 i =1,thisDuration = 24 / (5 -1) = 6;然后将整个数组往后延,这样每次保存的值都会往后延。
最前面是最新的电池充电时间,mNumChargeStepDurations是所有的level,哪怕再次调用这个函数,数组还是往后延,该保存的值都保存了。
因此计算每格电池的平均充电时间,每格电池所花的时间之和除以就是所有的level即mNumChargeStepDurations。就是平均每格电池的充电时间。
至此BatteryStatsImpl中计算充电电池还剩多少时间我们已经分析完了。
接下来我们再来看下"batterystats.bin"这个文件
先来看它的读取:会在readSummaryFromParcel函数中,将成员变量都读出来。
public void readLocked() {
if (mFile == null) {
Slog.w("BatteryStats", "readLocked: no file associated with this instance");
return;
}
mUidStats.clear();
try {
File file = mFile.chooseForRead();
if (!file.exists()) {
return;
}
FileInputStream stream = new FileInputStream(file);
byte[] raw = BatteryStatsHelper.readFully(stream);
Parcel in = Parcel.obtain();
in.unmarshall(raw, 0, raw.length);
in.setDataPosition(0);
stream.close();
readSummaryFromParcel(in);
} catch(Exception e) {
Slog.e("BatteryStats", "Error reading battery statistics", e);
}
readSummaryFromParcel函数,从"batterystats.bin"这个文件读取各个成员变量。
public void readSummaryFromParcel(Parcel in) {
final int version = in.readInt();
if (version != VERSION) {
Slog.w("BatteryStats", "readFromParcel: version got " + version
+ ", expected " + VERSION + "; erasing old stats");
return;
}
readHistory(in, true);
mStartCount = in.readInt();
mUptime = in.readLong();
mRealtime = in.readLong();
mStartClockTime = in.readLong();
mStartPlatformVersion = in.readString();
mEndPlatformVersion = in.readString();
mOnBatteryTimeBase.readSummaryFromParcel(in);
mOnBatteryScreenOffTimeBase.readSummaryFromParcel(in);
mDischargeUnplugLevel = in.readInt();
mDischargePlugLevel = in.readInt();
mDischargeCurrentLevel = in.readInt();
mCurrentBatteryLevel = in.readInt();
mLowDischargeAmountSinceCharge = in.readInt();
mHighDischargeAmountSinceCharge = in.readInt();
mDischargeAmountScreenOnSinceCharge = in.readInt();
mDischargeAmountScreenOffSinceCharge = in.readInt();
mNumDischargeStepDurations = in.readInt();
in.readLongArray(mDischargeStepDurations);
mNumChargeStepDurations = in.readInt();
然后还有两个写的函数,一个同步一个异步
public void writeAsyncLocked() {
writeLocked(false);
}
public void writeSyncLocked() {
writeLocked(true);
}
void writeLocked(boolean sync) {
if (mFile == null) {
Slog.w("BatteryStats", "writeLocked: no file associated with this instance");
return;
}
if (mShuttingDown) {
return;
}
Parcel out = Parcel.obtain();
writeSummaryToParcel(out, true);
mLastWriteTime = SystemClock.elapsedRealtime();
if (mPendingWrite != null) {
mPendingWrite.recycle();
}
mPendingWrite = out;
if (sync) {
commitPendingDataToDisk();
} else {
BackgroundThread.getHandler().post(new Runnable() {
@Override public void run() {
commitPendingDataToDisk();
}
});
}
}
在ActivityManagerService中新建BatteryStatsService的时候,会去调用BatteryStatsImpl的readLocked,读取"batterystats.bin"的值,来初始化自己的成员变量。
mBatteryStatsService = new BatteryStatsService(systemDir, mHandler);
mBatteryStatsService.getActiveStatistics().readLocked();
mBatteryStatsService.getActiveStatistics().writeAsyncLocked();
比如在关机的时候进行写,但这时候是同步的。
我们怎么理解新建BatteryStatsService的时候,会去调用BatteryStatsImpl的readLocked,读取"batterystats.bin"的值,来初始化自己的成员变量。
比如说充电,一开机,之前的充电的每格电池的充电时间都没有,通过从"batterystats.bin"文件中读取,就可以将上次开机的状态知道了。
其实仔细看代码,知道插入usb充电时,由于mOnBattery 改变了会调用setOnBatteryLocked函数,而这时候将mLastChargeStepTime = -1;mNumChargeStepDurations = 0;
void setOnBatteryLocked(final long mSecRealtime, final long mSecUptime, final boolean onBattery,
final int oldStatus, final int level) {
boolean doWrite = false;
Message m = mHandler.obtainMessage(MSG_REPORT_POWER_CHANGE);
m.arg1 = onBattery ? 1 : 0;
mHandler.sendMessage(m);
final long uptime = mSecUptime * 1000;
final long realtime = mSecRealtime * 1000;
final boolean screenOn = mScreenState == Display.STATE_ON;
if (onBattery) {
...........
} else {
Slog.e("kangchen", "setOnBatteryLocked mNumChargeStepDurations = 0;");
mOnBattery = mOnBatteryInternal = onBattery;
pullPendingStateUpdatesLocked();
mHistoryCur.batteryLevel = (byte)level;
mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Battery plugged to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(mSecRealtime, mSecUptime);
mDischargeCurrentLevel = mDischargePlugLevel = level;
if (level < mDischargeUnplugLevel) {
mLowDischargeAmountSinceCharge += mDischargeUnplugLevel-level-1;
mHighDischargeAmountSinceCharge += mDischargeUnplugLevel-level;
}
updateDischargeScreenLevelsLocked(screenOn, screenOn);
updateTimeBasesLocked(false, !screenOn, uptime, realtime);
mNumChargeStepDurations = 0;
mLastChargeStepLevel = level;
mMaxChargeStepLevel = level;
mLastChargeStepTime = -1;
mInitStepMode = mCurStepMode;
mModStepMode = 0;
}
.............
下次BatteryService再次调用BatterStatsImpl的setBatteryState的时候,首先先要电量充了一格电才能进这个分支,但是由于这时候mLastChargeStepTime 还是-1,所以进addLevelSteps函数,直接返回,mNumChargeStepDurations 还是为0 。所以需要再充一格电才能进去,并且mNumChargeStepDurations 不为0
} else {
if (mLastChargeStepLevel != level && mMaxChargeStepLevel < level) {
mNumChargeStepDurations = addLevelSteps(mChargeStepDurations,
mNumChargeStepDurations, mLastChargeStepTime,
level - mLastChargeStepLevel, modeBits, elapsedRealtime);
mLastChargeStepLevel = level;
mMaxChargeStepLevel = level;
mLastChargeStepTime = elapsedRealtime;
mInitStepMode = mCurStepMode;
mModStepMode = 0;
}
}
private static int addLevelSteps(long[] steps, int stepCount, long lastStepTime,
int numStepLevels, long modeBits, long elapsedRealtime) {
if (lastStepTime >= 0 && numStepLevels > 0) {//lastStepTime为0 if进不去
long duration = elapsedRealtime - lastStepTime;
for (int i=0; i<numStepLevels; i++) {
System.arraycopy(steps, 0, steps, 1, steps.length-1);
long thisDuration = duration / (numStepLevels-i);
duration -= thisDuration;
if (thisDuration > STEP_LEVEL_TIME_MASK) {
thisDuration = STEP_LEVEL_TIME_MASK;
}
steps[0] = thisDuration | modeBits;
}
stepCount += numStepLevels;
if (stepCount > steps.length) {
stepCount = steps.length;
}
}
return stepCount;
}
而且只有当mNumChargeStepDurations 大于0的时候,computeChargeTimeRemaining计算才会有正常返回值。
public long computeChargeTimeRemaining(long curTime) {
if (mOnBattery) {
// Not yet working.
return -1;
}
/* Broken
int curLevel = mCurrentBatteryLevel;
int plugLevel = mDischargePlugLevel;
if (plugLevel < 0 || curLevel < (plugLevel+1)) {
return -1;
}
long duration = computeBatteryRealtime(curTime, STATS_SINCE_UNPLUGGED);
if (duration < 1000*1000) {
return -1;
}
long usPerLevel = duration/(curLevel-plugLevel);
return usPerLevel * (100-curLevel);
*/
if (mNumChargeStepDurations < 1) {
return -1;
}
long msPerLevel = computeTimePerLevel(mChargeStepDurations, mNumChargeStepDurations);
if (msPerLevel <= 0) {
return -1;
}
return (msPerLevel * (100-mCurrentBatteryLevel)) * 1000;
}
因此插上usb线,在锁屏状态下。需要充两格电或者以上,才会有剩余时间的显示。