1 /*
2  * Copyright (C) 2024 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  */
16 
17 package com.android.server.power.stats;
18 
19 import android.annotation.NonNull;
20 import android.os.PersistableBundle;
21 import android.telephony.ModemActivityInfo;
22 import android.util.Slog;
23 import android.util.SparseArray;
24 
25 import com.android.internal.os.PowerStats;
26 
27 /**
28  * Captures the positions and lengths of sections of the stats array, such as time-in-state,
29  * power usage estimates etc.
30  */
31 class MobileRadioPowerStatsLayout extends PowerStatsLayout {
32     private static final String TAG = "MobileRadioPowerStatsLayout";
33     private static final String EXTRA_DEVICE_SLEEP_TIME_POSITION = "dt-sleep";
34     private static final String EXTRA_DEVICE_IDLE_TIME_POSITION = "dt-idle";
35     private static final String EXTRA_DEVICE_SCAN_TIME_POSITION = "dt-scan";
36     private static final String EXTRA_DEVICE_CALL_TIME_POSITION = "dt-call";
37     private static final String EXTRA_DEVICE_CALL_POWER_POSITION = "dp-call";
38     private static final String EXTRA_STATE_RX_TIME_POSITION = "srx";
39     private static final String EXTRA_STATE_TX_TIMES_POSITION = "stx";
40     private static final String EXTRA_STATE_TX_TIMES_COUNT = "stxc";
41     private static final String EXTRA_UID_RX_BYTES_POSITION = "urxb";
42     private static final String EXTRA_UID_TX_BYTES_POSITION = "utxb";
43     private static final String EXTRA_UID_RX_PACKETS_POSITION = "urxp";
44     private static final String EXTRA_UID_TX_PACKETS_POSITION = "utxp";
45 
46     private int mDeviceSleepTimePosition;
47     private int mDeviceIdleTimePosition;
48     private int mDeviceScanTimePosition;
49     private int mDeviceCallTimePosition;
50     private int mDeviceCallPowerPosition;
51     private int mStateRxTimePosition;
52     private int mStateTxTimesPosition;
53     private int mStateTxTimesCount;
54     private int mUidRxBytesPosition;
55     private int mUidTxBytesPosition;
56     private int mUidRxPacketsPosition;
57     private int mUidTxPacketsPosition;
58 
MobileRadioPowerStatsLayout()59     MobileRadioPowerStatsLayout() {
60     }
61 
MobileRadioPowerStatsLayout(@onNull PowerStats.Descriptor descriptor)62     MobileRadioPowerStatsLayout(@NonNull PowerStats.Descriptor descriptor) {
63         super(descriptor);
64     }
65 
addDeviceMobileActivity()66     void addDeviceMobileActivity() {
67         mDeviceSleepTimePosition = addDeviceSection(1, "sleep");
68         mDeviceIdleTimePosition = addDeviceSection(1, "idle");
69         mDeviceScanTimePosition = addDeviceSection(1, "scan");
70         mDeviceCallTimePosition = addDeviceSection(1, "call", FLAG_OPTIONAL);
71     }
72 
addStateStats()73     void addStateStats() {
74         mStateRxTimePosition = addStateSection(1, "rx");
75         mStateTxTimesCount = ModemActivityInfo.getNumTxPowerLevels();
76         mStateTxTimesPosition = addStateSection(mStateTxTimesCount, "tx");
77     }
78 
addUidNetworkStats()79     void addUidNetworkStats() {
80         mUidRxPacketsPosition = addUidSection(1, "rx-pkts");
81         mUidRxBytesPosition = addUidSection(1, "rx-B");
82         mUidTxPacketsPosition = addUidSection(1, "tx-pkts");
83         mUidTxBytesPosition = addUidSection(1, "tx-B");
84     }
85 
86     @Override
addDeviceSectionPowerEstimate()87     public void addDeviceSectionPowerEstimate() {
88         super.addDeviceSectionPowerEstimate();
89         // Printed as part of the PhoneCallPowerStatsProcessor
90         mDeviceCallPowerPosition = addDeviceSection(1, "call-power", FLAG_HIDDEN);
91     }
92 
setDeviceSleepTime(long[] stats, long durationMillis)93     public void setDeviceSleepTime(long[] stats, long durationMillis) {
94         stats[mDeviceSleepTimePosition] = durationMillis;
95     }
96 
getDeviceSleepTime(long[] stats)97     public long getDeviceSleepTime(long[] stats) {
98         return stats[mDeviceSleepTimePosition];
99     }
100 
setDeviceIdleTime(long[] stats, long durationMillis)101     public void setDeviceIdleTime(long[] stats, long durationMillis) {
102         stats[mDeviceIdleTimePosition] = durationMillis;
103     }
104 
getDeviceIdleTime(long[] stats)105     public long getDeviceIdleTime(long[] stats) {
106         return stats[mDeviceIdleTimePosition];
107     }
108 
setDeviceScanTime(long[] stats, long durationMillis)109     public void setDeviceScanTime(long[] stats, long durationMillis) {
110         stats[mDeviceScanTimePosition] = durationMillis;
111     }
112 
getDeviceScanTime(long[] stats)113     public long getDeviceScanTime(long[] stats) {
114         return stats[mDeviceScanTimePosition];
115     }
116 
setDeviceCallTime(long[] stats, long durationMillis)117     public void setDeviceCallTime(long[] stats, long durationMillis) {
118         stats[mDeviceCallTimePosition] = durationMillis;
119     }
120 
getDeviceCallTime(long[] stats)121     public long getDeviceCallTime(long[] stats) {
122         return stats[mDeviceCallTimePosition];
123     }
124 
setDeviceCallPowerEstimate(long[] stats, double power)125     public void setDeviceCallPowerEstimate(long[] stats, double power) {
126         stats[mDeviceCallPowerPosition] = (long) (power * MILLI_TO_NANO_MULTIPLIER);
127     }
128 
getDeviceCallPowerEstimate(long[] stats)129     public double getDeviceCallPowerEstimate(long[] stats) {
130         return stats[mDeviceCallPowerPosition] / MILLI_TO_NANO_MULTIPLIER;
131     }
132 
setStateRxTime(long[] stats, long durationMillis)133     public void setStateRxTime(long[] stats, long durationMillis) {
134         stats[mStateRxTimePosition] = durationMillis;
135     }
136 
getStateRxTime(long[] stats)137     public long getStateRxTime(long[] stats) {
138         return stats[mStateRxTimePosition];
139     }
140 
setStateTxTime(long[] stats, int level, int durationMillis)141     public void setStateTxTime(long[] stats, int level, int durationMillis) {
142         stats[mStateTxTimesPosition + level] = durationMillis;
143     }
144 
getStateTxTime(long[] stats, int level)145     public long getStateTxTime(long[] stats, int level) {
146         return stats[mStateTxTimesPosition + level];
147     }
148 
setUidRxBytes(long[] stats, long count)149     public void setUidRxBytes(long[] stats, long count) {
150         stats[mUidRxBytesPosition] = count;
151     }
152 
getUidRxBytes(long[] stats)153     public long getUidRxBytes(long[] stats) {
154         return stats[mUidRxBytesPosition];
155     }
156 
setUidTxBytes(long[] stats, long count)157     public void setUidTxBytes(long[] stats, long count) {
158         stats[mUidTxBytesPosition] = count;
159     }
160 
getUidTxBytes(long[] stats)161     public long getUidTxBytes(long[] stats) {
162         return stats[mUidTxBytesPosition];
163     }
164 
setUidRxPackets(long[] stats, long count)165     public void setUidRxPackets(long[] stats, long count) {
166         stats[mUidRxPacketsPosition] = count;
167     }
168 
getUidRxPackets(long[] stats)169     public long getUidRxPackets(long[] stats) {
170         return stats[mUidRxPacketsPosition];
171     }
172 
setUidTxPackets(long[] stats, long count)173     public void setUidTxPackets(long[] stats, long count) {
174         stats[mUidTxPacketsPosition] = count;
175     }
176 
getUidTxPackets(long[] stats)177     public long getUidTxPackets(long[] stats) {
178         return stats[mUidTxPacketsPosition];
179     }
180 
181     /**
182      * Copies the elements of the stats array layout into <code>extras</code>
183      */
toExtras(PersistableBundle extras)184     public void toExtras(PersistableBundle extras) {
185         super.toExtras(extras);
186         extras.putInt(EXTRA_DEVICE_SLEEP_TIME_POSITION, mDeviceSleepTimePosition);
187         extras.putInt(EXTRA_DEVICE_IDLE_TIME_POSITION, mDeviceIdleTimePosition);
188         extras.putInt(EXTRA_DEVICE_SCAN_TIME_POSITION, mDeviceScanTimePosition);
189         extras.putInt(EXTRA_DEVICE_CALL_TIME_POSITION, mDeviceCallTimePosition);
190         extras.putInt(EXTRA_DEVICE_CALL_POWER_POSITION, mDeviceCallPowerPosition);
191         extras.putInt(EXTRA_STATE_RX_TIME_POSITION, mStateRxTimePosition);
192         extras.putInt(EXTRA_STATE_TX_TIMES_POSITION, mStateTxTimesPosition);
193         extras.putInt(EXTRA_STATE_TX_TIMES_COUNT, mStateTxTimesCount);
194         extras.putInt(EXTRA_UID_RX_BYTES_POSITION, mUidRxBytesPosition);
195         extras.putInt(EXTRA_UID_TX_BYTES_POSITION, mUidTxBytesPosition);
196         extras.putInt(EXTRA_UID_RX_PACKETS_POSITION, mUidRxPacketsPosition);
197         extras.putInt(EXTRA_UID_TX_PACKETS_POSITION, mUidTxPacketsPosition);
198     }
199 
200     /**
201      * Retrieves elements of the stats array layout from <code>extras</code>
202      */
fromExtras(PersistableBundle extras)203     public void fromExtras(PersistableBundle extras) {
204         super.fromExtras(extras);
205         mDeviceSleepTimePosition = extras.getInt(EXTRA_DEVICE_SLEEP_TIME_POSITION);
206         mDeviceIdleTimePosition = extras.getInt(EXTRA_DEVICE_IDLE_TIME_POSITION);
207         mDeviceScanTimePosition = extras.getInt(EXTRA_DEVICE_SCAN_TIME_POSITION);
208         mDeviceCallTimePosition = extras.getInt(EXTRA_DEVICE_CALL_TIME_POSITION);
209         mDeviceCallPowerPosition = extras.getInt(EXTRA_DEVICE_CALL_POWER_POSITION);
210         mStateRxTimePosition = extras.getInt(EXTRA_STATE_RX_TIME_POSITION);
211         mStateTxTimesPosition = extras.getInt(EXTRA_STATE_TX_TIMES_POSITION);
212         mStateTxTimesCount = extras.getInt(EXTRA_STATE_TX_TIMES_COUNT);
213         mUidRxBytesPosition = extras.getInt(EXTRA_UID_RX_BYTES_POSITION);
214         mUidTxBytesPosition = extras.getInt(EXTRA_UID_TX_BYTES_POSITION);
215         mUidRxPacketsPosition = extras.getInt(EXTRA_UID_RX_PACKETS_POSITION);
216         mUidTxPacketsPosition = extras.getInt(EXTRA_UID_TX_PACKETS_POSITION);
217     }
218 
addRxTxTimesForRat(SparseArray<long[]> stateStats, int networkType, int freqRange, long rxTime, int[] txTime)219     public void addRxTxTimesForRat(SparseArray<long[]> stateStats, int networkType, int freqRange,
220             long rxTime, int[] txTime) {
221         if (txTime.length != mStateTxTimesCount) {
222             Slog.wtf(TAG, "Invalid TX time array size: " + txTime.length);
223             return;
224         }
225 
226         boolean nonZero = false;
227         if (rxTime != 0) {
228             nonZero = true;
229         } else {
230             for (int i = txTime.length - 1; i >= 0; i--) {
231                 if (txTime[i] != 0) {
232                     nonZero = true;
233                     break;
234                 }
235             }
236         }
237 
238         if (!nonZero) {
239             return;
240         }
241 
242         int rat = MobileRadioPowerStatsCollector.mapRadioAccessNetworkTypeToRadioAccessTechnology(
243                 networkType);
244         int stateKey = MobileRadioPowerStatsCollector.makeStateKey(rat, freqRange);
245         long[] stats = stateStats.get(stateKey);
246         if (stats == null) {
247             stats = new long[getStateStatsArrayLength()];
248             stateStats.put(stateKey, stats);
249         }
250 
251         stats[mStateRxTimePosition] += rxTime;
252         for (int i = mStateTxTimesCount - 1; i >= 0; i--) {
253             stats[mStateTxTimesPosition + i] += txTime[i];
254         }
255     }
256 }
257