Android8.0.0-r4——BatteryStatsService(二)

4、电量计算 
Android中计算耗电量离不开BatteryStatsHelper这个类,它主要用于计算所有应用和服务的用电量。 
示例:在Settings设置中显示电量相关信息,就是通过调用BatteryStatsHelper的接口来实现的。

从BatteryStatsHelper类的注释来看,当需要使用BatteryStatsHelper时: 必须在Activity或者Fragment初始化时,在onAttach(Fragment)或onCreate(Activity)中立即调用BatteryStatsHelper的create(); 同时在activity或者Fragment销毁时,在onDestroy()调用BatteryStatsHelper的destroy()。 

4.1 用法示例 
Settings中的BatteryStatsHelper的使用方式。

代码路径:/packages/apps/Settings/src/com/android/settings/fuelgauge/PowerUsageBase.java
(http://androidxref.com/8.0.0_r4/xref/packages/apps/Settings/src/com/android/settings/fuelgauge/PowerUsageBase.java)

41    protected BatteryStatsHelper mStatsHelper;
42    protected UserManager mUm;
43    private BatteryBroadcastReceiver mBatteryBroadcastReceiver;
44
45    @Override
46    public void onAttach(Activity activity) {
47        super.onAttach(activity);
48        mUm = (UserManager) activity.getSystemService(Context.USER_SERVICE);
49        mStatsHelper = new BatteryStatsHelper(activity, true);//创建
50    }
51
52    @Override
53    public void onCreate(Bundle icicle) {
54        super.onCreate(icicle);
55        mStatsHelper.create(icicle);//初始化
56        setHasOptionsMenu(true);
57
58        mBatteryBroadcastReceiver = new BatteryBroadcastReceiver(getContext());
59        mBatteryBroadcastReceiver.setBatteryChangedListener(() -> {
60            restartBatteryStatsLoader();
61        });
62
63        getLoaderManager().initLoader(0, icicle, this);
64    }


BatteryStatsHelper的构造函数比较简单,就是初始化一些变量。 

代码路径:/frameworks/base/core/java/com/android/internal/os/BatteryStatsHelper.java
(http://androidxref.com/8.0.0_r4/xref/frameworks/base/core/java/com/android/internal/os/BatteryStatsHelper.java)
172    public BatteryStatsHelper(Context context, boolean collectBatteryBroadcast, boolean wifiOnly) {
173        mContext = context;
174        mCollectBatteryBroadcast = collectBatteryBroadcast;
175        mWifiOnly = wifiOnly;
176        mPackageManager = context.getPackageManager();
177
178        final Resources resources = context.getResources();
179        mSystemPackageArray = resources.getStringArray(
180                com.android.internal.R.array.config_batteryPackageTypeSystem);
181        mServicepackageArray = resources.getStringArray(
182                com.android.internal.R.array.config_batteryPackageTypeService);
183    }

BatteryStatsHelper.create:

代码路径:/frameworks/base/core/java/com/android/internal/os/BatteryStatsHelper.java
(http://androidxref.com/8.0.0_r4/xref/frameworks/base/core/java/com/android/internal/os/BatteryStatsHelper.java)

275    public void create(Bundle icicle) {
276        if (icicle != null) {
277            mStats = sStatsXfer;
278            mBatteryBroadcast = sBatteryBroadcastXfer;
279        }
280        mBatteryInfo = IBatteryStats.Stub.asInterface(
281                ServiceManager.getService(BatteryStats.SERVICE_NAME));//获取BSS的服务端代理
282        mPowerProfile = new PowerProfile(mContext);//读取PowerProfile
283    }

PowerProfile在前文分析BSImpl的构造函数时已经提到过了,主要记录不同硬件模块在不同状态下的耗电量。更新用电量时主要依赖于BatteryStatsHelper的refreshStats函数


4.2 BatteryStatsHelper的refreshStats函数

代码路径:/frameworks/base/core/java/com/android/internal/os/BatteryStatsHelper.java
(http://androidxref.com/8.0.0_r4/xref/frameworks/base/core/java/com/android/internal/os/BatteryStatsHelper.java)

348    public void refreshStats(int statsType, SparseArray<UserHandle> asUsers, long rawRealtimeUs,
349            long rawUptimeUs) {
350        // Initialize mStats if necessary.
351        getStats();//确保获取了BSImp的统计信息
352        //初始化基本的状态
353        mMaxPower = 0;
354        mMaxRealPower = 0;
355        mComputedPower = 0;
356        mTotalPower = 0;
357       //重置相关的列表 
358        mUsageList.clear();
359        mWifiSippers.clear();
360        mBluetoothSippers.clear();
361        mUserSippers.clear();
362        mMobilemsppList.clear();
363
364        if (mStats == null) {
365            return;
366        }
367        //初始化相关的电量计算工具,各种计算工具都继承自PowerCalculator类,用于计算不同模块的耗电量
368        if (mCpuPowerCalculator == null) {
369            mCpuPowerCalculator = new CpuPowerCalculator(mPowerProfile);
370        }
371        mCpuPowerCalculator.reset();
        ............................................
423        //利用BSImpl中的信息,初始化一些变量
424        mStatsType = statsType;
425        mRawUptimeUs = rawUptimeUs;
426        mRawRealtimeUs = rawRealtimeUs;
427        mBatteryUptimeUs = mStats.getBatteryUptime(rawUptimeUs);
428        mBatteryRealtimeUs = mStats.getBatteryRealtime(rawRealtimeUs);
429        mTypeBatteryUptimeUs = mStats.computeBatteryUptime(rawUptimeUs, mStatsType);
430        mTypeBatteryRealtimeUs = mStats.computeBatteryRealtime(rawRealtimeUs, mStatsType);
431        mBatteryTimeRemainingUs = mStats.computeBatteryTimeRemaining(rawRealtimeUs);
432        mChargeTimeRemainingUs = mStats.computeChargeTimeRemaining(rawRealtimeUs);
          .......................................................
446
447        processAppUsage(asUsers);//1、计算各个应用的耗电量
448
         ....................................................
474
475        processMiscUsage();//计算各个模块,除去APP之外消耗的电量
476
477        Collections.sort(mUsageList);//按照耗电量排序
478
479        // At this point, we've sorted the list so we are guaranteed the max values are at the top.
480        // We have only added real powers so far.
481        if (!mUsageList.isEmpty()) {//计算耗电量最大的应用,及整个机器耗电量之和
482            mMaxRealPower = mMaxPower = mUsageList.get(0).totalPowerMah;
483            final int usageListCount = mUsageList.size();
484            for (int i = 0; i < usageListCount; i++) {
485                mComputedPower += mUsageList.get(i).totalPowerMah;
486            }
487        }
488
        .................................................
494        mTotalPower = mComputedPower;
495        if (mStats.getLowDischargeAmountSinceCharge() > 1) {//计算耗电量最大的应用,及整个机器耗电量之和
496            if (mMinDrainedPower > mComputedPower) {//mMinDrainedPower是统计出的电池的实际消耗电量,电池耗电量大于统计的总耗电量
497                double amount = mMinDrainedPower - mComputedPower;//计算差异
498                mTotalPower = mMinDrainedPower;//更新耗电量
499                BatterySipper bs = new BatterySipper(DrainType.UNACCOUNTED, null, amount);//利用差异量,构造一个耗电对象,type为UNACCOUNTED
500
501                // Insert the BatterySipper in its sorted position.
502                int index = Collections.binarySearch(mUsageList, bs);//按大小插入表中,同时更新最大耗电量
503                if (index < 0) {
504                    index = -(index + 1);
505                }
506                mUsageList.add(index, bs);
507                mMaxPower = Math.max(mMaxPower, amount);
508            } else if (mMaxDrainedPower < mComputedPower) {//电池耗电量小于统计的总耗电量
509                double amount = mComputedPower - mMaxDrainedPower;
510
511                // Insert the BatterySipper in its sorted position.
512                BatterySipper bs = new BatterySipper(DrainType.OVERCOUNTED, null, amount);//同样插入一个耗电对象,type为OVERCOUNTED
513                int index = Collections.binarySearch(mUsageList, bs);
514                if (index < 0) {
515                    index = -(index + 1);
516                }
517                mUsageList.add(index, bs);
518                mMaxPower = Math.max(mMaxPower, amount);
519            }
520        }
      ....................................................
536    }
 

refreshStats函数的主要作用就是重新统计终端的耗电量,然后更新自身的存储变量。 进行更新后,创建BatteryStatsHelper的类,就可以调用BatteryStatsHelper的getTotalPower、getUsageList等接口,获取终端耗电信息

4.2.1 processAppUsage 

 refreshStats函数中比较重要的函数是processAppUsage:

代码路径:/frameworks/base/core/java/com/android/internal/os/BatteryStatsHelper.java
(http://androidxref.com/8.0.0_r4/xref/frameworks/base/core/java/com/android/internal/os/BatteryStatsHelper.java)

538    private void processAppUsage(SparseArray<UserHandle> asUsers) {
539        final boolean forAllUsers = (asUsers.get(UserHandle.USER_ALL) != null);
540        mStatsPeriod = mTypeBatteryRealtimeUs;
541
542        BatterySipper osSipper = null;
543        final SparseArray<? extends Uid> uidStats = mStats.getUidStats();//得到BSImpl中的BatteryStatsImpl.Uid对象组成的列表,统计每个uid的耗电信息(主要是时间)
544        final int NU = uidStats.size();
545        for (int iu = 0; iu < NU; iu++) {//循环计算每个应用的耗电量
546            final Uid u = uidStats.valueAt(iu);
547            final BatterySipper app = new BatterySipper(BatterySipper.DrainType.APP, u, 0);
548
549            mCpuPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);//得到该app的占用CPU消耗的电量
550            mWakelockPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);//得到该app的持有WakeLock消耗的电量
551            mMobileRadioPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs,
552                    mStatsType);//得到该app的使用射频消耗的电量
553            mWifiPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);
554            mBluetoothPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs,
555                    mStatsType);
556            mSensorPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);
557            mCameraPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);
558            mFlashlightPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs,
559                    mStatsType);
560
561            final double totalPower = app.sumPower();//计算这个应用耗电量的总和
562            if (DEBUG && totalPower != 0) {
563                Log.d(TAG, String.format("UID %d: total power=%s", u.getUid(),
564                        makemAh(totalPower)));
565            }
566
567            // Add the app to the list if it is consuming power.
568            if (totalPower != 0 || u.getUid() == 0) {
569                //
570                // Add the app to the app list, WiFi, Bluetooth, etc, or into "Other Users" list.
571                //
572                final int uid = app.getUid();//根据应用的类型,将应用耗电量信息添加到对应的列表
573                final int userId = UserHandle.getUserId(uid);
574                if (uid == Process.WIFI_UID) {
575                    mWifiSippers.add(app);
576                } else if (uid == Process.BLUETOOTH_UID) {
577                    mBluetoothSippers.add(app);
578                } else if (!forAllUsers && asUsers.get(userId) == null
579                        && UserHandle.getAppId(uid) >= Process.FIRST_APPLICATION_UID) {
580                    // We are told to just report this user's apps as one large entry.
581                    List<BatterySipper> list = mUserSippers.get(userId);//如果该应用是单独某个用户下的应用则添加的userSippers列表
582                    if (list == null) {
583                        list = new ArrayList<>();
584                        mUserSippers.put(userId, list);
585                    }
586                    list.add(app);
587                } else {
588                    mUsageList.add(app);//否则直接添加到普通的应用列表
589                }
590
591                if (uid == 0) {
592                    osSipper = app;//android系统
593                }
594            }
595        }
596
597        if (osSipper != null) {// 计算os消耗的电量,除去app消耗
598            // The device has probably been awake for longer than the screen on
599            // time and application wake lock time would account for.  Assign
600            // this remainder to the OS, if possible.
601            mWakelockPowerCalculator.calculateRemaining(osSipper, mStats, mRawRealtimeUs,
602                    mRawUptimeUs, mStatsType);
603            osSipper.sumPower();
604        }
605    }

4.2.2 processMiscUsage 

    refreshStats中另一个比较重要的函数processMiscUsage:

代码路径:/frameworks/base/core/java/com/android/internal/os/BatteryStatsHelper.java
(http://androidxref.com/8.0.0_r4/xref/frameworks/base/core/java/com/android/internal/os/BatteryStatsHelper.java)

737    private void processMiscUsage() {
738        addUserUsage();
739        addPhoneUsage();
740        addScreenUsage();
741        addWiFiUsage();
742        addBluetoothUsage();
743        addMemoryUsage();
744        addIdleUsage(); // Not including cellular idle power
745        // Don't compute radio usage if it's a wifi-only device
746        if (!mWifiOnly) {
747            addRadioUsage();
748        }
749    }

processMiscUsage中使用的几个函数,也是用于计算工具统计每个模块的耗电量。 但与processAppUsage统计的侧重点不一样。  

Android将一个模块的电量粗略分为两种。 一种是app在实际使用模块,引起的耗电量;一种是没有app调用,只要开启就会消耗的电量。 例如:WiFi只要开启,不论是否有app利用WiFi上网,WiFi都需要进行CSMA,因此会有基础的电量消耗。

4.2.3 计算方法举例 

以数据业务相关的MobileRadioPowerCalculator为例,看看计算工具到底是如何工作的。
代码路径:/frameworks/base/core/java/com/android/internal/os/MobileRadioPowerCalculator.java
(http://androidxref.com/8.0.0_r4/xref/frameworks/base/core/java/com/android/internal/os/MobileRadioPowerCalculator.java)

22public class MobileRadioPowerCalculator extends PowerCalculator {//从PowerProfile下,得到各种场景的单位耗电量
      .............................................................
52    public MobileRadioPowerCalculator(PowerProfile profile, BatteryStats stats) {
53        mPowerRadioOn = profile.getAveragePower(PowerProfile.POWER_RADIO_ACTIVE);//radio on时的单位耗电量
54        for (int i = 0; i < mPowerBins.length; i++) { //各种信号强度下的单位耗电量
55            mPowerBins[i] = profile.getAveragePower(PowerProfile.POWER_RADIO_ON, i);
56        }
57        mPowerScan = profile.getAveragePower(PowerProfile.POWER_RADIO_SCANNING);//搜网时的单位耗电量
58        mStats = stats;
59    }
60
61    @Override
62    public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
63                             long rawUptimeUs, int statsType) {
64        // Add cost of mobile traffic.
65        app.mobileRxPackets = u.getNetworkActivityPackets(BatteryStats.NETWORK_MOBILE_RX_DATA,
66                statsType);//得到APP利用mobile发送分组的数量
67        app.mobileTxPackets = u.getNetworkActivityPackets(BatteryStats.NETWORK_MOBILE_TX_DATA,
68                statsType);
69        app.mobileActive = u.getMobileRadioActiveTime(statsType) / 1000;//得到APP在mobile active时的运行时间
70        app.mobileActiveCount = u.getMobileRadioActiveCount(statsType);
71        app.mobileRxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_MOBILE_RX_DATA,
72                statsType);//得到APP利用mobile发送字节的数量
73        app.mobileTxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_MOBILE_TX_DATA,
74                statsType);
75
76        if (app.mobileActive > 0) {
77            // We are tracking when the radio is up, so can use the active time to
78            // determine power use.
79            mTotalAppMobileActiveMs += app.mobileActive;//总体时间
80            app.mobileRadioPowerMah = (app.mobileActive * mPowerRadioOn) / (1000*60*60);//运行时间 * 单位耗电量 得到整体的耗电情况
81        } else {
82            // We are not tracking when the radio is up, so must approximate power use
83            // based on the number of packets.
84            app.mobileRadioPowerMah = (app.mobileRxPackets + app.mobileTxPackets)
85                    * getMobilePowerPerPacket(rawRealtimeUs, statsType);//mobile处于active时,app并没有运行,利用整体的收发包数量得到耗电量
86        }
87        if (DEBUG && app.mobileRadioPowerMah != 0) {
88            Log.d(TAG, "UID " + u.getUid() + ": mobile packets "
89                    + (app.mobileRxPackets + app.mobileTxPackets)
90                    + " active time " + app.mobileActive
91                    + " power=" + BatteryStatsHelper.makemAh(app.mobileRadioPowerMah));
92        }
93    }
94
95    @Override
96    public void calculateRemaining(BatterySipper app, BatteryStats stats, long rawRealtimeUs,
97                                   long rawUptimeUs, int statsType) {
98        double power = 0;
99        long signalTimeMs = 0;
100        long noCoverageTimeMs = 0;
101        for (int i = 0; i < mPowerBins.length; i++) {
102            long strengthTimeMs = stats.getPhoneSignalStrengthTime(i, rawRealtimeUs, statsType)
103                    / 1000;
104            final double p = (strengthTimeMs * mPowerBins[i]) / (60*60*1000);//计算处于每个信号强度下的耗电量
105            if (DEBUG && p != 0) {
106                Log.d(TAG, "Cell strength #" + i + ": time=" + strengthTimeMs + " power="
107                        + BatteryStatsHelper.makemAh(p));
108            }
109            power += p;//累加
110            signalTimeMs += strengthTimeMs;//整体的统计时间
111            if (i == 0) {
112                noCoverageTimeMs = strengthTimeMs;//无信号时间
113            }
114        }
115
116        final long scanningTimeMs = stats.getPhoneSignalScanningTime(rawRealtimeUs, statsType)
117                / 1000;//计算出搜网的耗电量
118        final double p = (scanningTimeMs * mPowerScan) / (60*60*1000);
119        if (DEBUG && p != 0) {
120            Log.d(TAG, "Cell radio scanning: time=" + scanningTimeMs
121                    + " power=" + BatteryStatsHelper.makemAh(p));
122        }
123        power += p;
124        long radioActiveTimeMs = mStats.getMobileRadioActiveTime(rawRealtimeUs, statsType) / 1000;//计算出radio on,但app未使用时段的基础耗电量
125        long remainingActiveTimeMs = radioActiveTimeMs - mTotalAppMobileActiveMs;
126        if (remainingActiveTimeMs > 0) {
127            power += (mPowerRadioOn * remainingActiveTimeMs) / (1000*60*60);
128        }
129
130        if (power != 0) { //将计算的结果保存在app对应的BatterySipper中
131            if (signalTimeMs != 0) {
132                app.noCoveragePercent = noCoverageTimeMs * 100.0 / signalTimeMs;
133            }
134            app.mobileActive = remainingActiveTimeMs;
135            app.mobileActiveCount = stats.getMobileRadioActiveUnknownCount(statsType);
136            app.mobileRadioPowerMah = power;
137        }
138    }
139
140    @Override
141    public void reset() {
142        mTotalAppMobileActiveMs = 0;
143    }
144
145    public void reset(BatteryStats stats) {
146        reset();
147        mStats = stats;
148    }
149}

Android将一个模块的电量粗略分为两种。 一种是app在实际使用模块,引起的耗电量;一种是没有app调用,只要开启就会消耗的电量。 对于数据业务而言: app在进行实际的收发数据,那么这部分电量就是app引起的耗电量。终端维持一定的信号强度消耗的电量;搜网消耗的电量;打开数据开关,但没有数据收发时消耗的电量,统称为基础耗电量。

5、BSS的setBatteryState函数 

代码路径:/frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
(http://androidxref.com/8.0.0_r4/xref/frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java)

1030    public void setBatteryState(final int status, final int health, final int plugType,
1031            final int level, final int temp, final int volt, final int chargeUAh,
1032            final int chargeFullUAh) {
1033        enforceCallingPermission();
1034
1035        // BatteryService calls us here and we may update external state. It would be wrong
1036        // to block such a low level service like BatteryService on external stats like WiFi.
1037        mHandler.post(new Runnable() {
1038            @Override
1039            public void run() {
1040                synchronized (mStats) {//判断是否充电
1041                    final boolean onBattery = plugType == BatteryStatsImpl.BATTERY_PLUGGED_NONE;
1042                    if (mStats.isOnBattery() == onBattery) {
1043                        // The battery state has not changed, so we don't need to sync external
1044                        // stats immediately.
1045                        mStats.setBatteryStateLocked(status, health, plugType, level, temp, volt,
1046                                chargeUAh, chargeFullUAh);//充电状态未改变,仅做记录
1047                        return;
1048                    }
1049                }
1050
1051                // Sync external stats first as the battery has changed states. If we don't sync
1052                // immediately here, we may not collect the relevant data later.
1053                updateExternalStatsSync("battery-state", BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL);//充电状态改变,则先同步WIFI、BT等的信息
1054                synchronized (mStats) {
1055                    mStats.setBatteryStateLocked(status, health, plugType, level, temp, volt,
1056                            chargeUAh, chargeFullUAh);
1057                }
1058            }
1059        });
1060    }


实际的记录工作还是依赖于BSImpl的setBatteryStateLocked函数

代码路径:/frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
(http://androidxref.com/8.0.0_r4/xref/frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java)

10553    public void setBatteryStateLocked(int status, int health, int plugType, int level,
10554            int temp, int volt, int chargeUAh, int chargeFullUAh) {
10555        // Temperature is encoded without the signed bit, so clamp any negative temperatures to 0.
10556        temp = Math.max(0, temp);
10557
10558        final boolean onBattery = plugType == BATTERY_PLUGGED_NONE;//判断当前是否是电池供电(即是否没有插着充电器)
10559        final long uptime = mClocks.uptimeMillis();
10560        final long elapsedRealtime = mClocks.elapsedRealtime();
10561        if (!mHaveBatteryLevel) {
10562            mHaveBatteryLevel = true;
10563            // We start out assuming that the device is plugged in (not
10564            // on battery).  If our first report is now that we are indeed
10565            // plugged in, then twiddle our state to correctly reflect that
10566            // since we won't be going through the full setOnBattery().
10567            if (onBattery == mOnBattery) {
10568                if (onBattery) {
10569                    mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
10570                } else {
10571                    mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
10572                }
10573            }
10574            // Always start out assuming charging, that will be updated later.
10575            mHistoryCur.states2 |= HistoryItem.STATE2_CHARGING_FLAG;
10576            mHistoryCur.batteryStatus = (byte)status;
10577            mHistoryCur.batteryLevel = (byte)level;
10578            mHistoryCur.batteryChargeUAh = chargeUAh;
10579            mMaxChargeStepLevel = mMinDischargeStepLevel =
10580                    mLastChargeStepLevel = mLastDischargeStepLevel = level;
10581            mLastChargingStateLevel = level;
10582        } else if (mCurrentBatteryLevel != level || mOnBattery != onBattery) {
10583            recordDailyStatsIfNeededLocked(level >= 100 && onBattery);
10584        }
10585        int oldStatus = mHistoryCur.batteryStatus;
10586        if (onBattery) {//如果是电池供电,则记录下当前的未充电的电量
10587            mDischargeCurrentLevel = level;
10588            if (!mRecordingHistory) {
10589                mRecordingHistory = true;
10590                startRecordingHistory(elapsedRealtime, uptime, true);//将当前的电池状态添加到历史记录
10591            }
10592        } else if (level < 96) {//充电但电量低于96%,同时没有记录过
10593            if (!mRecordingHistory) {
10594                mRecordingHistory = true;
10595                startRecordingHistory(elapsedRealtime, uptime, true);
10596            }
10597        }
10598        mCurrentBatteryLevel = level;
10599        if (mDischargePlugLevel < 0) {
10600            mDischargePlugLevel = level;
10601        }
10602
10603        if (onBattery != mOnBattery) {//充电状态发生改变,进行一些历史信息记录
10604            mHistoryCur.batteryLevel = (byte)level;
10605            mHistoryCur.batteryStatus = (byte)status;
10606            mHistoryCur.batteryHealth = (byte)health;
10607            mHistoryCur.batteryPlugType = (byte)plugType;
10608            mHistoryCur.batteryTemperature = (short)temp;
10609            mHistoryCur.batteryVoltage = (char)volt;
10610            if (chargeUAh < mHistoryCur.batteryChargeUAh) {
10611                // Only record discharges
10612                final long chargeDiff = mHistoryCur.batteryChargeUAh - chargeUAh;
10613                mDischargeCounter.addCountLocked(chargeDiff);
10614                mDischargeScreenOffCounter.addCountLocked(chargeDiff);
10615            }
10616            mHistoryCur.batteryChargeUAh = chargeUAh;
10617            setOnBatteryLocked(elapsedRealtime, uptime, onBattery, oldStatus, level, chargeUAh);//setOnBatteryLocked执行充电状态发生变化的逻辑
10618        } else {
10619            boolean changed = false;//判断电池信息是否发生变化,变化时将changed置为true
10620            if (mHistoryCur.batteryLevel != level) {
10621                mHistoryCur.batteryLevel = (byte)level;
10622                changed = true;
10623
10624                // TODO(adamlesinski): Schedule the creation of a HistoryStepDetails record
10625                // which will pull external stats.
10626                scheduleSyncExternalStatsLocked("battery-level", ExternalStatsSync.UPDATE_ALL);
10627            }
10628            ......................................................
10710            if (changed) {
10711                addHistoryRecordLocked(elapsedRealtime, uptime);//如果电量信息发生变化,就将当前的状态添加到历史记录中
10712            }
10713        }
10714        if (!onBattery && status == BatteryManager.BATTERY_STATUS_FULL) {
10715            // We don't record history while we are plugged in and fully charged.
10716            // The next time we are unplugged, history will be cleared.
10717            mRecordingHistory = DEBUG;
10718        }
10719
10720        if (mMinLearnedBatteryCapacity == -1) {
10721            mMinLearnedBatteryCapacity = chargeFullUAh;
10722        } else {
10723            Math.min(mMinLearnedBatteryCapacity, chargeFullUAh);
10724        }
10725        mMaxLearnedBatteryCapacity = Math.max(mMaxLearnedBatteryCapacity, chargeFullUAh);
10726    }


setBatteryStateLocked函数: 首先判断供电状态是否发生了变化,如果发生变化,则调用setOnBatteryLocked进行处理;如果供电状态没有发生变化,则判断当前电池的各种信息是否发生变化。如果发生了变化,就将当前的电池信息添加到历史记录中。

setOnBatteryLocked相关的代码:

代码路径:/frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
(http://androidxref.com/8.0.0_r4/xref/frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java)

10388    void setOnBatteryLocked(final long mSecRealtime, final long mSecUptime, final boolean onBattery,
10389            final int oldStatus, final int level, final int chargeUAh) {
10390        boolean doWrite = false;
10391        Message m = mHandler.obtainMessage(MSG_REPORT_POWER_CHANGE);//触发回调
10392        m.arg1 = onBattery ? 1 : 0;
10393        mHandler.sendMessage(m);
10394
10395        final long uptime = mSecUptime * 1000;
10396        final long realtime = mSecRealtime * 1000;
10397        final boolean screenOn = mScreenState == Display.STATE_ON;
10398        if (onBattery) {
10399            // We will reset our status if we are unplugging after the
10400            // battery was last full, or the level is at 100, or
10401            // we have gone through a significant charge (from a very low
10402            // level to a now very high level).
10403            boolean reset = false;
           //如果拔去充电器的时候电量是满的,或当前电量大于90,或从一个很低的电量充电到很高的电量,或电量历史记录的数据太大
10404            if (!mNoAutoReset && (oldStatus == BatteryManager.BATTERY_STATUS_FULL
10405                    || level >= 90
10406                    || (mDischargeCurrentLevel < 20 && level >= 80)
10407                    || (getHighDischargeAmountSinceCharge() >= 200
10408                            && mHistoryBuffer.dataSize() >= MAX_HISTORY_BUFFER))) {
10409                Slog.i(TAG, "Resetting battery stats: level=" + level + " status=" + oldStatus
10410                        + " dischargeLevel=" + mDischargeCurrentLevel
10411                        + " lowAmount=" + getLowDischargeAmountSinceCharge()
10412                        + " highAmount=" + getHighDischargeAmountSinceCharge());
10413                // Before we write, collect a snapshot of the final aggregated
10414                // stats to be reported in the next checkin.  Only do this if we have
10415                // a sufficient amount of data to make it interesting.
10416                if (getLowDischargeAmountSinceCharge() >= 20) {//变化的信息的数据足够时(累积耗电量足够大),生成一个snapshot,写入到mCheckinFile中
10417                    final Parcel parcel = Parcel.obtain();
10418                    writeSummaryToParcel(parcel, true);
10419                    BackgroundThread.getHandler().post(new Runnable() {
10420                        @Override public void run() {
10421                            synchronized (mCheckinFile) {
10422                                FileOutputStream stream = null;
10423                                try {
10424                                    stream = mCheckinFile.startWrite();
10425                                    stream.write(parcel.marshall());
10426                                    stream.flush();
10427                                    FileUtils.sync(stream);
10428                                    stream.close();
10429                                    mCheckinFile.finishWrite(stream);
10430                                } catch (IOException e) {
10431                                    Slog.w("BatteryStats",
10432                                            "Error writing checkin battery statistics", e);
10433                                    mCheckinFile.failWrite(stream);
10434                                } finally {
10435                                    parcel.recycle();
10436                                }
10437                            }
10438                        }
10439                    });
10440                }
10441                doWrite = true;
10442                resetAllStatsLocked();//重置电量统计的相关信息,清除当前的电量统计
10443                if (chargeUAh > 0 && level > 0) {
10444                    // Only use the reported coulomb charge value if it is supported and reported.
10445                    mEstimatedBatteryCapacity = (int) ((chargeUAh / 1000) / (level / 100.0));
10446                }
10447                mDischargeStartLevel = level;
10448                reset = true;
10449                mDischargeStepTracker.init();
10450            }
10451            if (mCharging) {
10452                setChargingLocked(false);
10453            }
10454            mLastChargingStateLevel = level;
10455            mOnBattery = mOnBatteryInternal = true;
10456            mLastDischargeStepLevel = level;
10457            mMinDischargeStepLevel = level;
10458            mDischargeStepTracker.clearTime();
10459            mDailyDischargeStepTracker.clearTime();
10460            mInitStepMode = mCurStepMode;
10461            mModStepMode = 0;
10462            pullPendingStateUpdatesLocked();
10463            mHistoryCur.batteryLevel = (byte)level;
10464            mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
10465            if (DEBUG_HISTORY) Slog.v(TAG, "Battery unplugged to: "
10466                    + Integer.toHexString(mHistoryCur.states));
10467            if (reset) {
10468                mRecordingHistory = true;
10469                startRecordingHistory(mSecRealtime, mSecUptime, reset);
10470            }
10471            addHistoryRecordLocked(mSecRealtime, mSecUptime);
10472            mDischargeCurrentLevel = mDischargeUnplugLevel = level;//由充电变为不充电,记录下变成不充电状态时的电量
10473            if (screenOn) {
10474                mDischargeScreenOnUnplugLevel = level;
10475                mDischargeScreenOffUnplugLevel = 0;
10476            } else {
10477                mDischargeScreenOnUnplugLevel = 0;
10478                mDischargeScreenOffUnplugLevel = level;
10479            }
10480            mDischargeAmountScreenOn = 0;
10481            mDischargeAmountScreenOff = 0;
10482            updateTimeBasesLocked(true, !screenOn, uptime, realtime);//更新TimeBase,和电量统计计时器有关
10483        } else {
10484            mLastChargingStateLevel = level;
10485            mOnBattery = mOnBatteryInternal = false;
10486            pullPendingStateUpdatesLocked();
10487            mHistoryCur.batteryLevel = (byte)level;
10488            mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
10489            if (DEBUG_HISTORY) Slog.v(TAG, "Battery plugged to: "
10490                    + Integer.toHexString(mHistoryCur.states));
10491            addHistoryRecordLocked(mSecRealtime, mSecUptime);
10492            mDischargeCurrentLevel = mDischargePlugLevel = level;//记录变成充电状态时的电量
10493            if (level < mDischargeUnplugLevel) {//当前电量低于断开电源时的电量,表示电量消耗了
10494                mLowDischargeAmountSinceCharge += mDischargeUnplugLevel-level-1;//记录下电池用电时的电量消耗
10495                mHighDischargeAmountSinceCharge += mDischargeUnplugLevel-level;
10496            }
10497            updateDischargeScreenLevelsLocked(screenOn, screenOn);
10498            updateTimeBasesLocked(false, !screenOn, uptime, realtime);//更新TimeBase,和电量统计计时器有关
10499            mChargeStepTracker.init();
10500            mLastChargeStepLevel = level;
10501            mMaxChargeStepLevel = level;
10502            mInitStepMode = mCurStepMode;
10503            mModStepMode = 0;
10504        }
10505        if (doWrite || (mLastWriteTime + (60 * 1000)) < mSecRealtime) {//从充电变为未充电,或写入的间隔够大
10506            if (mFile != null) {
10507                writeAsyncLocked();//将信息写入到BatteryStats.bin中
10508            }
10509        }
10510    }
10511

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值