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,一经查实,立即删除!

相关文章

matlab如何找出最小的数据,读取数据并找出全部数据的最大值和最小值

各位老大&#xff0c;如何将以下txt文件中的数据比较大小&#xff0c;获得全部数据的最大值和最小值&#xff0c;并且知道是那个发射组("Shot Number"),我现在的问题时这些数据如何赋予数组&#xff0c;"Shot Point MaxNumber",29"Shot Number",…

JS 判断两个时间的大小(可自由选择精确度:天,小时,分钟,秒)

//可自由选择精确度 如&#xff1a;签到时间&#xff1a;2018-11-07 11&#xff1a;00&#xff1a;00 签退时间&#xff1a;2018-11-07 10&#xff1a;59&#xff1a;59 //判断时间先后 //统一格式 var a $("#fdtmInDate").val(); var aa a.split(T); if (aa.lengt…

java学习(65):类访问static修饰的内部类

public class NotebookComputer01{ //定义一个非私有化的变量 private static int num; private CPU cpu; //方法呗私有化 public static class CPU{ //类型 private String number; //运行速度 private long speed; public void counter(int num){ System.out.println(Integer…

php 函数 数组 难学,php 数组的常用函数

函数名功能array_combine()生成一个数组,用一个数组的值作为键名,另一个数组值作为值range()创建并返回一个包含指定范围的元素的数组。compact()创建一个由参数所带变量组成的数组array_fill()用给定的值生成数组array_chunk()把一个数组分割为新的数组块array_merge()把两个或…

iOS录音后播放声音变小的解决方法

目前需求是录音之后再播放出来。经常会出现播放声音变很小的情况。 解决方法&#xff1a; if (recorder.recording){  [recorder stop];} [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionDefaultToS…

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));}/**** 普…

性能与优化的文章

Improving Your App’s Performance with PerfView Tools For Performance Analyzing WPA/WPR 微软WINDOS PERFORMANCE跟踪分析工具包 Windows Sysinternals——system utilities and technical information such as process dump,TCP View and so on 微软内置工具集&…

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

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

oracle自动备份定时任务,Oracle数据库定时自动备份批处理代码(Windows)

这是最近写的一个Oracle数据库自动备份的批处理&#xff0c;经过测试正常运行&#xff0c;记录如下。包括两部分&#xff0c;逻辑备份和冷备份&#xff0c;如有不完整之处&#xff0c;还往看到本文的高手指导&#xff01;注&#xff1a;这些内容是本人经过一番学习和多次测试调…

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…

oracle分区表扩分区 很慢,升级oracle10g 大分区表update变慢

原来使用的数据库是oracle8.1.7.4 这次升级为oracle 10.0.2.4,在导入旧dmp时候明显能够感觉到导入数据比较快。1.可是在正式使用之后&#xff0c;发现启用一个大表(使用了分区表)&#xff0c;在update使用比较慢&#xff0c;语句和索引建的和过去在oracle8i上是完全一致的。这…

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验证…

双机oracle,[精华] [原创]oracle双机群集系统

没有做oracle failsafe的oracle双机群集系统&#xff0c;如有要做failsafe的兄弟可以在此基础上安装FAILSAFE。一 .群集环境:1. 硬件环境:服务器A . IBM 365 SERVER 单路XEON SMP CPU, 6GB内存, 三块36.4G硬盘(RAID5), 本地千兆网卡(PRIVATE_LAN), 附加IBM 千兆光纤网卡(PUBL…

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

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

mysql(1):修改数据库密码

总是忘记&#xff0c;每次都要查文档&#xff0c;背背背 方法1&#xff1a; 用SET PASSWORD命令 首先登录MySQL。 格式&#xff1a;mysql> set password for 用户名localhost password(‘新密码’); 例子&#xff1a;mysql> set password for rootlocalhost passwor…

学PHP的嫌弃什么歌,抖音再见了互相嫌弃的老同学是什么歌

最近高考结束了&#xff0c;有一首歌突然很火&#xff0c;这首歌有一句歌词是再见了互相嫌弃的老同学再见了来不及说出的谢谢&#xff0c;那么这首感人的分别歌曲是什么歌呢?下面就让我们一起来看看吧。据悉这首歌是由好妹妹演的的不说再见好妹妹简介好妹妹乐队 是由两个热情洋…

ubuntu16 深度学习环境搭建步骤

在安装ubuntu之前需要条一下BIOS&#xff0c;讲UEFI模式改为Legacy 模式。 ubuntu分区系统搭建可以参考一下博客&#xff1a; 分区大小为&#xff1a; boot 400~500Mswap 内存大小主分区 >20G可以30Ghome 剩余全是引导区一定要放在boot上 添加对exfat格式u盘的支持 sudo apt…

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…