Proportionally attribute Mobile Radio Energy Consumption to Phone usage.

Proportionally split out the energy consumption of phone usage from the
rest of the mobile radio energy consumption.

Fixes: 244603408
Test: atest MobileRadioPowerCalculator
Change-Id: I5db49ea7c88cfd502db36265ae5a6555f728d2f7
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 547d406..083b4f6 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -2904,6 +2904,15 @@
     public abstract long getMobileRadioEnergyConsumptionUC();
 
     /**
+     * Returns the battery consumption (in microcoulombs) of the phone calls, derived from on device
+     * power measurement data.
+     * Will return {@link #POWER_DATA_UNAVAILABLE} if data is unavailable.
+     *
+     * {@hide}
+     */
+    public abstract long getPhoneEnergyConsumptionUC();
+
+    /**
      * Returns the battery consumption (in microcoulombs) of the screen while on, derived from on
      * device power measurement data.
      * Will return {@link #POWER_DATA_UNAVAILABLE} if data is unavailable.
diff --git a/core/java/com/android/internal/power/EnergyConsumerStats.java b/core/java/com/android/internal/power/EnergyConsumerStats.java
index 8cf17cda..e2098dd 100644
--- a/core/java/com/android/internal/power/EnergyConsumerStats.java
+++ b/core/java/com/android/internal/power/EnergyConsumerStats.java
@@ -59,7 +59,8 @@
     public static final int POWER_BUCKET_GNSS = 6;
     public static final int POWER_BUCKET_MOBILE_RADIO = 7;
     public static final int POWER_BUCKET_CAMERA = 8;
-    public static final int NUMBER_STANDARD_POWER_BUCKETS = 9; // Buckets above this are custom.
+    public static final int POWER_BUCKET_PHONE = 9;
+    public static final int NUMBER_STANDARD_POWER_BUCKETS = 10; // Buckets above this are custom.
 
     @IntDef(prefix = {"POWER_BUCKET_"}, value = {
             POWER_BUCKET_UNKNOWN,
@@ -72,6 +73,7 @@
             POWER_BUCKET_GNSS,
             POWER_BUCKET_MOBILE_RADIO,
             POWER_BUCKET_CAMERA,
+            POWER_BUCKET_PHONE,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface StandardPowerBucket {
diff --git a/services/core/java/com/android/server/power/stats/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/power/stats/BatteryExternalStatsWorker.java
index 3fcb08a5..2fbf3fb 100644
--- a/services/core/java/com/android/server/power/stats/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/power/stats/BatteryExternalStatsWorker.java
@@ -900,6 +900,7 @@
                     break;
                 case EnergyConsumerType.MOBILE_RADIO:
                     buckets[EnergyConsumerStats.POWER_BUCKET_MOBILE_RADIO] = true;
+                    buckets[EnergyConsumerStats.POWER_BUCKET_PHONE] = true;
                     break;
                 case EnergyConsumerType.DISPLAY:
                     buckets[EnergyConsumerStats.POWER_BUCKET_SCREEN_ON] = true;
diff --git a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
index f9482dd..2fb5cec 100644
--- a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
+++ b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
@@ -178,7 +178,7 @@
     // TODO: remove "tcp" from network methods, since we measure total stats.
 
     // Current on-disk Parcel version. Must be updated when the format of the parcelable changes
-    public static final int VERSION = 211;
+    public static final int VERSION = 212;
 
     // The maximum number of names wakelocks we will keep track of
     // per uid; once the limit is reached, we batch the remaining wakelocks
@@ -5740,6 +5740,9 @@
                     HistoryItem.STATE2_PHONE_IN_CALL_FLAG);
             mPhoneOn = true;
             mPhoneOnTimer.startRunningLocked(elapsedRealtimeMs);
+            if (mConstants.PHONE_ON_EXTERNAL_STATS_COLLECTION) {
+                scheduleSyncExternalStatsLocked("phone-on", ExternalStatsSync.UPDATE_RADIO);
+            }
         }
     }
 
@@ -5750,6 +5753,7 @@
                     HistoryItem.STATE2_PHONE_IN_CALL_FLAG);
             mPhoneOn = false;
             mPhoneOnTimer.stopRunningLocked(elapsedRealtimeMs);
+            scheduleSyncExternalStatsLocked("phone-off", ExternalStatsSync.UPDATE_RADIO);
         }
     }
 
@@ -7425,6 +7429,12 @@
 
     @GuardedBy("this")
     @Override
+    public long getPhoneEnergyConsumptionUC() {
+        return getPowerBucketConsumptionUC(EnergyConsumerStats.POWER_BUCKET_PHONE);
+    }
+
+    @GuardedBy("this")
+    @Override
     public long getScreenOnEnergyConsumptionUC() {
         return getPowerBucketConsumptionUC(EnergyConsumerStats.POWER_BUCKET_SCREEN_ON);
     }
@@ -12051,17 +12061,36 @@
         }
 
         synchronized (this) {
+            final long totalRadioDurationMs =
+                    mMobileRadioActiveTimer.getTimeSinceMarkLocked(
+                            elapsedRealtimeMs * 1000) / 1000;
+            mMobileRadioActiveTimer.setMark(elapsedRealtimeMs);
+            final long phoneOnDurationMs = Math.min(totalRadioDurationMs,
+                    mPhoneOnTimer.getTimeSinceMarkLocked(elapsedRealtimeMs * 1000) / 1000);
+            mPhoneOnTimer.setMark(elapsedRealtimeMs);
+
             if (!mOnBatteryInternal || mIgnoreNextExternalStats) {
                 return;
             }
 
             final SparseDoubleArray uidEstimatedConsumptionMah;
+            final long dataConsumedChargeUC;
             if (consumedChargeUC > 0 && isMobileRadioEnergyConsumerSupportedLocked()) {
+                // Crudely attribute power consumption. Added (totalRadioDurationMs / 2) to the
+                // numerator for long rounding.
+                final long phoneConsumedChargeUC =
+                        (consumedChargeUC * phoneOnDurationMs + totalRadioDurationMs / 2)
+                                / totalRadioDurationMs;
+                dataConsumedChargeUC = consumedChargeUC - phoneConsumedChargeUC;
+
                 mGlobalEnergyConsumerStats.updateStandardBucket(
-                        EnergyConsumerStats.POWER_BUCKET_MOBILE_RADIO, consumedChargeUC);
+                        EnergyConsumerStats.POWER_BUCKET_PHONE, phoneConsumedChargeUC);
+                mGlobalEnergyConsumerStats.updateStandardBucket(
+                        EnergyConsumerStats.POWER_BUCKET_MOBILE_RADIO, dataConsumedChargeUC);
                 uidEstimatedConsumptionMah = new SparseDoubleArray();
             } else {
                 uidEstimatedConsumptionMah = null;
+                dataConsumedChargeUC = POWER_DATA_UNAVAILABLE;
             }
 
             RxTxConsumption rxTxConsumption = null;
@@ -12250,13 +12279,9 @@
                         totalEstimatedConsumptionMah += rxTxConsumption.txConsumptionMah;
                     } else {
                         // Estimate total active radio power consumption since last mark.
-                        final long totalRadioTimeMs =
-                                mMobileRadioActiveTimer.getTimeSinceMarkLocked(
-                                        elapsedRealtimeMs * 1000) / 1000;
-                        mMobileRadioActiveTimer.setMark(elapsedRealtimeMs);
                         totalEstimatedConsumptionMah +=
                                 mMobileRadioPowerCalculator.calcPowerFromRadioActiveDurationMah(
-                                        totalRadioTimeMs);
+                                        totalRadioDurationMs);
 
                         // Estimate idle power consumption at each signal strength level
                         final int numSignalStrengthLevels = mPhoneSignalStrengthsTimer.length;
@@ -12279,7 +12304,7 @@
                                 mMobileRadioPowerCalculator.calcScanTimePowerMah(scanTimeMs);
                     }
                     distributeEnergyToUidsLocked(EnergyConsumerStats.POWER_BUCKET_MOBILE_RADIO,
-                            consumedChargeUC, uidEstimatedConsumptionMah,
+                            dataConsumedChargeUC, uidEstimatedConsumptionMah,
                             totalEstimatedConsumptionMah, elapsedRealtimeMs);
                 }
             }
@@ -15041,6 +15066,8 @@
                 "record_usage_history";
         public static final String KEY_PER_UID_MODEM_POWER_MODEL =
                 "per_uid_modem_power_model";
+        public static final String KEY_PHONE_ON_EXTERNAL_STATS_COLLECTION =
+                "phone_on_external_stats_collection";
 
         public static final String PER_UID_MODEM_POWER_MODEL_MOBILE_RADIO_ACTIVE_TIME_NAME =
                 "mobile_radio_active_time";
@@ -15089,6 +15116,7 @@
         @PerUidModemPowerModel
         private static final int DEFAULT_PER_UID_MODEM_MODEL =
                 PER_UID_MODEM_POWER_MODEL_MODEM_ACTIVITY_INFO_RX_TX;
+        private static final boolean DEFAULT_PHONE_ON_EXTERNAL_STATS_COLLECTION = true;
 
         public boolean TRACK_CPU_ACTIVE_CLUSTER_TIME = DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME;
         /* Do not set default value for KERNEL_UID_READERS_THROTTLE_TIME. Need to trigger an
@@ -15106,6 +15134,8 @@
         public int BATTERY_CHARGED_DELAY_MS = DEFAULT_BATTERY_CHARGED_DELAY_MS;
         public boolean RECORD_USAGE_HISTORY = DEFAULT_RECORD_USAGE_HISTORY;
         public int PER_UID_MODEM_MODEL = DEFAULT_PER_UID_MODEM_MODEL;
+        public boolean PHONE_ON_EXTERNAL_STATS_COLLECTION =
+                DEFAULT_PHONE_ON_EXTERNAL_STATS_COLLECTION;
 
         private ContentResolver mResolver;
         private final KeyValueListParser mParser = new KeyValueListParser(',');
@@ -15187,6 +15217,10 @@
                         "");
                 PER_UID_MODEM_MODEL = getPerUidModemModel(perUidModemModel);
 
+                PHONE_ON_EXTERNAL_STATS_COLLECTION = mParser.getBoolean(
+                        KEY_PHONE_ON_EXTERNAL_STATS_COLLECTION,
+                        DEFAULT_PHONE_ON_EXTERNAL_STATS_COLLECTION);
+
                 updateBatteryChargedDelayMsLocked();
 
                 onChange();
@@ -15256,6 +15290,8 @@
             pw.println(RECORD_USAGE_HISTORY);
             pw.print(KEY_PER_UID_MODEM_POWER_MODEL); pw.print("=");
             pw.println(getPerUidModemModelName(PER_UID_MODEM_MODEL));
+            pw.print(KEY_PHONE_ON_EXTERNAL_STATS_COLLECTION); pw.print("=");
+            pw.println(PHONE_ON_EXTERNAL_STATS_COLLECTION);
         }
     }
 
diff --git a/services/core/java/com/android/server/power/stats/PhonePowerCalculator.java b/services/core/java/com/android/server/power/stats/PhonePowerCalculator.java
index bb89333..79ec6e2 100644
--- a/services/core/java/com/android/server/power/stats/PhonePowerCalculator.java
+++ b/services/core/java/com/android/server/power/stats/PhonePowerCalculator.java
@@ -42,14 +42,27 @@
     @Override
     public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats,
             long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {
+        final long energyConsumerUC = batteryStats.getPhoneEnergyConsumptionUC();
+        final int powerModel = getPowerModel(energyConsumerUC, query);
+
         final long phoneOnTimeMs = batteryStats.getPhoneOnTime(rawRealtimeUs,
                 BatteryStats.STATS_SINCE_CHARGED) / 1000;
-        final double phoneOnPower = mPowerEstimator.calculatePower(phoneOnTimeMs);
-        if (phoneOnPower != 0) {
-            builder.getAggregateBatteryConsumerBuilder(
-                    BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE)
-                    .setConsumedPower(BatteryConsumer.POWER_COMPONENT_PHONE, phoneOnPower)
-                    .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_PHONE, phoneOnTimeMs);
+
+        final double phoneOnPower;
+        switch (powerModel) {
+            case BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION:
+                phoneOnPower = uCtoMah(energyConsumerUC);
+                break;
+            case BatteryConsumer.POWER_MODEL_POWER_PROFILE:
+            default:
+                phoneOnPower = mPowerEstimator.calculatePower(phoneOnTimeMs);
         }
+
+        if (phoneOnPower == 0.0)  return;
+
+        builder.getAggregateBatteryConsumerBuilder(
+                        BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE)
+                .setConsumedPower(BatteryConsumer.POWER_COMPONENT_PHONE, phoneOnPower, powerModel)
+                .setUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_PHONE, phoneOnTimeMs);
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/MobileRadioPowerCalculatorTest.java b/services/tests/servicestests/src/com/android/server/power/stats/MobileRadioPowerCalculatorTest.java
index d059472..2e647c4 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/MobileRadioPowerCalculatorTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/stats/MobileRadioPowerCalculatorTest.java
@@ -602,6 +602,8 @@
         stats.noteNetworkInterfaceForTransports("cellular",
                 new int[]{NetworkCapabilities.TRANSPORT_CELLULAR});
 
+        stats.notePhoneOnLocked(9800, 9800);
+
         // Note application network activity
         NetworkStats networkStats = new NetworkStats(10000, 1)
                 .addEntry(new NetworkStats.Entry("cellular", APP_UID, 0, 0,
@@ -614,27 +616,34 @@
 
         mStatsRule.setTime(12_000, 12_000);
 
-        MobileRadioPowerCalculator calculator =
+        MobileRadioPowerCalculator mobileRadioPowerCalculator =
                 new MobileRadioPowerCalculator(mStatsRule.getPowerProfile());
-
-        mStatsRule.apply(calculator);
+        PhonePowerCalculator phonePowerCalculator =
+                new PhonePowerCalculator(mStatsRule.getPowerProfile());
+        mStatsRule.apply(mobileRadioPowerCalculator, phonePowerCalculator);
 
         BatteryConsumer deviceConsumer = mStatsRule.getDeviceBatteryConsumer();
         // 10_000_000 micro-Coulomb * 1/1000 milli/micro * 1/3600 hour/second = 2.77778 mAh
+        // 1800ms data duration / 2000 total duration *  2.77778 mAh = 2.5
+        // 200ms phone on duration / 2000 total duration *  2.77778 mAh = 0.27777
         assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
-                .isWithin(PRECISION).of(2.77778);
+                .isWithin(PRECISION).of(2.5);
         assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
                 .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
+        assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_PHONE))
+                .isWithin(PRECISION).of(0.27778);
+        assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_PHONE))
+                .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
 
         BatteryConsumer appsConsumer = mStatsRule.getAppsBatteryConsumer();
         assertThat(appsConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
-                .isWithin(PRECISION).of(1.53934);
+                .isWithin(PRECISION).of(1.38541);
         assertThat(appsConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
                 .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
 
         UidBatteryConsumer uidConsumer = mStatsRule.getUidBatteryConsumer(APP_UID);
         assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
-                .isWithin(PRECISION).of(1.53934);
+                .isWithin(PRECISION).of(1.38541);
         assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
                 .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
     }
@@ -649,6 +658,9 @@
                 .initMeasuredEnergyStatsLocked();
         BatteryStatsImpl stats = mStatsRule.getBatteryStats();
 
+        stats.noteMobileRadioPowerStateLocked(DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH, 0, -1,
+                0, 0);
+
         // Scan for a cell
         stats.notePhoneStateLocked(ServiceState.STATE_OUT_OF_SERVICE,
                 TelephonyManager.SIM_STATE_READY,
@@ -686,6 +698,9 @@
         stats.notePhoneSignalStrengthLocked(signalStrength, 8333, 8333);
         when(gsmSignalStrength.getLevel()).thenReturn(SignalStrength.SIGNAL_STRENGTH_MODERATE);
         stats.notePhoneSignalStrengthLocked(signalStrength, 8666, 8666);
+
+        stats.notePhoneOnLocked(9000, 9000);
+
         when(gsmSignalStrength.getLevel()).thenReturn(SignalStrength.SIGNAL_STRENGTH_GOOD);
         stats.notePhoneSignalStrengthLocked(signalStrength, 9110, 9110);
 
@@ -732,16 +747,24 @@
 
         mStatsRule.setTime(10_000, 10_000);
 
-        MobileRadioPowerCalculator calculator =
+        MobileRadioPowerCalculator mobileRadioPowerCalculator =
                 new MobileRadioPowerCalculator(mStatsRule.getPowerProfile());
-
-        mStatsRule.apply(calculator);
+        PhonePowerCalculator phonePowerCalculator =
+                new PhonePowerCalculator(mStatsRule.getPowerProfile());
+        mStatsRule.apply(mobileRadioPowerCalculator, phonePowerCalculator);
 
         BatteryConsumer deviceConsumer = mStatsRule.getDeviceBatteryConsumer();
+        // 10_000_000 micro-Coulomb * 1/1000 milli/micro * 1/3600 hour/second = 2.77778 mAh
+        // 9000ms data duration / 10000 total duration *  2.77778 mAh = 2.5
+        // 1000ms phone on duration / 10000 total duration *  2.77778 mAh = 0.27777
         assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
-                .isWithin(PRECISION).of(2.77778);
+                .isWithin(PRECISION).of(2.5);
         assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
                 .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
+        assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_PHONE))
+                .isWithin(PRECISION).of(0.27778);
+        assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_PHONE))
+                .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
 
         // CDMA2000 [Tx0, Tx1, Tx2, Tx3, Tx4, Rx] drain * duration
         //   [720, 1080, 1440, 1800, 2160, 1440] mA . [10, 11, 12, 13, 14, 15] ms = 111600 mA-ms
@@ -767,10 +790,10 @@
         // _________________
         // =    5177753 mA-ms estimated total consumption
         //
-        // 2.77778 mA-h measured total consumption * 3957753 / 5177753 = 2.123268 mA-h
+        // 2.5 mA-h measured total consumption * 3957753 / 5177753 = 1.91094 mA-h
         BatteryConsumer appsConsumer = mStatsRule.getAppsBatteryConsumer();
         assertThat(appsConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
-                .isWithin(PRECISION).of(2.123268);
+                .isWithin(PRECISION).of(1.91094);
         assertThat(appsConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
                 .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
 
@@ -791,17 +814,17 @@
         // 3333768 * 133.33333 / 204.44444 = 2174196.52174 mA-ms App 1 Tx Power Consumption
         //
         // Total App Power consumption * Ratio of App 1 / Total Estimated Power Consumption
-        // 2.123268 * (467988.75 + 2174196.52174) / 3957753 = 1.41749 App 1 Power Consumption
+        // 1.91094 * (467988.75 + 2174196.52174) / 3957753 = 1.27574 App 1 Power Consumption
         UidBatteryConsumer uidConsumer = mStatsRule.getUidBatteryConsumer(APP_UID);
         assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
-                .isWithin(PRECISION).of(1.41749);
+                .isWithin(PRECISION).of(1.27574);
         assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
                 .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
 
         // Rest should go to the other app
         UidBatteryConsumer uidConsumer2 = mStatsRule.getUidBatteryConsumer(APP_UID2);
         assertThat(uidConsumer2.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
-                .isWithin(PRECISION).of(0.705778);
+                .isWithin(PRECISION).of(0.63520);
         assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
                 .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
     }
@@ -814,6 +837,9 @@
                 .initMeasuredEnergyStatsLocked();
         BatteryStatsImpl stats = mStatsRule.getBatteryStats();
 
+        stats.noteMobileRadioPowerStateLocked(DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH, 0, -1,
+                0, 0);
+
         // Scan for a cell
         stats.notePhoneStateLocked(ServiceState.STATE_OUT_OF_SERVICE,
                 TelephonyManager.SIM_STATE_READY,
@@ -851,6 +877,9 @@
         stats.notePhoneSignalStrengthLocked(signalStrength, 8333, 8333);
         when(gsmSignalStrength.getLevel()).thenReturn(SignalStrength.SIGNAL_STRENGTH_MODERATE);
         stats.notePhoneSignalStrengthLocked(signalStrength, 8666, 8666);
+
+        stats.notePhoneOnLocked(9000, 9000);
+
         when(gsmSignalStrength.getLevel()).thenReturn(SignalStrength.SIGNAL_STRENGTH_GOOD);
         stats.notePhoneSignalStrengthLocked(signalStrength, 9110, 9110);
         when(gsmSignalStrength.getLevel()).thenReturn(SignalStrength.SIGNAL_STRENGTH_GREAT);
@@ -868,30 +897,38 @@
 
         mStatsRule.setTime(12_000, 12_000);
 
-        MobileRadioPowerCalculator calculator =
-                new MobileRadioPowerCalculator(mStatsRule.getPowerProfile());
 
-        mStatsRule.apply(calculator);
+        MobileRadioPowerCalculator mobileRadioPowerCalculator =
+                new MobileRadioPowerCalculator(mStatsRule.getPowerProfile());
+        PhonePowerCalculator phonePowerCalculator =
+                new PhonePowerCalculator(mStatsRule.getPowerProfile());
+        mStatsRule.apply(mobileRadioPowerCalculator, phonePowerCalculator);
 
         BatteryConsumer deviceConsumer = mStatsRule.getDeviceBatteryConsumer();
         // 10_000_000 micro-Coulomb * 1/1000 milli/micro * 1/3600 hour/second = 2.77778 mAh
+        // 9000ms data duration / 10000 total duration *  2.77778 mAh = 2.5
+        // 1000ms phone on duration / 10000 total duration *  2.77778 mAh = 0.27777
         assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
-                .isWithin(PRECISION).of(2.77778);
+                .isWithin(PRECISION).of(2.5);
         assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
                 .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
+        assertThat(deviceConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_PHONE))
+                .isWithin(PRECISION).of(0.27778);
+        assertThat(deviceConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_PHONE))
+                .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
 
         BatteryConsumer appsConsumer = mStatsRule.getAppsBatteryConsumer();
         // Estimated Rx/Tx modem consumption = 0.94 mAh
         // Estimated total modem consumption = 1.27888 mAh
-        // 2.77778 * 0.94 / 1.27888 = 2.04170 mAh
+        // 2.5 * 0.94 / 1.27888 = 1.83754 mAh
         assertThat(appsConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
-                .isWithin(PRECISION).of(2.04170);
+                .isWithin(PRECISION).of(1.83754);
         assertThat(appsConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
                 .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
 
         UidBatteryConsumer uidConsumer = mStatsRule.getUidBatteryConsumer(APP_UID);
         assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
-                .isWithin(PRECISION).of(2.04170);
+                .isWithin(PRECISION).of(1.83754);
         assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO))
                 .isEqualTo(BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION);
     }