Settings中电池选项-Android13

Settings中电池选项-Android13

  • 1、设置中界面
  • 2、电池计算
    • 2.1 充电时间计算
      • 2.1.1 BatteryUsageStats获取
      • 2.1.2 BatteryStatsImpl计算
    • 2.2 电池剩余使用时间
      • 2.2.1 Estimate获取
      • 2.2.2 BatteryStatsImpl计算
  • 3、电池信息来源
    • 4、命令模拟
    • * 日志

[电池]Android 9.0 电池未充电与充电字符串提示信息[通俗易懂]


1、设置中界面

packages/apps/Settings/src/com/android/settings/fuelgauge/PowerUsageSummary.java
packages/apps/Settings/res/xml/power_usage_summary.xml
packages/apps/Settings/src/com/android/settings/fuelgauge/BatteryUtils.java
packages/apps/Settings/src/com/android/settings/fuelgauge/BatteryInfo.java

在这里插入图片描述

12-23 13:13:23.184   602   715 I ActivityTaskManager: START u0 {act=android.intent.action.MAIN cmp=com.android.settings/.SubSettings (has extras)} from uid 1000
12-23 13:13:23.285   994  2135 D BatteryTipLoader: BatteryInfoLoader post query: 5ms
12-23 13:13:23.356   994  2135 D BatteryInfo: time for getBatteryInfo: 1ms
12-23 13:13:23.357   994  2135 D BatteryTipLoader: BatteryInfoLoader.loadInBackground: 82ms
12-23 13:13:23.950   994   994 D SettingsActivity: Switching to fragment com.android.settings.fuelgauge.batteryusage.PowerUsageSummary

2、电池计算

packages/apps/Settings/src/com/android/settings/fuelgauge/BatteryInfo.java

    public static BatteryInfo getBatteryInfo(Context context, Intent batteryBroadcast,@NonNull BatteryUsageStats batteryUsageStats, Estimate estimate,long elapsedRealtimeUs, boolean shortString) {final long startTime = System.currentTimeMillis();final boolean isCompactStatus = context.getResources().getBoolean(com.android.settings.R.bool.config_use_compact_battery_status);BatteryInfo info = new BatteryInfo();info.mBatteryUsageStats = batteryUsageStats;info.batteryLevel = Utils.getBatteryLevel(batteryBroadcast);info.batteryPercentString = Utils.formatPercentage(info.batteryLevel);info.mCharging = batteryBroadcast.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0;info.averageTimeToDischarge = estimate.getAverageDischargeTime();info.isOverheated = batteryBroadcast.getIntExtra(BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_UNKNOWN)== BatteryManager.BATTERY_HEALTH_OVERHEAT;info.statusLabel = Utils.getBatteryStatus(context, batteryBroadcast, isCompactStatus);info.batteryStatus = batteryBroadcast.getIntExtra(BatteryManager.EXTRA_STATUS, BatteryManager.BATTERY_STATUS_UNKNOWN);if (!info.mCharging) {updateBatteryInfoDischarging(context, shortString, estimate, info);} else {updateBatteryInfoCharging(context, batteryBroadcast, batteryUsageStats,info, isCompactStatus);}BatteryUtils.logRuntime(LOG_TAG, "time for getBatteryInfo", startTime);return info;}private static void updateBatteryInfoCharging(Context context, Intent batteryBroadcast,BatteryUsageStats stats, BatteryInfo info, boolean compactStatus) {final Resources resources = context.getResources();final long chargeTimeMs = stats.getChargeTimeRemainingMs();final int status = batteryBroadcast.getIntExtra(BatteryManager.EXTRA_STATUS,BatteryManager.BATTERY_STATUS_UNKNOWN);info.discharging = false;info.suggestionLabel = null;if (info.isOverheated && status != BatteryManager.BATTERY_STATUS_FULL) {info.remainingLabel = null;int chargingLimitedResId = R.string.power_charging_limited;info.chargeLabel =context.getString(chargingLimitedResId, info.batteryPercentString);} else if (chargeTimeMs > 0 && status != BatteryManager.BATTERY_STATUS_FULL) {info.remainingTimeUs = PowerUtil.convertMsToUs(chargeTimeMs);final CharSequence timeString = StringUtil.formatElapsedTime(context,PowerUtil.convertUsToMs(info.remainingTimeUs),false /* withSeconds */,true /* collapseTimeUnit */);int resId = R.string.power_charging_duration;info.remainingLabel = context.getString(R.string.power_remaining_charging_duration_only, timeString);info.chargeLabel = context.getString(resId, info.batteryPercentString, timeString);} else {final String chargeStatusLabel =Utils.getBatteryStatus(context, batteryBroadcast, compactStatus);info.remainingLabel = null;info.chargeLabel = info.batteryLevel == 100 ? info.batteryPercentString :resources.getString(R.string.power_charging, info.batteryPercentString,chargeStatusLabel.toLowerCase());}}private static void updateBatteryInfoDischarging(Context context, boolean shortString,Estimate estimate, BatteryInfo info) {final long drainTimeUs = PowerUtil.convertMsToUs(estimate.getEstimateMillis());if (drainTimeUs > 0) {info.remainingTimeUs = drainTimeUs;info.remainingLabel = PowerUtil.getBatteryRemainingStringFormatted(context,PowerUtil.convertUsToMs(drainTimeUs),null /* percentageString */,false /* basedOnUsage */);info.chargeLabel = PowerUtil.getBatteryRemainingStringFormatted(context,PowerUtil.convertUsToMs(drainTimeUs),info.batteryPercentString,estimate.isBasedOnUsage() && !shortString);info.suggestionLabel = PowerUtil.getBatteryTipStringFormatted(context, PowerUtil.convertUsToMs(drainTimeUs));} else {info.remainingLabel = null;info.suggestionLabel = null;info.chargeLabel = info.batteryPercentString;}}

2.1 充电时间计算

2.1.1 BatteryUsageStats获取

  • updateBatteryInfoCharging 中获取 BatteryUsageStatsmChargeTimeRemainingMs还需的充电时间;显示<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"还需<xliff:g id="TIME">%1$s</xliff:g>充满"</string>
  • BatteryUsageStats对象是BatteryStatsService通过BatteryUsageStatsProvider获取
  • BatteryUsageStatsProviderBatteryChargeCalculator.java#calculate最终调用到batteryStats.computeChargeTimeRemaining(rawRealtimeUs)计算

packages/apps/Settings/src/com/android/settings/fuelgauge/BatteryUtils.java

    public BatteryInfo getBatteryInfo(final String tag) {final BatteryStatsManager systemService = mContext.getSystemService(BatteryStatsManager.class);BatteryUsageStats batteryUsageStats;try {batteryUsageStats = systemService.getBatteryUsageStats(new BatteryUsageStatsQuery.Builder().includeBatteryHistory().build());} catch (RuntimeException e) {Log.e(TAG, "getBatteryInfo() error from getBatteryUsageStats()", e);// Use default BatteryUsageStats.batteryUsageStats = new BatteryUsageStats.Builder(new String[0]).build();}final long startTime = System.currentTimeMillis();// Stuff we always need to get BatteryInfofinal Intent batteryBroadcast = mContext.registerReceiver(null,new IntentFilter(Intent.ACTION_BATTERY_CHANGED));final long elapsedRealtimeUs = PowerUtil.convertMsToUs(SystemClock.elapsedRealtime());BatteryInfo batteryInfo;Estimate estimate = getEnhancedEstimate();// couldn't get estimate from cache or provider, use fallbackif (estimate == null) {estimate = new Estimate(batteryUsageStats.getBatteryTimeRemainingMs(),false /* isBasedOnUsage */,EstimateKt.AVERAGE_TIME_TO_DISCHARGE_UNKNOWN);}BatteryUtils.logRuntime(tag, "BatteryInfoLoader post query", startTime);batteryInfo = BatteryInfo.getBatteryInfo(mContext, batteryBroadcast,batteryUsageStats, estimate, elapsedRealtimeUs, false /* shortString */);BatteryUtils.logRuntime(tag, "BatteryInfoLoader.loadInBackground", startTime);try {batteryUsageStats.close();} catch (Exception e) {Log.e(TAG, "BatteryUsageStats.close() failed", e);}return batteryInfo;}

frameworks/base/core/java/com/android/internal/os/BatteryUsageStatsProvider.java

    private BatteryUsageStats getCurrentBatteryUsageStats(BatteryUsageStatsQuery query,long currentTimeMs) {final long realtimeUs = elapsedRealtime() * 1000;final long uptimeUs = uptimeMillis() * 1000;final boolean includePowerModels = (query.getFlags()& BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_POWER_MODELS) != 0;final boolean includeProcessStateData = ((query.getFlags()& BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_PROCESS_STATE_DATA) != 0)&& mStats.isProcessStateDataAvailable();final boolean includeVirtualUids =  ((query.getFlags()& BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_VIRTUAL_UIDS) != 0);final BatteryUsageStats.Builder batteryUsageStatsBuilder = new BatteryUsageStats.Builder(mStats.getCustomEnergyConsumerNames(), includePowerModels,includeProcessStateData);// TODO(b/188068523): use a monotonic clock to ensure resilience of order and duration// of stats sessions to wall-clock adjustmentsbatteryUsageStatsBuilder.setStatsStartTimestamp(mStats.getStartClockTime());batteryUsageStatsBuilder.setStatsEndTimestamp(currentTimeMs);SparseArray<? extends BatteryStats.Uid> uidStats = mStats.getUidStats();for (int i = uidStats.size() - 1; i >= 0; i--) {final BatteryStats.Uid uid = uidStats.valueAt(i);if (!includeVirtualUids && uid.getUid() == Process.SDK_SANDBOX_VIRTUAL_UID) {continue;}batteryUsageStatsBuilder.getOrCreateUidBatteryConsumerBuilder(uid).setTimeInStateMs(UidBatteryConsumer.STATE_BACKGROUND,getProcessBackgroundTimeMs(uid, realtimeUs)).setTimeInStateMs(UidBatteryConsumer.STATE_FOREGROUND,getProcessForegroundTimeMs(uid, realtimeUs));}final int[] powerComponents = query.getPowerComponents();final List<PowerCalculator> powerCalculators = getPowerCalculators();for (int i = 0, count = powerCalculators.size(); i < count; i++) {PowerCalculator powerCalculator = powerCalculators.get(i);if (powerComponents != null) {boolean include = false;for (int j = 0; j < powerComponents.length; j++) {if (powerCalculator.isPowerComponentSupported(powerComponents[j])) {include = true;break;}}if (!include) {continue;}}powerCalculator.calculate(batteryUsageStatsBuilder, mStats, realtimeUs, uptimeUs,query);}if ((query.getFlags()& BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_HISTORY) != 0) {if (!(mStats instanceof BatteryStatsImpl)) {throw new UnsupportedOperationException("History cannot be included for " + getClass().getName());}BatteryStatsImpl batteryStatsImpl = (BatteryStatsImpl) mStats;// Make a copy of battery history to avoid concurrent modification.Parcel historyBuffer = Parcel.obtain();historyBuffer.appendFrom(batteryStatsImpl.mHistoryBuffer, 0,batteryStatsImpl.mHistoryBuffer.dataSize());final File systemDir =batteryStatsImpl.mBatteryStatsHistory.getHistoryDirectory().getParentFile();final BatteryStatsHistory batteryStatsHistory =new BatteryStatsHistory(batteryStatsImpl, systemDir, historyBuffer);batteryUsageStatsBuilder.setBatteryHistory(batteryStatsHistory);}BatteryUsageStats stats = batteryUsageStatsBuilder.build();if (includeProcessStateData) {verify(stats);}return stats;}// STOPSHIP(b/229906525): remove verification before shippingprivate static boolean sErrorReported;private void verify(BatteryUsageStats stats) {if (sErrorReported) {return;}final double precision = 2.0;   // Allow rounding errors up to 2 mAhfinal int[] components ={BatteryConsumer.POWER_COMPONENT_CPU,BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO,BatteryConsumer.POWER_COMPONENT_WIFI,BatteryConsumer.POWER_COMPONENT_BLUETOOTH};final int[] states ={BatteryConsumer.PROCESS_STATE_FOREGROUND,BatteryConsumer.PROCESS_STATE_BACKGROUND,BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE,BatteryConsumer.PROCESS_STATE_CACHED};for (UidBatteryConsumer ubc : stats.getUidBatteryConsumers()) {for (int component : components) {double consumedPower = ubc.getConsumedPower(ubc.getKey(component));double sumStates = 0;for (int state : states) {sumStates += ubc.getConsumedPower(ubc.getKey(component, state));}if (sumStates > consumedPower + precision) {String error = "Sum of states exceeds total. UID = " + ubc.getUid() + " "+ BatteryConsumer.powerComponentIdToString(component)+ " total = " + consumedPower + " states = " + sumStates;if (!sErrorReported) {Slog.wtf(TAG, error);sErrorReported = true;} else {Slog.e(TAG, error);}return;}}}}

frameworks/base/core/java/com/android/internal/os/BatteryChargeCalculator.java

    @Overridepublic void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats,long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {builder.setDischargePercentage(batteryStats.getDischargeAmount(BatteryStats.STATS_SINCE_CHARGED));int batteryCapacityMah = batteryStats.getLearnedBatteryCapacity() / 1000;if (batteryCapacityMah <= 0) {batteryCapacityMah = batteryStats.getMinLearnedBatteryCapacity() / 1000;if (batteryCapacityMah <= 0) {batteryCapacityMah = batteryStats.getEstimatedBatteryCapacity();}}builder.setBatteryCapacity(batteryCapacityMah);final double dischargedPowerLowerBoundMah =batteryStats.getLowDischargeAmountSinceCharge() * batteryCapacityMah / 100.0;final double dischargedPowerUpperBoundMah =batteryStats.getHighDischargeAmountSinceCharge() * batteryCapacityMah / 100.0;builder.setDischargePercentage(batteryStats.getDischargeAmount(BatteryStats.STATS_SINCE_CHARGED)).setDischargedPowerRange(dischargedPowerLowerBoundMah,dischargedPowerUpperBoundMah).setDischargeDurationMs(batteryStats.getBatteryRealtime(rawRealtimeUs) / 1000);final long batteryTimeRemainingMs = batteryStats.computeBatteryTimeRemaining(rawRealtimeUs);if (batteryTimeRemainingMs != -1) {builder.setBatteryTimeRemainingMs(batteryTimeRemainingMs / 1000);}final long chargeTimeRemainingMs = batteryStats.computeChargeTimeRemaining(rawRealtimeUs);if (chargeTimeRemainingMs != -1) {builder.setChargeTimeRemainingMs(chargeTimeRemainingMs / 1000);}long dischargeMah = batteryStats.getUahDischarge(BatteryStats.STATS_SINCE_CHARGED) / 1000;if (dischargeMah == 0) {dischargeMah = (long) ((dischargedPowerLowerBoundMah + dischargedPowerUpperBoundMah) / 2+ 0.5);}builder.getAggregateBatteryConsumerBuilder(BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE).setConsumedPower(dischargeMah);}

2.1.2 BatteryStatsImpl计算

  • mBatteryTimeToFullSeconds 这个是底层支持计算,由底层health上报。
  • 计算逻辑 final LevelStepTracker mChargeStepTracker = new LevelStepTracker(MAX_LEVEL_STEPS);
    1. 电池状态信息变化调用**setBatteryStateLocked**,这里mChargeStepTrackerinit()初始化或level增大变化记录计算addLevelSteps
    2. mChargeStepTracker.mNumStepDurations < 1 充满一格电不会显示,至少连续充满两格电
    3. mChargeStepTracker.computeTimePerLevel() 平均addLevelSteps记录充电每个格电的总时间
    4. (msPerLevel * (100 - mCurrentBatteryLevel)) * 1000; 连续充电的平均得到的每格电充电时间 * 需要充电level

frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java

    @Overridepublic long computeChargeTimeRemaining(long curTime) {if (mOnBattery) {// Not yet working.return -1;}if (mBatteryTimeToFullSeconds >= 0) {return mBatteryTimeToFullSeconds * (1000 * 1000); // s to us}// Else use algorithmic approachif (mChargeStepTracker.mNumStepDurations < 1) {return -1;}long msPerLevel = mChargeStepTracker.computeTimePerLevel();if (msPerLevel <= 0) {return -1;}return (msPerLevel * (100 - mCurrentBatteryLevel)) * 1000;}

frameworks/base/core/java/android/os/BatteryStats.java

    public static final class LevelStepTracker {public long mLastStepTime = -1;public int mNumStepDurations;public final long[] mStepDurations;public LevelStepTracker(int maxLevelSteps) {mStepDurations = new long[maxLevelSteps];}public LevelStepTracker(int numSteps, long[] steps) {mNumStepDurations = numSteps;mStepDurations = new long[numSteps];System.arraycopy(steps, 0, mStepDurations, 0, numSteps);}// ... ...public void init() {mLastStepTime = -1;mNumStepDurations = 0;}// ... ...public long computeTimePerLevel() {final long[] steps = mStepDurations;final int numSteps = mNumStepDurations;// 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;}// ... ...public void addLevelSteps(int numStepLevels, long modeBits, long elapsedRealtime) {int stepCount = mNumStepDurations;final long lastStepTime = mLastStepTime;if (lastStepTime >= 0 && numStepLevels > 0) {final long[] steps = mStepDurations;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;}}mNumStepDurations = stepCount;mLastStepTime = elapsedRealtime;}// ... ...}

2.2 电池剩余使用时间

2.2.1 Estimate获取

  • updateBatteryInfoDischarging 获取EstimateestimateMillis ,由 2.1.1BatteryUsageStats 获取中查看实际获取batteryUsageStats.getBatteryTimeRemainingMs()
  • BatteryUsageStatsmBatteryTimeRemainingMs查看上面BatteryChargeCalculator.java#calculate最终调用到batteryStats.computeBatteryTimeRemaining(rawRealtimeUs)计算
  • Estimate.kt 如果缓存的估计值可用,则返回该估计值。如果估计不可用或超过2分钟,将返回null。相关属性Settings.Global.BATTERY_ESTIMATES_LAST_UPDATE_TIME、Settings.Global.TIME_REMAINING_ESTIMATE_MILLIS、Settings.Global.TIME_REMAINING_ESTIMATE_BASED_ON_USAGE、Settings.Global.AVERAGE_TIME_TO_DISCHARGE

frameworks/base/packages/SettingsLib/src/com/android/settingslib/fuelgauge/Estimate.kt
packages/apps/Settings/src/com/android/settings/fuelgauge/BatteryUtils.java

    Estimate getEnhancedEstimate() {Estimate estimate = null;// Get enhanced prediction if availableif (Duration.between(Estimate.getLastCacheUpdateTime(mContext), Instant.now()).compareTo(Duration.ofSeconds(10)) < 0) {estimate = Estimate.getCachedEstimateIfAvailable(mContext);} else if (mPowerUsageFeatureProvider != null &&mPowerUsageFeatureProvider.isEnhancedBatteryPredictionEnabled(mContext)) {estimate = mPowerUsageFeatureProvider.getEnhancedBatteryPrediction(mContext);if (estimate != null) {Estimate.storeCachedEstimate(mContext, estimate);}}return estimate;}

2.2.2 BatteryStatsImpl计算

  • 计算逻辑 final LevelStepTracker mDischargeStepTracker = new LevelStepTracker(MAX_LEVEL_STEPS);
    1. 电池状态信息变化调用**setBatteryStateLocked**,这里mDischargeStepTracker init()初始化或level减小变化记录计算addLevelSteps
    2. mDischargeStepTracker.mNumStepDurations < 1 耗电一格电不会显示,至少连续耗电两格电
    3. mChargeStepTracker.computeTimePerLevel() 平均addLevelSteps记录耗电每个格电的总时间
    4. (msPerLevel * mCurrentBatteryLevel) * 1000 连续耗电的平均得到的每格电充电时间 * 当前电量level

frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java

    public long computeBatteryTimeRemaining(long curTime) {if (!mOnBattery) {return -1;}if (mDischargeStepTracker.mNumStepDurations < 1) {return -1;}long msPerLevel = mDischargeStepTracker.computeTimePerLevel();if (msPerLevel <= 0) {return -1;}return (msPerLevel * mCurrentBatteryLevel) * 1000;}

3、电池信息来源

  • mHealthServiceWrapper = HealthServiceWrapper.create(this::update);注册监听IHealthInfoCallback.hal,回调执行 update > processValuesLocked
  • android.hardware.health@2.0-service 中 轮询更新Health::update(),其中battery_monitor_->logValues()输出日志healthd : battery l=
  • BatteryService.java#processValuesLocked 通过BatteryStatsService.java最终通知到 BatteryStatsImpl.java#setBatteryStateLocked;这里输出Event日志battery_level、battery_status、battery_discharge、BatteryService

frameworks/base/services/core/java/com/android/server/BatteryService.java

    private void registerHealthCallback() {traceBegin("HealthInitWrapper");// IHealth is lazily retrieved.try {mHealthServiceWrapper = HealthServiceWrapper.create(this::update);} catch (RemoteException ex) {Slog.e(TAG, "health: cannot register callback. (RemoteException)");throw ex.rethrowFromSystemServer();} catch (NoSuchElementException ex) {Slog.e(TAG, "health: cannot register callback. (no supported health HAL service)");throw ex;} finally {traceEnd();}traceBegin("HealthInitWaitUpdate");// init register for new service notifications, and IServiceManager should return the// existing service in a near future. Wait for this.update() to instantiate// the initial mHealthInfo.long beforeWait = SystemClock.uptimeMillis();synchronized (mLock) {while (mHealthInfo == null) {Slog.i(TAG, "health: Waited " + (SystemClock.uptimeMillis() - beforeWait) +"ms for callbacks. Waiting another " + HEALTH_HAL_WAIT_MS + " ms...");try {mLock.wait(HEALTH_HAL_WAIT_MS);} catch (InterruptedException ex) {Slog.i(TAG, "health: InterruptedException when waiting for update. "+ " Continuing...");}}}Slog.i(TAG, "health: Waited " + (SystemClock.uptimeMillis() - beforeWait)+ "ms and received the update.");traceEnd();}private void update(android.hardware.health.HealthInfo info) {traceBegin("HealthInfoUpdate");Trace.traceCounter(Trace.TRACE_TAG_POWER, "BatteryChargeCounter", info.batteryChargeCounterUah);Trace.traceCounter(Trace.TRACE_TAG_POWER, "BatteryCurrent", info.batteryCurrentMicroamps);Trace.traceCounter(Trace.TRACE_TAG_POWER, "PlugType", plugType(info));Trace.traceCounter(Trace.TRACE_TAG_POWER, "BatteryStatus", info.batteryStatus);synchronized (mLock) {if (!mUpdatesStopped) {mHealthInfo = info;// Process the new values.processValuesLocked(false);mLock.notifyAll(); // for any waiters on new info} else {copyV1Battery(mLastHealthInfo, info);}}traceEnd();}private void processValuesLocked(boolean force) {boolean logOutlier = false;long dischargeDuration = 0;mBatteryLevelCritical =mHealthInfo.batteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN&& mHealthInfo.batteryLevel <= mCriticalBatteryLevel;mPlugType = plugType(mHealthInfo);if (DEBUG) {Slog.d(TAG, "Processing new values: "+ "info=" + mHealthInfo+ ", mBatteryLevelCritical=" + mBatteryLevelCritical+ ", mPlugType=" + mPlugType);}// Let the battery stats keep track of the current level.try {mBatteryStats.setBatteryState(mHealthInfo.batteryStatus,mHealthInfo.batteryHealth,mPlugType,mHealthInfo.batteryLevel,mHealthInfo.batteryTemperatureTenthsCelsius,mHealthInfo.batteryVoltageMillivolts,mHealthInfo.batteryChargeCounterUah,mHealthInfo.batteryFullChargeUah,mHealthInfo.batteryChargeTimeToFullNowSeconds);} catch (RemoteException e) {// Should never happen.}shutdownIfNoPowerLocked();shutdownIfOverTempLocked();if (force|| (mHealthInfo.batteryStatus != mLastBatteryStatus|| mHealthInfo.batteryHealth != mLastBatteryHealth|| mHealthInfo.batteryPresent != mLastBatteryPresent|| mHealthInfo.batteryLevel != mLastBatteryLevel|| mPlugType != mLastPlugType|| mHealthInfo.batteryVoltageMillivolts != mLastBatteryVoltage|| mHealthInfo.batteryTemperatureTenthsCelsius != mLastBatteryTemperature|| mHealthInfo.maxChargingCurrentMicroamps != mLastMaxChargingCurrent|| mHealthInfo.maxChargingVoltageMicrovolts != mLastMaxChargingVoltage|| mHealthInfo.batteryChargeCounterUah != mLastChargeCounter|| mInvalidCharger != mLastInvalidCharger)) {if (mPlugType != mLastPlugType) {if (mLastPlugType == BATTERY_PLUGGED_NONE) {// discharging -> chargingmChargeStartLevel = mHealthInfo.batteryLevel;mChargeStartTime = SystemClock.elapsedRealtime();final LogMaker builder = new LogMaker(MetricsEvent.ACTION_CHARGE);builder.setType(MetricsEvent.TYPE_ACTION);builder.addTaggedData(MetricsEvent.FIELD_PLUG_TYPE, mPlugType);builder.addTaggedData(MetricsEvent.FIELD_BATTERY_LEVEL_START,mHealthInfo.batteryLevel);mMetricsLogger.write(builder);// 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 != mHealthInfo.batteryLevel) {dischargeDuration = SystemClock.elapsedRealtime() - mDischargeStartTime;logOutlier = true;EventLog.writeEvent(EventLogTags.BATTERY_DISCHARGE, dischargeDuration,mDischargeStartLevel, mHealthInfo.batteryLevel);// make sure we see a discharge event before logging againmDischargeStartTime = 0;}} else if (mPlugType == BATTERY_PLUGGED_NONE) {// charging -> discharging or we just powered upmDischargeStartTime = SystemClock.elapsedRealtime();mDischargeStartLevel = mHealthInfo.batteryLevel;long chargeDuration = SystemClock.elapsedRealtime() - mChargeStartTime;if (mChargeStartTime != 0 && chargeDuration != 0) {final LogMaker builder = new LogMaker(MetricsEvent.ACTION_CHARGE);builder.setType(MetricsEvent.TYPE_DISMISS);builder.addTaggedData(MetricsEvent.FIELD_PLUG_TYPE, mLastPlugType);builder.addTaggedData(MetricsEvent.FIELD_CHARGING_DURATION_MILLIS,chargeDuration);builder.addTaggedData(MetricsEvent.FIELD_BATTERY_LEVEL_START,mChargeStartLevel);builder.addTaggedData(MetricsEvent.FIELD_BATTERY_LEVEL_END,mHealthInfo.batteryLevel);mMetricsLogger.write(builder);}mChargeStartTime = 0;}}if (mHealthInfo.batteryStatus != mLastBatteryStatus ||mHealthInfo.batteryHealth != mLastBatteryHealth ||mHealthInfo.batteryPresent != mLastBatteryPresent ||mPlugType != mLastPlugType) {EventLog.writeEvent(EventLogTags.BATTERY_STATUS,mHealthInfo.batteryStatus, mHealthInfo.batteryHealth, mHealthInfo.batteryPresent ? 1 : 0,mPlugType, mHealthInfo.batteryTechnology);}if (mHealthInfo.batteryLevel != mLastBatteryLevel) {// Don't do this just from voltage or temperature changes, that is// too noisy.EventLog.writeEvent(EventLogTags.BATTERY_LEVEL,mHealthInfo.batteryLevel,mHealthInfo.batteryVoltageMillivolts,mHealthInfo.batteryTemperatureTenthsCelsius);}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&& mHealthInfo.batteryStatus !=BatteryManager.BATTERY_STATUS_UNKNOWN&& mHealthInfo.batteryLevel <= mLowBatteryWarningLevel) {mBatteryLevelLow = true;}} else {// Should we now switch out of low battery mode?if (mPlugType != BATTERY_PLUGGED_NONE) {mBatteryLevelLow = false;} else if (mHealthInfo.batteryLevel >= mLowBatteryCloseWarningLevel)  {mBatteryLevelLow = false;} else if (force && mHealthInfo.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;}}mSequence++;// 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) {final Intent statusIntent = new Intent(Intent.ACTION_POWER_CONNECTED);statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);statusIntent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence);mHandler.post(new Runnable() {@Overridepublic void run() {mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);}});}else if (mPlugType == 0 && mLastPlugType != 0) {final Intent statusIntent = new Intent(Intent.ACTION_POWER_DISCONNECTED);statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);statusIntent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence);mHandler.post(new Runnable() {@Overridepublic void run() {mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);}});}if (shouldSendBatteryLowLocked()) {mSentLowBatteryBroadcast = true;final Intent statusIntent = new Intent(Intent.ACTION_BATTERY_LOW);statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);statusIntent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence);mHandler.post(new Runnable() {@Overridepublic void run() {mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);}});} else if (mSentLowBatteryBroadcast &&mHealthInfo.batteryLevel >= mLowBatteryCloseWarningLevel) {mSentLowBatteryBroadcast = false;final Intent statusIntent = new Intent(Intent.ACTION_BATTERY_OKAY);statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);statusIntent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence);mHandler.post(new Runnable() {@Overridepublic void run() {mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);}});}// We are doing this after sending the above broadcasts, so anything processing// them will get the new sequence number at that point.  (See for example how testing// of JobScheduler's BatteryController works.)sendBatteryChangedIntentLocked();if (mLastBatteryLevel != mHealthInfo.batteryLevel || mLastPlugType != mPlugType) {sendBatteryLevelChangedIntentLocked();}// Update the battery LEDmLed.updateLightsLocked();// This needs to be done after sendIntent() so that we get the lastest battery stats.if (logOutlier && dischargeDuration != 0) {logOutlierLocked(dischargeDuration);}mLastBatteryStatus = mHealthInfo.batteryStatus;mLastBatteryHealth = mHealthInfo.batteryHealth;mLastBatteryPresent = mHealthInfo.batteryPresent;mLastBatteryLevel = mHealthInfo.batteryLevel;mLastPlugType = mPlugType;mLastBatteryVoltage = mHealthInfo.batteryVoltageMillivolts;mLastBatteryTemperature = mHealthInfo.batteryTemperatureTenthsCelsius;mLastMaxChargingCurrent = mHealthInfo.maxChargingCurrentMicroamps;mLastMaxChargingVoltage = mHealthInfo.maxChargingVoltageMicrovolts;mLastChargeCounter = mHealthInfo.batteryChargeCounterUah;mLastBatteryLevelCritical = mBatteryLevelCritical;mLastInvalidCharger = mInvalidCharger;}}

hardware/interfaces/health/2.0/utils/libhealthservice/HealthServiceCommon.cpp

void healthd_mode_service_2_0_battery_update(struct android::BatteryProperties* prop) {HealthInfo info;convertToHealthInfo(prop, info.legacy);Health::getImplementation()->notifyListeners(&info);
}static struct healthd_mode_ops healthd_mode_service_2_0_ops = {.init = healthd_mode_service_2_0_init,.preparetowait = healthd_mode_service_2_0_preparetowait,.heartbeat = healthd_mode_service_2_0_heartbeat,.battery_update = healthd_mode_service_2_0_battery_update,
};int health_service_main(const char* instance) {gInstanceName = instance;if (gInstanceName.empty()) {gInstanceName = "default";}healthd_mode_ops = &healthd_mode_service_2_0_ops;LOG(INFO) << LOG_TAG << gInstanceName << ": Hal starting main loop...";return healthd_main();
}

hardware/interfaces/health/2.0/default/healthd_common_adapter.cpp

// Adapter of HealthLoop to use legacy healthd_mode_ops.
class HealthLoopAdapter : public HealthLoop {public:// Expose internal functions, assuming clients calls them in the same thread// where StartLoop is called.int RegisterEvent(int fd, BoundFunction func, EventWakeup wakeup) {return HealthLoop::RegisterEvent(fd, func, wakeup);}void AdjustWakealarmPeriods(bool charger_online) {return HealthLoop::AdjustWakealarmPeriods(charger_online);}protected:void Init(healthd_config* config) override { healthd_mode_ops->init(config); }void Heartbeat() override { healthd_mode_ops->heartbeat(); }int PrepareToWait() override { return healthd_mode_ops->preparetowait(); }void ScheduleBatteryUpdate() override { Health::getImplementation()->update(); }
};

hardware/interfaces/health/utils/libhealthloop/HealthLoop.cpp

void HealthLoop::PeriodicChores() {ScheduleBatteryUpdate();
}void HealthLoop::MainLoop(void) {int nevents = 0;while (1) {reject_event_register_ = true;size_t eventct = event_handlers_.size();struct epoll_event events[eventct];int timeout = awake_poll_interval_;int mode_timeout;/* Don't wait for first timer timeout to run periodic chores */if (!nevents) PeriodicChores();Heartbeat();mode_timeout = PrepareToWait();if (timeout < 0 || (mode_timeout > 0 && mode_timeout < timeout)) timeout = mode_timeout;nevents = epoll_wait(epollfd_, events, eventct, timeout);if (nevents == -1) {if (errno == EINTR) continue;KLOG_ERROR(LOG_TAG, "healthd_mainloop: epoll_wait failed\n");break;}for (int n = 0; n < nevents; ++n) {if (events[n].data.ptr) {auto* event_handler = reinterpret_cast<EventHandler*>(events[n].data.ptr);event_handler->func(event_handler->object, events[n].events);}}}return;
}

hardware/interfaces/health/2.0/default/Health.cpp

Return<Result> Health::update() {if (!healthd_mode_ops || !healthd_mode_ops->battery_update) {LOG(WARNING) << "health@2.0: update: not initialized. "<< "update() should not be called in charger";return Result::UNKNOWN;}// Retrieve all information and call healthd_mode_ops->battery_update, which calls// notifyListeners.battery_monitor_->updateValues();const HealthInfo_1_0& health_info = battery_monitor_->getHealthInfo_1_0();struct BatteryProperties props;convertFromHealthInfo(health_info, &props);bool log = (healthd_board_battery_update(&props) == 0);if (log) {battery_monitor_->logValues();}healthd_mode_ops->battery_update(&props);bool chargerOnline = battery_monitor_->isChargerOnline();// adjust uevent / wakealarm periodshealthd_battery_update_internal(chargerOnline);return Result::SUCCESS;
}void Health::notifyListeners(HealthInfo* healthInfo) {std::vector<StorageInfo> info;get_storage_info(info);std::vector<DiskStats> stats;get_disk_stats(stats);int32_t currentAvg = 0;struct BatteryProperty prop;status_t ret = battery_monitor_->getProperty(BATTERY_PROP_CURRENT_AVG, &prop);if (ret == OK) {currentAvg = static_cast<int32_t>(prop.valueInt64);}healthInfo->batteryCurrentAverage = currentAvg;healthInfo->diskStats = stats;healthInfo->storageInfos = info;std::lock_guard<decltype(callbacks_lock_)> lock(callbacks_lock_);for (auto it = callbacks_.begin(); it != callbacks_.end();) {auto ret = (*it)->healthInfoChanged(*healthInfo);if (!ret.isOk() && ret.isDeadObject()) {it = callbacks_.erase(it);} else {++it;}}
}

4、命令模拟

frameworks/base/services/core/java/com/android/server/BatteryService.java

C:\Users\Administrator\Desktop>adb shell cmd battery
Battery service (battery) commands:helpPrint this help text.get [-f] [ac|usb|wireless|status|level|temp|present|counter|invalid]set [-f] [ac|usb|wireless|status|level|temp|present|counter|invalid] <value>Force a battery property value, freezing battery state.-f: force a battery change broadcast be sent, prints new sequence.unplug [-f]Force battery unplugged, freezing battery state.-f: force a battery change broadcast be sent, prints new sequence.reset [-f]Unfreeze battery state, returning to current hardware values.-f: force a battery change broadcast be sent, prints new sequence.suspend_inputSuspend charging even if plugged in.

* 日志

  • Event日志
# ---------------------------
# BatteryService.java
# ---------------------------
2722 battery_level (level|1|6),(voltage|1|1),(temperature|1|1)
2723 battery_status (status|1|5),(health|1|5),(present|1|5),(plugged|1|5),(technology|3)
# This is logged when battery goes from discharging to charging.
# It lets us count the total amount of time between charges and the discharge level
2730 battery_discharge (duration|2|3),(minLevel|1|6),(maxLevel|1|6)
12-23 05:47:45.420   602   764 I battery_status: [2,2,1,1,Li-ion]
12-23 13:13:43.762     0     0 W healthd : battery l=57 v=5000 t=25.0 h=2 st=2 c=900000 fc=3000000 cc=10 chg=a
12-23 13:13:51.756   602   623 I battery_level: [58,5000,250]
12-23 13:13:52.156   994  2461 D BatteryInfoLoader: BatteryInfoLoader post query: 5ms
12-23 13:13:52.168   994  2461 D BatteryInfo: time for getBatteryInfo: 1ms
12-23 13:13:52.170   994  2461 D BatteryInfoLoader: BatteryInfoLoader.loadInBackground: 19ms
12-23 13:13:52.300   994  2131 D BatteryTipLoader: BatteryInfoLoader post query: 6ms
12-23 13:13:52.308   994  2131 D BatteryInfo: time for getBatteryInfo: 1ms
12-23 13:13:52.308   994  2131 D BatteryTipLoader: BatteryInfoLoader.loadInBackground: 15ms
12-23 13:13:57.300   602   623 I battery_level: [59,5000,250]
12-23 13:13:57.706   994  2135 D BatteryTipLoader: BatteryInfoLoader post query: 14ms
12-23 13:13:57.713   994  2135 D BatteryInfo: time for getBatteryInfo: 7ms
12-23 13:13:57.714   994  2135 D BatteryTipLoader: BatteryInfoLoader.loadInBackground: 21ms
12-23 13:13:57.789   994  2461 D BatteryInfoLoader: BatteryInfoLoader post query: 4ms
12-23 13:13:57.792   994  2461 D BatteryInfo: time for getBatteryInfo: 1ms
12-23 13:13:57.793   994  2461 D BatteryInfoLoader: BatteryInfoLoader.loadInBackground: 8ms

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/426488.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java学习(66):局部类内方法访问

定义一个类 package com.zx; public class NotebookComputer {private int num; private CPU cpu;public String fromIntoBit(){ class CPU2{// 局部内部类public String countBit(int num){return Integer.toBinaryString(num);}}return (new CPU2().countBit(num));}/**** 普…

java学习(67):匿名内部类

package com.zx; /* 2 匿名内部类 3 就是内部类的简化写法。 4 5 前提&#xff1a;存在一个类或者接口 6 这里的类可以是具体类也可以是抽象类。 7 8 格式&#xff1a; 9 new 类名或者接口名(){ 10 重写方法; 11 …

11.8学习笔记

封装一套自己的model类&#xff08;增 删 查 改&#xff09; select * from news where 1 :默认子查询查询所有的条件 ,如果有其他的条件可以覆盖默认查询所有的条件 mysqli_insert_id //返回添加的id mysqli_affected_rows();//返回删除的行数 例子&#xff1a; header("…

java学习(68):局部内部类

public class test113 {public void method(){final int age 23;class Localinner{public void method(){System.out.println("歌谣");System.out.println(age);}}new Localinner().method();}public static void main(String[] args) {test113 onew test113();o.met…

java学习(69):java模式设计之适配器

1需求是 //公司招员工&#xff0c;要求会讲中、英、法、日四国语言&#xff0c;同时还很会编程的员工。 这时候&#xff0c;我们先定义一个接口&#xff0c;实现接口中的方法我们就认为满足 //公司招员工&#xff0c;要求会讲中、英、法、日四国语言&#xff0c;同时还很会编…

selenium 验证码——万能码的使用

使用万能码需要导入一个random类生成随机码 # codingutf-8 import randomver random.randint(1000,9999)print u生成验证码&#xff1a;%d %vernum input(u输入验证码&#xff1a;) print numif num ver:print u登陆成功 elif num 999999:print u登陆成功 else:print u验证…

Intellij IDEA创建的Web项目配置Tomcat并启动Maven项目

点击如图所示的地方&#xff0c;进行添加Tomcat配置页面弹出页面后&#xff0c;按照如图顺序找到&#xff0c;点击号tomcat Service -> Local注意&#xff0c;这里不要选错了哦&#xff0c;还有一个TomEE Service&#xff01;按照下面图所示进行配置。图中数字的地方代表的配…

java学习(70):GUL图形用户界面初识

import java.awt.*; import javax.swing.*; public class test04 {public static void main(String[] args){//定义一个图形界面JFrame aanew JFrame();//建立一个标题aa.setTitle("歌谣");//创建一个按钮JButton an1new JButton("歌谣");//设置初始位置aa…

oracle实时分析,Oracle Exalytics 大幅提升实时分析洞察力

【天极网OOW2013上海消息】甲骨文近日宣布推出Oracle Exalytics商务智能云服务器的新版本Oracle Exalytics X3-4。新系统显著增强了软件功能和硬件更新&#xff0c;极大提升了针对商务分析的业内最快集成系统的性能。新的Oracle Exalytics X3-4具有2 TB主内存&#xff0c;2.4TB…

java学习(71):GUL边界布局管理器

//面向对象思想&#xff0c;边界管理布局器 import java.awt.*; import javax.swing.*; public class test06 extends JFrame {JButton an1,an2,an3,an4,an5;//把需要的组件定义在这里public static void main(String[] args){test06 lx1new test06();//主函数调用即可}//定义…

java学习(72):GUL流式布局管理器

//面向对象思想&#xff0c;流式管理布局器 import java.awt.*; import javax.swing.*; public class test07 extends JFrame {JButton[] an{null,null,null,null,null,null,null,null};//把需要的组件定义在这里public static void main(String[] args){test07 lx1new test07…

linux日志服务器配置在哪个文件,Linux中日志的基本配置(syslog)

Syslog日志的作用&#xff1a;syslog 日志可以帮我们主动的收集到设备的各种信息,并保存在syslog服务器上,当某些设备出现故障的时候,我们可以省去手动收集信息的麻烦,方便快捷的从syslog服务器中读取设备的各种信息来进行分析排错。linux中日志的类型&#xff1a;(1)info&…

java学习(73):GUL网格布局管理器

//面向对象思想&#xff0c;网格管理布局器 import java.awt.*; import javax.swing.*; public class test08 extends JFrame {JButton[] an{null,null,null,null,null,null,null,null,null};//把需要的组件定义在这里int s9;public static void main(String[] args){test08 l…

linux如何创建备份文件,如何备份Linux 配置文件

如何备份Linux配置文件文件备份是服务器安全最重要的一个环节&#xff0c;下面小编介绍使用Git工具来备份Linux配置文件。一、安装Git[rootlocalhost ~]# yum install git检查Git版本[rootlocalhost ~]# git --versiongit version 1.8.3.1[rootlocalhost ~]#设置初始参数将如下…

20172327 2018-2019-1 《程序设计与数据结构》第八周学习总结

20172327 2018-2019-1 《程序设计与数据结构》第八周学习总结 教材学习内容总结 第十二章 优先队列与堆 堆1.最小堆&#xff08;minheap)&#xff1a;对是一个完全二叉树&#xff0c;其中的每个结点都小于或等于它的两个孩子。2.最大堆&#xff08;maxheap)&#xff1a;对是一个…

java学习(74):GUL面板

//jPanel面板 //面向对象思想&#xff0c;面板&#xff0c;窗口的基础之上再加窗口 import java.awt.*; import javax.swing.*; public class test09 extends JFrame {JPanel mb1,mb2;JButton an1,an2,an3,an4,an5;public static void main(String[] args){test09 lx1new test…

java学习(75):GUL文本框和标签

//jPanel面板 文本框和标签 //面向对象思想&#xff0c;面板&#xff0c;窗口的基础之上再加窗口 import java.awt.*; import javax.swing.*; public class test10 extends JFrame {JPanel mb1,mb2,mb3;JButton an1,an2;JLabel bq1,bq2;//标签JTextField wbk;//文本框JPassword…

linux apr文件解压失败,Apache编译安装提示configure: error: APR not found错误解决方法...

在配置Apache的时候&#xff0c;出现configure: error: APR not found错误原因是缺少一些依赖包&#xff0c;安装这些依赖包就行了下载依赖包&#xff0c;注意我这里下载的与参考链接上的有些不同&#xff0c;安装上也有不一样wget http://archive.apache.org/dist/apr/apr-1.5…

java学习(76):GUL单选按钮和复选按钮

//单选按钮和复选按钮 //面向对象思想&#xff0c;面板&#xff0c;窗口的基础之上再加窗口 import java.awt.*; import javax.swing.*; public class test11 extends JFrame {JPanel mb1,mb2,mb3;JButton an1,an2;JLabel bq1,bq2;//标签JCheckBox fxk1,fxk2,fxk3;//复选框JRad…

uos20专业版是linux哪个版本,WPS Office 2019 for Linux 专业版已与统一操作系统 UOS 完成适配...

统信软件近日发布消息称&#xff0c;办公软件 WPS Office 2019 for Linux 专业版已与统一操作系统 UOS 完成适配工作。对比 2016 版本&#xff0c;2019 版本总体性能有大幅提升。这不仅体现在整体的启动速度上&#xff0c;文字、表格和演示三个组件基础功能的性能同样得到了整体…