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 android.telephony.satellite; 18 19 import android.annotation.NonNull; 20 import android.os.Parcel; 21 import android.os.Parcelable; 22 import android.util.Log; 23 24 import java.util.HashMap; 25 import java.util.Map; 26 import java.util.Objects; 27 28 /** 29 * SatelliteSessionStats is used to represent the usage stats of the satellite service. 30 * 31 * @hide 32 */ 33 public final class SatelliteSessionStats implements Parcelable { 34 private int mCountOfSuccessfulUserMessages; 35 private int mCountOfUnsuccessfulUserMessages; 36 private int mCountOfTimedOutUserMessagesWaitingForConnection; 37 private int mCountOfTimedOutUserMessagesWaitingForAck; 38 private int mCountOfUserMessagesInQueueToBeSent; 39 private long mLatencyOfSuccessfulUserMessages; 40 41 private Map<Integer, SatelliteSessionStats> datagramStats; 42 private long mMaxLatency; 43 private long mLastMessageLatency; 44 SatelliteSessionStats()45 public SatelliteSessionStats() { 46 this.datagramStats = new HashMap<>(); 47 } 48 49 /** 50 * SatelliteSessionStats constructor 51 * 52 * @param builder Builder to create SatelliteSessionStats object/ 53 */ SatelliteSessionStats(@onNull Builder builder)54 public SatelliteSessionStats(@NonNull Builder builder) { 55 mCountOfSuccessfulUserMessages = builder.mCountOfSuccessfulUserMessages; 56 mCountOfUnsuccessfulUserMessages = builder.mCountOfUnsuccessfulUserMessages; 57 mCountOfTimedOutUserMessagesWaitingForConnection = 58 builder.mCountOfTimedOutUserMessagesWaitingForConnection; 59 mCountOfTimedOutUserMessagesWaitingForAck = 60 builder.mCountOfTimedOutUserMessagesWaitingForAck; 61 mCountOfUserMessagesInQueueToBeSent = builder.mCountOfUserMessagesInQueueToBeSent; 62 mLatencyOfSuccessfulUserMessages = builder.mLatencyOfSuccessfulUserMessages; 63 } 64 SatelliteSessionStats(Parcel in)65 private SatelliteSessionStats(Parcel in) { 66 readFromParcel(in); 67 } 68 69 @Override describeContents()70 public int describeContents() { 71 return 0; 72 } 73 74 @Override writeToParcel(@onNull Parcel out, int flags)75 public void writeToParcel(@NonNull Parcel out, int flags) { 76 out.writeInt(mCountOfSuccessfulUserMessages); 77 out.writeInt(mCountOfUnsuccessfulUserMessages); 78 out.writeInt(mCountOfTimedOutUserMessagesWaitingForConnection); 79 out.writeInt(mCountOfTimedOutUserMessagesWaitingForAck); 80 out.writeInt(mCountOfUserMessagesInQueueToBeSent); 81 out.writeLong(mLatencyOfSuccessfulUserMessages); 82 out.writeLong(mMaxLatency); 83 out.writeLong(mLastMessageLatency); 84 85 if (datagramStats != null && !datagramStats.isEmpty()) { 86 out.writeInt(datagramStats.size()); 87 for (Map.Entry<Integer, SatelliteSessionStats> entry : datagramStats.entrySet()) { 88 out.writeInt(entry.getKey()); 89 out.writeParcelable(entry.getValue(), flags); 90 } 91 } else { 92 out.writeInt(0); 93 } 94 } 95 96 @NonNull 97 public static final Creator<SatelliteSessionStats> CREATOR = new Parcelable.Creator<>() { 98 99 @Override 100 public SatelliteSessionStats createFromParcel(Parcel in) { 101 return new SatelliteSessionStats(in); 102 } 103 104 @Override 105 public SatelliteSessionStats[] newArray(int size) { 106 return new SatelliteSessionStats[size]; 107 } 108 }; 109 110 @Override 111 @NonNull toString()112 public String toString() { 113 StringBuilder sb = new StringBuilder(); 114 if (datagramStats != null) { 115 sb.append(" ====== SatelliteSessionStatsWrapper Info ============="); 116 for (Map.Entry<Integer, SatelliteSessionStats> entry : datagramStats.entrySet()) { 117 Integer key = entry.getKey(); 118 SatelliteSessionStats value = entry.getValue(); 119 sb.append("\n"); 120 sb.append("Key:"); 121 sb.append(key); 122 sb.append(", SatelliteSessionStats:["); 123 value.getPrintableCounters(sb); 124 sb.append(","); 125 sb.append(" LatencyOfSuccessfulUserMessages:"); 126 sb.append(value.mLatencyOfSuccessfulUserMessages); 127 sb.append(","); 128 sb.append(" mMaxLatency:"); 129 sb.append(value.mMaxLatency); 130 sb.append(","); 131 sb.append(" mLastMessageLatency:"); 132 sb.append(value.mLastMessageLatency); 133 sb.append("]"); 134 sb.append("\n"); 135 } 136 sb.append(" ============== ================== ==============="); 137 sb.append("\n"); 138 sb.append("\n"); 139 } else { 140 sb.append("\n"); 141 getPrintableCounters(sb); 142 } 143 sb.append("\n"); 144 return sb.toString(); 145 } 146 getPrintableCounters(StringBuilder sb)147 private void getPrintableCounters(StringBuilder sb) { 148 sb.append("countOfSuccessfulUserMessages:"); 149 sb.append(mCountOfSuccessfulUserMessages); 150 sb.append(","); 151 152 sb.append("countOfUnsuccessfulUserMessages:"); 153 sb.append(mCountOfUnsuccessfulUserMessages); 154 sb.append(","); 155 156 sb.append("countOfTimedOutUserMessagesWaitingForConnection:"); 157 sb.append(mCountOfTimedOutUserMessagesWaitingForConnection); 158 sb.append(","); 159 160 sb.append("countOfTimedOutUserMessagesWaitingForAck:"); 161 sb.append(mCountOfTimedOutUserMessagesWaitingForAck); 162 sb.append(","); 163 164 sb.append("countOfUserMessagesInQueueToBeSent:"); 165 sb.append(mCountOfUserMessagesInQueueToBeSent); 166 } 167 168 @Override equals(Object o)169 public boolean equals(Object o) { 170 if (this == o) return true; 171 if (o == null || getClass() != o.getClass()) return false; 172 SatelliteSessionStats that = (SatelliteSessionStats) o; 173 return mCountOfSuccessfulUserMessages == that.mCountOfSuccessfulUserMessages 174 && mLatencyOfSuccessfulUserMessages == that.mLatencyOfSuccessfulUserMessages 175 && mCountOfUnsuccessfulUserMessages == that.mCountOfUnsuccessfulUserMessages 176 && mCountOfTimedOutUserMessagesWaitingForConnection 177 == that.mCountOfTimedOutUserMessagesWaitingForConnection 178 && mCountOfTimedOutUserMessagesWaitingForAck 179 == that.mCountOfTimedOutUserMessagesWaitingForAck 180 && mCountOfUserMessagesInQueueToBeSent == that.mCountOfUserMessagesInQueueToBeSent; 181 } 182 183 @Override hashCode()184 public int hashCode() { 185 return Objects.hash(mCountOfSuccessfulUserMessages, mLatencyOfSuccessfulUserMessages, 186 mCountOfUnsuccessfulUserMessages, mCountOfTimedOutUserMessagesWaitingForConnection, 187 mCountOfTimedOutUserMessagesWaitingForAck, mCountOfUserMessagesInQueueToBeSent); 188 } 189 getCountOfSuccessfulUserMessages()190 public int getCountOfSuccessfulUserMessages() { 191 return mCountOfSuccessfulUserMessages; 192 } 193 incrementSuccessfulUserMessageCount()194 public void incrementSuccessfulUserMessageCount() { 195 mCountOfSuccessfulUserMessages++; 196 } 197 getCountOfUnsuccessfulUserMessages()198 public int getCountOfUnsuccessfulUserMessages() { 199 return mCountOfUnsuccessfulUserMessages; 200 } 201 incrementUnsuccessfulUserMessageCount()202 public void incrementUnsuccessfulUserMessageCount() { 203 mCountOfUnsuccessfulUserMessages++; 204 } 205 getCountOfTimedOutUserMessagesWaitingForConnection()206 public int getCountOfTimedOutUserMessagesWaitingForConnection() { 207 return mCountOfTimedOutUserMessagesWaitingForConnection; 208 } 209 incrementTimedOutUserMessagesWaitingForConnection()210 public void incrementTimedOutUserMessagesWaitingForConnection() { 211 mCountOfTimedOutUserMessagesWaitingForConnection++; 212 } 213 getCountOfTimedOutUserMessagesWaitingForAck()214 public int getCountOfTimedOutUserMessagesWaitingForAck() { 215 return mCountOfTimedOutUserMessagesWaitingForAck; 216 } 217 incrementTimedOutUserMessagesWaitingForAck()218 public void incrementTimedOutUserMessagesWaitingForAck() { 219 mCountOfTimedOutUserMessagesWaitingForAck++; 220 } 221 getCountOfUserMessagesInQueueToBeSent()222 public int getCountOfUserMessagesInQueueToBeSent() { 223 return mCountOfUserMessagesInQueueToBeSent; 224 } 225 incrementUserMessagesInQueueToBeSent()226 public void incrementUserMessagesInQueueToBeSent() { 227 mCountOfUserMessagesInQueueToBeSent++; 228 } 229 getLatencyOfAllSuccessfulUserMessages()230 public long getLatencyOfAllSuccessfulUserMessages() { 231 return mLatencyOfSuccessfulUserMessages; 232 } 233 updateLatencyOfAllSuccessfulUserMessages(long messageLatency)234 public void updateLatencyOfAllSuccessfulUserMessages(long messageLatency) { 235 mLatencyOfSuccessfulUserMessages += messageLatency; 236 } 237 recordSuccessfulOutgoingDatagramStats( @atelliteManager.DatagramType int datagramType, long latency)238 public void recordSuccessfulOutgoingDatagramStats( 239 @SatelliteManager.DatagramType int datagramType, long latency) { 240 try { 241 datagramStats.putIfAbsent(datagramType, new SatelliteSessionStats.Builder().build()); 242 SatelliteSessionStats data = datagramStats.get(datagramType); 243 data.incrementSuccessfulUserMessageCount(); 244 if (data.mMaxLatency < latency) { 245 data.mMaxLatency = latency; 246 } 247 data.mLastMessageLatency = latency; 248 data.updateLatencyOfAllSuccessfulUserMessages(latency); 249 } catch (Exception e) { 250 Log.e("SatelliteSessionStats", 251 "Error while recordSuccessfulOutgoingDatagramStats: " + e.getMessage()); 252 } 253 } 254 resetCountOfUserMessagesInQueueToBeSent()255 public void resetCountOfUserMessagesInQueueToBeSent() { 256 for (Map.Entry<Integer, SatelliteSessionStats> entry : datagramStats.entrySet()) { 257 SatelliteSessionStats statsPerDatagramType = entry.getValue(); 258 statsPerDatagramType.mCountOfUserMessagesInQueueToBeSent = 0; 259 } 260 } 261 getCountOfSuccessfulOutgoingDatagram( @atelliteManager.DatagramType int datagramType)262 public int getCountOfSuccessfulOutgoingDatagram( 263 @SatelliteManager.DatagramType int datagramType) { 264 SatelliteSessionStats data = datagramStats.getOrDefault(datagramType, 265 new SatelliteSessionStats()); 266 return data.getCountOfSuccessfulUserMessages(); 267 } 268 getMaxLatency()269 public long getMaxLatency() { 270 return this.mMaxLatency; 271 } 272 getLatencyOfAllSuccessfulUserMessages( @atelliteManager.DatagramType int datagramType)273 public Long getLatencyOfAllSuccessfulUserMessages( 274 @SatelliteManager.DatagramType int datagramType) { 275 SatelliteSessionStats data = datagramStats.getOrDefault(datagramType, 276 new SatelliteSessionStats()); 277 return data.getLatencyOfAllSuccessfulUserMessages(); 278 } 279 280 getLastMessageLatency()281 public long getLastMessageLatency() { 282 return this.mLastMessageLatency; 283 } 284 addCountOfUnsuccessfulUserMessages(@atelliteManager.DatagramType int datagramType, @SatelliteManager.SatelliteResult int resultCode)285 public void addCountOfUnsuccessfulUserMessages(@SatelliteManager.DatagramType int datagramType, 286 @SatelliteManager.SatelliteResult int resultCode) { 287 try { 288 datagramStats.putIfAbsent(datagramType, new SatelliteSessionStats.Builder().build()); 289 SatelliteSessionStats data = datagramStats.get(datagramType); 290 data.incrementUnsuccessfulUserMessageCount(); 291 if (resultCode == SatelliteManager.SATELLITE_RESULT_NOT_REACHABLE) { 292 data.incrementTimedOutUserMessagesWaitingForConnection(); 293 } else if (resultCode == SatelliteManager.SATELLITE_RESULT_MODEM_TIMEOUT) { 294 data.incrementTimedOutUserMessagesWaitingForAck(); 295 } 296 } catch (Exception e) { 297 Log.e("SatelliteSessionStats", 298 "Error while addCountOfUnsuccessfulUserMessages: " + e.getMessage()); 299 } 300 } 301 updateCountOfUserMessagesInQueueToBeSent( @atelliteManager.DatagramType int datagramType)302 public void updateCountOfUserMessagesInQueueToBeSent( 303 @SatelliteManager.DatagramType int datagramType) { 304 try { 305 datagramStats.putIfAbsent(datagramType, new SatelliteSessionStats.Builder().build()); 306 SatelliteSessionStats data = datagramStats.get(datagramType); 307 data.incrementUserMessagesInQueueToBeSent(); 308 } catch (Exception e) { 309 Log.e("SatelliteSessionStats", 310 "Error while addCountOfUserMessagesInQueueToBeSent: " + e.getMessage()); 311 } 312 } 313 getCountOfUnsuccessfulUserMessages(@atelliteManager.DatagramType int datagramType)314 public int getCountOfUnsuccessfulUserMessages(@SatelliteManager.DatagramType int datagramType) { 315 SatelliteSessionStats data = datagramStats.get(datagramType); 316 return data.getCountOfUnsuccessfulUserMessages(); 317 } 318 getCountOfTimedOutUserMessagesWaitingForConnection( @atelliteManager.DatagramType int datagramType)319 public int getCountOfTimedOutUserMessagesWaitingForConnection( 320 @SatelliteManager.DatagramType int datagramType) { 321 SatelliteSessionStats data = datagramStats.get(datagramType); 322 return data.getCountOfTimedOutUserMessagesWaitingForConnection(); 323 } 324 getCountOfTimedOutUserMessagesWaitingForAck( @atelliteManager.DatagramType int datagramType)325 public int getCountOfTimedOutUserMessagesWaitingForAck( 326 @SatelliteManager.DatagramType int datagramType) { 327 SatelliteSessionStats data = datagramStats.get(datagramType); 328 return data.getCountOfTimedOutUserMessagesWaitingForAck(); 329 } 330 getCountOfUserMessagesInQueueToBeSent( @atelliteManager.DatagramType int datagramType)331 public int getCountOfUserMessagesInQueueToBeSent( 332 @SatelliteManager.DatagramType int datagramType) { 333 SatelliteSessionStats data = datagramStats.get(datagramType); 334 return data.getCountOfUserMessagesInQueueToBeSent(); 335 } 336 clear()337 public void clear() { 338 datagramStats.clear(); 339 } 340 getSatelliteSessionStats()341 public Map<Integer, SatelliteSessionStats> getSatelliteSessionStats() { 342 return datagramStats; 343 } 344 setSatelliteSessionStats(Map<Integer, SatelliteSessionStats> sessionStats)345 public void setSatelliteSessionStats(Map<Integer, SatelliteSessionStats> sessionStats) { 346 this.datagramStats = sessionStats; 347 } 348 readFromParcel(Parcel in)349 private void readFromParcel(Parcel in) { 350 mCountOfSuccessfulUserMessages = in.readInt(); 351 mCountOfUnsuccessfulUserMessages = in.readInt(); 352 mCountOfTimedOutUserMessagesWaitingForConnection = in.readInt(); 353 mCountOfTimedOutUserMessagesWaitingForAck = in.readInt(); 354 mCountOfUserMessagesInQueueToBeSent = in.readInt(); 355 mLatencyOfSuccessfulUserMessages = in.readLong(); 356 mMaxLatency = in.readLong(); 357 mLastMessageLatency = in.readLong(); 358 359 int size = in.readInt(); 360 datagramStats = new HashMap<>(); 361 for (int i = 0; i < size; i++) { 362 Integer key = in.readInt(); 363 SatelliteSessionStats value = in.readParcelable( 364 SatelliteSessionStats.class.getClassLoader()); 365 datagramStats.put(key, value); 366 } 367 } 368 369 /** 370 * A builder class to create {@link SatelliteSessionStats} data object. 371 */ 372 public static final class Builder { 373 private int mCountOfSuccessfulUserMessages; 374 private int mCountOfUnsuccessfulUserMessages; 375 private int mCountOfTimedOutUserMessagesWaitingForConnection; 376 private int mCountOfTimedOutUserMessagesWaitingForAck; 377 private int mCountOfUserMessagesInQueueToBeSent; 378 private long mLatencyOfSuccessfulUserMessages; 379 380 private long mMaxLatency; 381 private long mLastMessageLatency; 382 /** 383 * Sets countOfSuccessfulUserMessages value of {@link SatelliteSessionStats} 384 * and then returns the Builder class. 385 */ 386 @NonNull setCountOfSuccessfulUserMessages(int count)387 public Builder setCountOfSuccessfulUserMessages(int count) { 388 mCountOfSuccessfulUserMessages = count; 389 return this; 390 } 391 392 /** 393 * Sets countOfUnsuccessfulUserMessages value of {@link SatelliteSessionStats} 394 * and then returns the Builder class. 395 */ 396 @NonNull setCountOfUnsuccessfulUserMessages(int count)397 public Builder setCountOfUnsuccessfulUserMessages(int count) { 398 mCountOfUnsuccessfulUserMessages = count; 399 return this; 400 } 401 402 /** 403 * Sets countOfTimedOutUserMessagesWaitingForConnection value of 404 * {@link SatelliteSessionStats} and then returns the Builder class. 405 */ 406 @NonNull setCountOfTimedOutUserMessagesWaitingForConnection(int count)407 public Builder setCountOfTimedOutUserMessagesWaitingForConnection(int count) { 408 mCountOfTimedOutUserMessagesWaitingForConnection = count; 409 return this; 410 } 411 412 /** 413 * Sets countOfTimedOutUserMessagesWaitingForAck value of {@link SatelliteSessionStats} 414 * and then returns the Builder class. 415 */ 416 @NonNull setCountOfTimedOutUserMessagesWaitingForAck(int count)417 public Builder setCountOfTimedOutUserMessagesWaitingForAck(int count) { 418 mCountOfTimedOutUserMessagesWaitingForAck = count; 419 return this; 420 } 421 422 /** 423 * Sets countOfUserMessagesInQueueToBeSent value of {@link SatelliteSessionStats} 424 * and then returns the Builder class. 425 */ 426 @NonNull setCountOfUserMessagesInQueueToBeSent(int count)427 public Builder setCountOfUserMessagesInQueueToBeSent(int count) { 428 mCountOfUserMessagesInQueueToBeSent = count; 429 return this; 430 } 431 432 @NonNull setLatencyOfSuccessfulUserMessages(long latency)433 public Builder setLatencyOfSuccessfulUserMessages(long latency) { 434 mLatencyOfSuccessfulUserMessages = latency; 435 return this; 436 } 437 438 @NonNull setMaxLatency(long maxLatency)439 public Builder setMaxLatency(long maxLatency) { 440 mMaxLatency = maxLatency; 441 return this; 442 } 443 444 @NonNull setLastLatency(long lastLatency)445 public Builder setLastLatency(long lastLatency) { 446 mLastMessageLatency = lastLatency; 447 return this; 448 } 449 450 /** Returns SatelliteSessionStats object. */ 451 @NonNull build()452 public SatelliteSessionStats build() { 453 return new SatelliteSessionStats(this); 454 } 455 } 456 }