blob: 9e8f06d994f07c65691e28f4f703d1d7bfadcb89 [file] [log] [blame]
Adam Lesinskie08af192015-03-25 16:42:59 -07001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package com.android.internal.os;
17
18import android.os.BatteryStats;
19import android.telephony.SignalStrength;
20import android.util.Log;
21
22public class MobileRadioPowerCalculator extends PowerCalculator {
23 private static final String TAG = "MobileRadioPowerController";
24 private static final boolean DEBUG = BatteryStatsHelper.DEBUG;
25 private final double mPowerRadioOn;
26 private final double[] mPowerBins = new double[SignalStrength.NUM_SIGNAL_STRENGTH_BINS];
27 private final double mPowerScan;
28 private BatteryStats mStats;
29 private long mTotalAppMobileActiveMs = 0;
30
31 /**
32 * Return estimated power (in mAs) of sending or receiving a packet with the mobile radio.
33 */
34 private double getMobilePowerPerPacket(long rawRealtimeUs, int statsType) {
35 final long MOBILE_BPS = 200000; // TODO: Extract average bit rates from system
36 final double MOBILE_POWER = mPowerRadioOn / 3600;
37
38 final long mobileRx = mStats.getNetworkActivityPackets(BatteryStats.NETWORK_MOBILE_RX_DATA,
39 statsType);
40 final long mobileTx = mStats.getNetworkActivityPackets(BatteryStats.NETWORK_MOBILE_TX_DATA,
41 statsType);
42 final long mobileData = mobileRx + mobileTx;
43
44 final long radioDataUptimeMs =
45 mStats.getMobileRadioActiveTime(rawRealtimeUs, statsType) / 1000;
46 final double mobilePps = (mobileData != 0 && radioDataUptimeMs != 0)
47 ? (mobileData / (double)radioDataUptimeMs)
48 : (((double)MOBILE_BPS) / 8 / 2048);
49 return (MOBILE_POWER / mobilePps) / (60*60);
50 }
51
52 public MobileRadioPowerCalculator(PowerProfile profile, BatteryStats stats) {
Hui Yu39b29bc2018-05-23 14:39:24 -070053 double temp =
54 profile.getAveragePowerOrDefault(PowerProfile.POWER_RADIO_ACTIVE, -1);
55 if (temp != -1) {
56 mPowerRadioOn = temp;
57 } else {
58 double sum = 0;
59 sum += profile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_RX);
60 for (int i = 0; i < mPowerBins.length; i++) {
61 sum += profile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_TX, i);
62 }
63 mPowerRadioOn = sum / (mPowerBins.length + 1);
Adam Lesinskie08af192015-03-25 16:42:59 -070064 }
Hui Yu39b29bc2018-05-23 14:39:24 -070065
66 temp = profile.getAveragePowerOrDefault(PowerProfile.POWER_RADIO_ON, -1);
67 if (temp != -1 ) {
68 for (int i = 0; i < mPowerBins.length; i++) {
69 mPowerBins[i] = profile.getAveragePower(PowerProfile.POWER_RADIO_ON, i);
70 }
71 } else {
72 double idle = profile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_IDLE);
73 mPowerBins[0] = idle * 25 / 180;
74 for (int i = 1; i < mPowerBins.length; i++) {
75 mPowerBins[i] = Math.max(1, idle / 256);
76 }
77 }
78
79 mPowerScan = profile.getAveragePowerOrDefault(PowerProfile.POWER_RADIO_SCANNING, 0);
Adam Lesinskie08af192015-03-25 16:42:59 -070080 mStats = stats;
81 }
82
83 @Override
84 public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
85 long rawUptimeUs, int statsType) {
86 // Add cost of mobile traffic.
87 app.mobileRxPackets = u.getNetworkActivityPackets(BatteryStats.NETWORK_MOBILE_RX_DATA,
88 statsType);
89 app.mobileTxPackets = u.getNetworkActivityPackets(BatteryStats.NETWORK_MOBILE_TX_DATA,
90 statsType);
91 app.mobileActive = u.getMobileRadioActiveTime(statsType) / 1000;
92 app.mobileActiveCount = u.getMobileRadioActiveCount(statsType);
93 app.mobileRxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_MOBILE_RX_DATA,
94 statsType);
95 app.mobileTxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_MOBILE_TX_DATA,
96 statsType);
97
98 if (app.mobileActive > 0) {
99 // We are tracking when the radio is up, so can use the active time to
100 // determine power use.
101 mTotalAppMobileActiveMs += app.mobileActive;
102 app.mobileRadioPowerMah = (app.mobileActive * mPowerRadioOn) / (1000*60*60);
103 } else {
104 // We are not tracking when the radio is up, so must approximate power use
105 // based on the number of packets.
106 app.mobileRadioPowerMah = (app.mobileRxPackets + app.mobileTxPackets)
107 * getMobilePowerPerPacket(rawRealtimeUs, statsType);
108 }
109 if (DEBUG && app.mobileRadioPowerMah != 0) {
110 Log.d(TAG, "UID " + u.getUid() + ": mobile packets "
111 + (app.mobileRxPackets + app.mobileTxPackets)
112 + " active time " + app.mobileActive
113 + " power=" + BatteryStatsHelper.makemAh(app.mobileRadioPowerMah));
114 }
115 }
116
117 @Override
118 public void calculateRemaining(BatterySipper app, BatteryStats stats, long rawRealtimeUs,
119 long rawUptimeUs, int statsType) {
120 double power = 0;
121 long signalTimeMs = 0;
122 long noCoverageTimeMs = 0;
123 for (int i = 0; i < mPowerBins.length; i++) {
124 long strengthTimeMs = stats.getPhoneSignalStrengthTime(i, rawRealtimeUs, statsType)
125 / 1000;
126 final double p = (strengthTimeMs * mPowerBins[i]) / (60*60*1000);
127 if (DEBUG && p != 0) {
128 Log.d(TAG, "Cell strength #" + i + ": time=" + strengthTimeMs + " power="
129 + BatteryStatsHelper.makemAh(p));
130 }
131 power += p;
132 signalTimeMs += strengthTimeMs;
133 if (i == 0) {
134 noCoverageTimeMs = strengthTimeMs;
135 }
136 }
137
138 final long scanningTimeMs = stats.getPhoneSignalScanningTime(rawRealtimeUs, statsType)
139 / 1000;
140 final double p = (scanningTimeMs * mPowerScan) / (60*60*1000);
141 if (DEBUG && p != 0) {
142 Log.d(TAG, "Cell radio scanning: time=" + scanningTimeMs
143 + " power=" + BatteryStatsHelper.makemAh(p));
144 }
145 power += p;
146 long radioActiveTimeMs = mStats.getMobileRadioActiveTime(rawRealtimeUs, statsType) / 1000;
147 long remainingActiveTimeMs = radioActiveTimeMs - mTotalAppMobileActiveMs;
148 if (remainingActiveTimeMs > 0) {
149 power += (mPowerRadioOn * remainingActiveTimeMs) / (1000*60*60);
150 }
151
152 if (power != 0) {
Adam Lesinskid9b48d52015-05-05 19:19:00 -0700153 if (signalTimeMs != 0) {
154 app.noCoveragePercent = noCoverageTimeMs * 100.0 / signalTimeMs;
155 }
Adam Lesinskie08af192015-03-25 16:42:59 -0700156 app.mobileActive = remainingActiveTimeMs;
157 app.mobileActiveCount = stats.getMobileRadioActiveUnknownCount(statsType);
158 app.mobileRadioPowerMah = power;
159 }
160 }
161
162 @Override
163 public void reset() {
164 mTotalAppMobileActiveMs = 0;
165 }
166
167 public void reset(BatteryStats stats) {
168 reset();
169 mStats = stats;
170 }
171}