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
中获取BatteryUsageStats
中mChargeTimeRemainingMs
还需的充电时间;显示<string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"还需<xliff:g id="TIME">%1$s</xliff:g>充满"</string>
BatteryUsageStats
对象是BatteryStatsService
通过BatteryUsageStatsProvider
获取BatteryUsageStatsProvider
中BatteryChargeCalculator.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);
:
- 电池状态信息变化调用**
setBatteryStateLocked
**,这里mChargeStepTracker
会init()
初始化或level增大变化记录计算addLevelSteps
mChargeStepTracker.mNumStepDurations < 1
充满一格电不会显示,至少连续充满两格电mChargeStepTracker.computeTimePerLevel()
平均addLevelSteps
记录充电每个格电的总时间(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
获取Estimate
中estimateMillis
,由2.1.1BatteryUsageStats
获取中查看实际获取batteryUsageStats.getBatteryTimeRemainingMs()
BatteryUsageStats
中mBatteryTimeRemainingMs
查看上面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);
:
- 电池状态信息变化调用**
setBatteryStateLocked
**,这里mDischargeStepTracker
会init()
初始化或level减小变化记录计算addLevelSteps
mDischargeStepTracker.mNumStepDurations < 1
耗电一格电不会显示,至少连续耗电两格电mChargeStepTracker.computeTimePerLevel()
平均addLevelSteps
记录耗电每个格电的总时间(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
相关文章:

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 电池未充电与充电字…...
解密 Java ForEach 提前终止问题
目录 前言:场景复现分析与解决方案解决方案详解总结 前言: 你是否曾在使用 Java 8 的 forEach 迭代集合时遇到过提前终止循环的问题?在这篇博客中,我们将深入探讨这一问题,并提供多种解决方案。通过场景复现、分析源码…...

7_js_dom编程入门1
Objective(本课目标) 掌握获取页面元素的常用方法 掌握事件触发案例 能够区分innerText和innerHTML的区别 综合案例训练 1 DOM 介绍 1.1 什么是DOM 文档对象模型(Document Object Model,简称DOM),是 …...

使用 Elasticsearch 检测抄袭 (一)
作者:Priscilla Parodi 抄袭可以是直接的,涉及复制部分或全部内容,也可以是释义的,即通过更改一些单词或短语来重新表述作者的作品。 灵感和释义之间是有区别的。 即使你得出类似的结论,也可以阅读内容,获得…...

STM32 cubeMX 直流电机控制风扇转动
本文使用的是 HAL 库。 文章目录 前言一、直流电机介绍二、直流电机原理图三、直流电机控制方法四、STM32CubeMX 配置直流电机五、代码编写总结 前言 实验开发板:STM32F051K8。所需软件:keil5 , cubeMX 。实验目的:了解 直流电机…...

我在 VSCode 插件里接入了 ChatGPT,解决了Bug无法定位的难题
作为一名软件开发者,我时常面临着代码中Bug的定位和解决问题。这个过程往往既费时又充满挑战。然而,最近我在我的VSCode插件中接入了ChatGPT,这个决定彻底改变了我处理Bug的方式。 Bug:开发者的噩梦 在开发过程中,遇…...
学Java的第四天
一、switch语句 switch (表达式) { case 1: 语句体1; break; case 2: 语句体2; break; ... default: 语句体n1; break; } 首先计算表达式的值,然后和case 比较,有对应的值就执行对应的语句,遇到 break 就结束。 最后如果所有的cas…...

[内功修炼]函数栈帧的创建与销毁
文章目录 1:什么是函数栈帧2:理解函数栈帧能解决什么问题呢3:函数栈帧的创建与销毁的解析3.1:什么是栈3.2:认识相关寄存器与汇编指令相关寄存器相关汇编指令 3.3 解析函数栈帧的创建和销毁3.3.1 预备知识3.3.2 详细解析一:调用main函数,为main函数开辟函数栈帧First:push前push…...

【深度学习-目标检测】03 - Faster R-CNN 论文学习与总结
论文地址:Faster R-CNN: Towards Real-Time ObjectDetection with Region Proposal Networks 论文学习 1. 摘要与引言 研究背景与挑战:当前最先进的目标检测网络依赖于 区域提议(Region Proposals)来假设目标的位置,…...
oracle11体系结构二-存储结构
数据区: 数据区(数据扩展区)由一组连续的oracle数据块所构成的存储结构,一个或多个数据块组成一个数据区,一个或多个数据区组成一个段。当段中所有空间被使用完后,oracle系统将自动为该段分配一个新的数据…...

如何通过内网穿透实现远程访问本地Linux SVN服务
文章目录 前言1. Ubuntu安装SVN服务2. 修改配置文件2.1 修改svnserve.conf文件2.2 修改passwd文件2.3 修改authz文件 3. 启动svn服务4. 内网穿透4.1 安装cpolar内网穿透4.2 创建隧道映射本地端口 5. 测试公网访问6. 配置固定公网TCP端口地址6.1 保留一个固定的公网TCP端口地址6…...

网页乱码问题(edge浏览器)
网页乱码问题(edge) 文章目录 网页乱码问题(edge)前言一、网页乱码问题1.是什么:(描述)2.解决方法:(针对edge浏览器)(1)下载charset插…...

泛微OA xmlrpcServlet接口任意文件读取漏洞(CNVD-2022-43245)
CNVD-2022-43245 泛微e-cology XmlRpcServlet接口处存在任意文件读取漏洞,攻击者可利用漏洞获取敏感信息。 1.漏洞级别 中危 2.影响范围 e-office < 9.5 202201133.漏洞搜索 fofa 搜索 app"泛微-OA(e-cology)"4.漏洞复现 …...

MATLAB ga函数的使用方法
一、ga句法结构 x ga(fitnessfcn,nvars) x ga(fitnessfcn,nvars,A,b) x ga(fitnessfcn,nvars,A,b,Aeq,beq) x ga(fitnessfcn,nvars,A,b,Aeq,beg,IB,UB) x ga(fitnessfcn,nvars,A,b,Aeq,beq,LB,UB,nonlcon) x ga(fitnessfcn,nvars,A,b,Aeq,beq,LB,UB,nonlcon,options) x …...

基于STM32和MQ-2传感器的无线烟雾检测系统设计
随着科技的不断发展,人们对生活安全的要求也越来越高。其中,烟雾检测系统在预防火灾方面起着至关重要的作用。本文将介绍一种基于STM32和MQ-2传感器的无线烟雾检测系统设计,旨在实时检测环境中的烟雾,并及时发出警报,以…...

华为vrrp+mstp+ospf+dhcp+dhcp relay配置案例
1、左边是vlan 10主桥,右边是vlan 20的主桥,并且互为备桥 2、 vlan 10 vrrp网关默认用左边,vlan 20的vrrp 网关默认用右边,对应mstp生成树 3、两边都track检测,不通就把vrrp减掉60,这样就会自动切另一边了 …...
5-Docker实例-tomcat application
1.安装如下树形结构创建目录及文件,内容如下: 目录结构: [root@centos79 ~]# tree demo demo ├── index.html └── WEB-INF└── web.xml1 directory, 2 files [root@centos79 ~]# index.html文件内容 [root@centos79 demo]# cat index.html <h1>hello dock…...

Pikachu靶场 “Http Header”SQL注入
1. 先在 pikachu 打开 Http Header 注入模块,点击提示 查看登录 账号 和 密码,登陆后去 Burp 中找到登陆的 GET请求 2. 设置payload1 :在 User-Agent最后 输入 查看 数据库名 or updatexml(1,concat(0x7e,database()),0) or 查看 用户名…...

OpenEuler安装内网穿透工具实现ssh连接openEuler系统
文章目录 1. 本地SSH连接测试2. openEuler安装Cpolar3. 配置 SSH公网地址4. 公网远程SSH连接5. 固定连接SSH公网地址6. SSH固定地址连接测试 本文主要介绍在openEuler中安装Cpolar内网穿透工具实现远程也可以ssh 连接openEuler系统使用. 欧拉操作系统(openEuler, 简称“欧拉”…...
【效率工具】利用python进行本地知识库(PDF和WORK文件内容)的批量模糊搜索
目录 前言 一、为什么要进行本地文档的批量搜索? 二、如何去做呢?...

龙虎榜——20250610
上证指数放量收阴线,个股多数下跌,盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型,指数短线有调整的需求,大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的:御银股份、雄帝科技 驱动…...

JavaSec-RCE
简介 RCE(Remote Code Execution),可以分为:命令注入(Command Injection)、代码注入(Code Injection) 代码注入 1.漏洞场景:Groovy代码注入 Groovy是一种基于JVM的动态语言,语法简洁,支持闭包、动态类型和Java互操作性,…...
Linux链表操作全解析
Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表?1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...
R语言AI模型部署方案:精准离线运行详解
R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)
引言:为什么 Eureka 依然是存量系统的核心? 尽管 Nacos 等新注册中心崛起,但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制,是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...
MySQL用户和授权
开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务: test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...

视觉slam十四讲实践部分记录——ch2、ch3
ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...
Go 语言并发编程基础:无缓冲与有缓冲通道
在上一章节中,我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道,它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好࿰…...

搭建DNS域名解析服务器(正向解析资源文件)
正向解析资源文件 1)准备工作 服务端及客户端都关闭安全软件 [rootlocalhost ~]# systemctl stop firewalld [rootlocalhost ~]# setenforce 0 2)服务端安装软件:bind 1.配置yum源 [rootlocalhost ~]# cat /etc/yum.repos.d/base.repo [Base…...

C++ 设计模式 《小明的奶茶加料风波》
👨🎓 模式名称:装饰器模式(Decorator Pattern) 👦 小明最近上线了校园奶茶配送功能,业务火爆,大家都在加料: 有的同学要加波霸 🟤,有的要加椰果…...