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线,在锁屏状态下。需要充两格电或者以上,才会有剩余时间的显示。