1 /* 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 */ 16 17 package android.telephony; 18 19 import android.annotation.DurationMillisLong; 20 import android.annotation.ElapsedRealtimeLong; 21 import android.annotation.IntDef; 22 import android.annotation.NonNull; 23 import android.annotation.SystemApi; 24 import android.annotation.TestApi; 25 import android.os.Parcel; 26 import android.os.Parcelable; 27 import android.os.SystemClock; 28 import android.util.Range; 29 30 import java.lang.annotation.Retention; 31 import java.lang.annotation.RetentionPolicy; 32 import java.util.Arrays; 33 import java.util.Objects; 34 35 /** 36 * Contains information about the modem's activity. May be useful for power stats reporting. 37 * @hide 38 */ 39 @SystemApi 40 public final class ModemActivityInfo implements Parcelable { 41 private static final int TX_POWER_LEVELS = 5; 42 43 /** 44 * Corresponds to transmit power of less than 0dBm. 45 */ 46 public static final int TX_POWER_LEVEL_0 = 0; 47 48 /** 49 * Corresponds to transmit power between 0dBm and 5dBm. 50 */ 51 public static final int TX_POWER_LEVEL_1 = 1; 52 53 /** 54 * Corresponds to transmit power between 5dBm and 15dBm. 55 */ 56 public static final int TX_POWER_LEVEL_2 = 2; 57 58 /** 59 * Corresponds to transmit power between 15dBm and 20dBm. 60 */ 61 public static final int TX_POWER_LEVEL_3 = 3; 62 63 /** 64 * Corresponds to transmit power above 20dBm. 65 */ 66 public static final int TX_POWER_LEVEL_4 = 4; 67 68 /** 69 * The number of transmit power levels. Fixed by HAL definition. 70 */ getNumTxPowerLevels()71 public static int getNumTxPowerLevels() { 72 return TX_POWER_LEVELS; 73 } 74 75 /** @hide */ 76 @IntDef(prefix = {"TX_POWER_LEVEL_"}, value = { 77 TX_POWER_LEVEL_0, 78 TX_POWER_LEVEL_1, 79 TX_POWER_LEVEL_2, 80 TX_POWER_LEVEL_3, 81 TX_POWER_LEVEL_4, 82 }) 83 @Retention(RetentionPolicy.SOURCE) 84 public @interface TxPowerLevel {} 85 86 private static final Range<Integer>[] TX_POWER_RANGES = new Range[] { 87 new Range<>(Integer.MIN_VALUE, 0), 88 new Range<>(0, 5), 89 new Range<>(5, 15), 90 new Range<>(15, 20), 91 new Range<>(20, Integer.MAX_VALUE) 92 }; 93 94 private long mTimestamp; 95 private int mSleepTimeMs; 96 private int mIdleTimeMs; 97 private int[] mTxTimeMs; 98 private int mRxTimeMs; 99 100 /** 101 * @hide 102 */ 103 @TestApi ModemActivityInfo(long timestamp, int sleepTimeMs, int idleTimeMs, @NonNull int[] txTimeMs, int rxTimeMs)104 public ModemActivityInfo(long timestamp, int sleepTimeMs, int idleTimeMs, 105 @NonNull int[] txTimeMs, int rxTimeMs) { 106 Objects.requireNonNull(txTimeMs); 107 if (txTimeMs.length != TX_POWER_LEVELS) { 108 throw new IllegalArgumentException("txTimeMs must have length == TX_POWER_LEVELS"); 109 } 110 mTimestamp = timestamp; 111 mSleepTimeMs = sleepTimeMs; 112 mIdleTimeMs = idleTimeMs; 113 mTxTimeMs = txTimeMs; 114 mRxTimeMs = rxTimeMs; 115 } 116 117 /** 118 * Provided for convenience in manipulation since the API exposes long values but internal 119 * representations are ints. 120 * @hide 121 */ ModemActivityInfo(long timestamp, long sleepTimeMs, long idleTimeMs, @NonNull int[] txTimeMs, long rxTimeMs)122 public ModemActivityInfo(long timestamp, long sleepTimeMs, long idleTimeMs, 123 @NonNull int[] txTimeMs, long rxTimeMs) { 124 this(timestamp, (int) sleepTimeMs, (int) idleTimeMs, txTimeMs, (int) rxTimeMs); 125 } 126 127 @Override toString()128 public String toString() { 129 return "ModemActivityInfo{" 130 + " mTimestamp=" + mTimestamp 131 + " mSleepTimeMs=" + mSleepTimeMs 132 + " mIdleTimeMs=" + mIdleTimeMs 133 + " mTxTimeMs[]=" + Arrays.toString(mTxTimeMs) 134 + " mRxTimeMs=" + mRxTimeMs 135 + "}"; 136 } 137 describeContents()138 public int describeContents() { 139 return 0; 140 } 141 142 public static final @android.annotation.NonNull Parcelable.Creator<ModemActivityInfo> CREATOR = 143 new Parcelable.Creator<ModemActivityInfo>() { 144 public ModemActivityInfo createFromParcel(@NonNull Parcel in) { 145 long timestamp = in.readLong(); 146 int sleepTimeMs = in.readInt(); 147 int idleTimeMs = in.readInt(); 148 int[] txTimeMs = new int[TX_POWER_LEVELS]; 149 in.readIntArray(txTimeMs); 150 int rxTimeMs = in.readInt(); 151 return new ModemActivityInfo(timestamp, sleepTimeMs, idleTimeMs, 152 txTimeMs, rxTimeMs); 153 } 154 155 public ModemActivityInfo[] newArray(int size) { 156 return new ModemActivityInfo[size]; 157 } 158 }; 159 160 /** 161 * @param dest The Parcel in which the object should be written. 162 * @param flags Additional flags about how the object should be written. 163 */ writeToParcel(@onNull Parcel dest, int flags)164 public void writeToParcel(@NonNull Parcel dest, int flags) { 165 dest.writeLong(mTimestamp); 166 dest.writeInt(mSleepTimeMs); 167 dest.writeInt(mIdleTimeMs); 168 dest.writeIntArray(mTxTimeMs); 169 dest.writeInt(mRxTimeMs); 170 } 171 172 /** 173 * Gets the timestamp at which this modem activity info was recorded. 174 * 175 * @return The timestamp, as returned by {@link SystemClock#elapsedRealtime()}, when this 176 * {@link ModemActivityInfo} was recorded. 177 */ getTimestampMillis()178 public @ElapsedRealtimeLong long getTimestampMillis() { 179 return mTimestamp; 180 } 181 182 /** @hide */ setTimestamp(long timestamp)183 public void setTimestamp(long timestamp) { 184 mTimestamp = timestamp; 185 } 186 187 /** 188 * Gets the amount of time the modem spent transmitting at a certain power level. 189 * 190 * @param powerLevel The power level to query. 191 * @return The amount of time, in milliseconds, that the modem spent transmitting at the 192 * given power level. 193 */ getTransmitDurationMillisAtPowerLevel( @xPowerLevel int powerLevel)194 public @DurationMillisLong long getTransmitDurationMillisAtPowerLevel( 195 @TxPowerLevel int powerLevel) { 196 return mTxTimeMs[powerLevel]; 197 } 198 199 /** 200 * Gets the range of transmit powers corresponding to a certain power level. 201 * 202 * @param powerLevel The power level to query 203 * @return A {@link Range} object representing the range of intensities (in dBm) to which this 204 * power level corresponds. 205 */ getTransmitPowerRange(@xPowerLevel int powerLevel)206 public @NonNull Range<Integer> getTransmitPowerRange(@TxPowerLevel int powerLevel) { 207 return TX_POWER_RANGES[powerLevel]; 208 } 209 210 /** @hide */ setTransmitTimeMillis(int[] txTimeMs)211 public void setTransmitTimeMillis(int[] txTimeMs) { 212 mTxTimeMs = Arrays.copyOf(txTimeMs, TX_POWER_LEVELS); 213 } 214 215 /** 216 * @return The raw array of transmit power durations 217 * @hide 218 */ 219 @NonNull getTransmitTimeMillis()220 public int[] getTransmitTimeMillis() { 221 return mTxTimeMs; 222 } 223 224 /** 225 * Gets the amount of time (in milliseconds) when the modem is in a low power or sleep state. 226 * 227 * @return Time in milliseconds. 228 */ getSleepTimeMillis()229 public @DurationMillisLong long getSleepTimeMillis() { 230 return mSleepTimeMs; 231 } 232 233 /** @hide */ setSleepTimeMillis(int sleepTimeMillis)234 public void setSleepTimeMillis(int sleepTimeMillis) { 235 mSleepTimeMs = sleepTimeMillis; 236 } 237 238 /** 239 * Provided for convenience, since the API surface needs to return longs but internal 240 * representations are ints. 241 * @hide 242 */ setSleepTimeMillis(long sleepTimeMillis)243 public void setSleepTimeMillis(long sleepTimeMillis) { 244 mSleepTimeMs = (int) sleepTimeMillis; 245 } 246 247 /** 248 * Computes the difference between this instance of {@link ModemActivityInfo} and another 249 * instance. 250 * 251 * This method should be used to compute the amount of activity that has happened between two 252 * samples of modem activity taken at separate times. The sample passed in as an argument to 253 * this method should be the one that's taken later in time (and therefore has more activity). 254 * @param other The other instance of {@link ModemActivityInfo} to diff against. 255 * @return An instance of {@link ModemActivityInfo} representing the difference in modem 256 * activity. 257 */ getDelta(@onNull ModemActivityInfo other)258 public @NonNull ModemActivityInfo getDelta(@NonNull ModemActivityInfo other) { 259 int[] txTimeMs = new int[ModemActivityInfo.TX_POWER_LEVELS]; 260 for (int i = 0; i < ModemActivityInfo.TX_POWER_LEVELS; i++) { 261 txTimeMs[i] = other.mTxTimeMs[i] - mTxTimeMs[i]; 262 } 263 return new ModemActivityInfo(other.getTimestampMillis(), 264 other.getSleepTimeMillis() - getSleepTimeMillis(), 265 other.getIdleTimeMillis() - getIdleTimeMillis(), 266 txTimeMs, 267 other.getReceiveTimeMillis() - getReceiveTimeMillis()); 268 } 269 270 /** 271 * Gets the amount of time (in milliseconds) when the modem is awake but neither transmitting 272 * nor receiving. 273 * 274 * @return Time in milliseconds. 275 */ getIdleTimeMillis()276 public @DurationMillisLong long getIdleTimeMillis() { 277 return mIdleTimeMs; 278 } 279 280 /** @hide */ setIdleTimeMillis(int idleTimeMillis)281 public void setIdleTimeMillis(int idleTimeMillis) { 282 mIdleTimeMs = idleTimeMillis; 283 } 284 285 /** 286 * Provided for convenience, since the API surface needs to return longs but internal 287 * representations are ints. 288 * @hide 289 */ setIdleTimeMillis(long idleTimeMillis)290 public void setIdleTimeMillis(long idleTimeMillis) { 291 mIdleTimeMs = (int) idleTimeMillis; 292 } 293 294 /** 295 * Gets the amount of time (in milliseconds) when the modem is awake and receiving data. 296 * 297 * @return Time in milliseconds. 298 */ getReceiveTimeMillis()299 public @DurationMillisLong long getReceiveTimeMillis() { 300 return mRxTimeMs; 301 } 302 303 /** @hide */ setReceiveTimeMillis(int rxTimeMillis)304 public void setReceiveTimeMillis(int rxTimeMillis) { 305 mRxTimeMs = rxTimeMillis; 306 } 307 308 /** 309 * Provided for convenience, since the API surface needs to return longs but internal 310 * representations are ints. 311 * @hide 312 */ setReceiveTimeMillis(long receiveTimeMillis)313 public void setReceiveTimeMillis(long receiveTimeMillis) { 314 mRxTimeMs = (int) receiveTimeMillis; 315 } 316 317 /** 318 * Indicates if the modem has reported valid {@link ModemActivityInfo}. 319 * 320 * @return {@code true} if this {@link ModemActivityInfo} record is valid, 321 * {@code false} otherwise. 322 * @hide 323 */ 324 @TestApi isValid()325 public boolean isValid() { 326 boolean isTxPowerValid = Arrays.stream(mTxTimeMs).allMatch((i) -> i >= 0); 327 328 return isTxPowerValid && ((getIdleTimeMillis() >= 0) && (getSleepTimeMillis() >= 0) 329 && (getReceiveTimeMillis() >= 0) && !isEmpty()); 330 } 331 332 /** @hide */ 333 @TestApi isEmpty()334 public boolean isEmpty() { 335 boolean isTxPowerEmpty = mTxTimeMs == null || mTxTimeMs.length == 0 336 || Arrays.stream(mTxTimeMs).allMatch((i) -> i == 0); 337 338 return isTxPowerEmpty && ((getIdleTimeMillis() == 0) && (getSleepTimeMillis() == 0) 339 && (getReceiveTimeMillis() == 0)); 340 } 341 342 343 @Override equals(Object o)344 public boolean equals(Object o) { 345 if (this == o) return true; 346 if (o == null || getClass() != o.getClass()) return false; 347 ModemActivityInfo that = (ModemActivityInfo) o; 348 return mTimestamp == that.mTimestamp 349 && mSleepTimeMs == that.mSleepTimeMs 350 && mIdleTimeMs == that.mIdleTimeMs 351 && mRxTimeMs == that.mRxTimeMs 352 && Arrays.equals(mTxTimeMs, that.mTxTimeMs); 353 } 354 355 @Override hashCode()356 public int hashCode() { 357 int result = Objects.hash(mTimestamp, mSleepTimeMs, mIdleTimeMs, mRxTimeMs); 358 result = 31 * result + Arrays.hashCode(mTxTimeMs); 359 return result; 360 } 361 } 362