1 /* 2 * Copyright (C) 2021 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.internal.telephony.metrics; 18 19 import static android.text.format.DateUtils.SECOND_IN_MILLIS; 20 21 import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_CALL_COMPOSER; 22 import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_CHATBOT; 23 import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_CHATBOT_ROLE; 24 import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_CHATBOT_STANDALONE; 25 import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_CHAT_V1; 26 import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_CHAT_V2; 27 import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_CUSTOM; 28 import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_FT; 29 import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_FT_OVER_SMS; 30 import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_GEO_PUSH; 31 import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_GEO_PUSH_VIA_SMS; 32 import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_MMTEL; 33 import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_POST_CALL; 34 import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_SHARED_MAP; 35 import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_SHARED_SKETCH; 36 import static com.android.internal.telephony.TelephonyStatsLog.PRESENCE_NOTIFY_EVENT__REASON__REASON_CUSTOM; 37 import static com.android.internal.telephony.TelephonyStatsLog.PRESENCE_NOTIFY_EVENT__REASON__REASON_DEACTIVATED; 38 import static com.android.internal.telephony.TelephonyStatsLog.PRESENCE_NOTIFY_EVENT__REASON__REASON_GIVEUP; 39 import static com.android.internal.telephony.TelephonyStatsLog.PRESENCE_NOTIFY_EVENT__REASON__REASON_NORESOURCE; 40 import static com.android.internal.telephony.TelephonyStatsLog.PRESENCE_NOTIFY_EVENT__REASON__REASON_PROBATION; 41 import static com.android.internal.telephony.TelephonyStatsLog.PRESENCE_NOTIFY_EVENT__REASON__REASON_REJECTED; 42 import static com.android.internal.telephony.TelephonyStatsLog.PRESENCE_NOTIFY_EVENT__REASON__REASON_TIMEOUT; 43 import static com.android.internal.telephony.TelephonyStatsLog.RCS_ACS_PROVISIONING_STATS__RESPONSE_TYPE__ERROR; 44 import static com.android.internal.telephony.TelephonyStatsLog.RCS_ACS_PROVISIONING_STATS__RESPONSE_TYPE__PRE_PROVISIONING_XML; 45 import static com.android.internal.telephony.TelephonyStatsLog.UCE_EVENT_STATS__TYPE__INCOMING_OPTION; 46 import static com.android.internal.telephony.TelephonyStatsLog.UCE_EVENT_STATS__TYPE__OUTGOING_OPTION; 47 import static com.android.internal.telephony.TelephonyStatsLog.UCE_EVENT_STATS__TYPE__PUBLISH; 48 import static com.android.internal.telephony.TelephonyStatsLog.UCE_EVENT_STATS__TYPE__SUBSCRIBE; 49 50 import android.annotation.NonNull; 51 import android.os.Binder; 52 import android.telephony.SubscriptionManager; 53 import android.telephony.TelephonyManager; 54 import android.telephony.TelephonyProtoEnums; 55 import android.telephony.ims.FeatureTagState; 56 import android.telephony.ims.RcsContactPresenceTuple; 57 import android.telephony.ims.RcsContactUceCapability; 58 import android.telephony.ims.aidl.IRcsConfigCallback; 59 import android.util.IndentingPrintWriter; 60 61 import com.android.ims.rcs.uce.UceStatsWriter; 62 import com.android.ims.rcs.uce.UceStatsWriter.UceStatsCallback; 63 import com.android.ims.rcs.uce.util.FeatureTags; 64 import com.android.internal.annotations.VisibleForTesting; 65 import com.android.internal.telephony.Phone; 66 import com.android.internal.telephony.PhoneFactory; 67 import com.android.internal.telephony.nano.PersistAtomsProto; 68 import com.android.internal.telephony.nano.PersistAtomsProto.GbaEvent; 69 import com.android.internal.telephony.nano.PersistAtomsProto.ImsDedicatedBearerEvent; 70 import com.android.internal.telephony.nano.PersistAtomsProto.ImsDedicatedBearerListenerEvent; 71 import com.android.internal.telephony.nano.PersistAtomsProto.ImsRegistrationFeatureTagStats; 72 import com.android.internal.telephony.nano.PersistAtomsProto.ImsRegistrationServiceDescStats; 73 import com.android.internal.telephony.nano.PersistAtomsProto.PresenceNotifyEvent; 74 import com.android.internal.telephony.nano.PersistAtomsProto.RcsAcsProvisioningStats; 75 import com.android.internal.telephony.nano.PersistAtomsProto.RcsClientProvisioningStats; 76 import com.android.internal.telephony.nano.PersistAtomsProto.SipDelegateStats; 77 import com.android.internal.telephony.nano.PersistAtomsProto.SipMessageResponse; 78 import com.android.internal.telephony.nano.PersistAtomsProto.SipTransportFeatureTagStats; 79 import com.android.internal.telephony.nano.PersistAtomsProto.SipTransportSession; 80 import com.android.internal.telephony.nano.PersistAtomsProto.UceEventStats; 81 import com.android.telephony.Rlog; 82 83 import java.io.PrintWriter; 84 import java.util.ArrayList; 85 import java.util.HashMap; 86 import java.util.HashSet; 87 import java.util.List; 88 import java.util.Map; 89 import java.util.Random; 90 import java.util.Set; 91 92 /** Tracks RCS provisioning, sip transport, UCE metrics for phone. */ 93 public class RcsStats { 94 private static final String TAG = RcsStats.class.getSimpleName(); 95 private static final long MIN_DURATION_MILLIS = 1L * SECOND_IN_MILLIS; 96 private final PersistAtomsStorage mAtomsStorage = 97 PhoneFactory.getMetricsCollector().getAtomsStorage(); 98 private static final Random RANDOM = new Random(); 99 100 private UceStatsWriterCallback mCallback; 101 private static RcsStats sInstance; 102 103 public static final int NONE = -1; 104 public static final int STATE_REGISTERED = 0; 105 public static final int STATE_DEREGISTERED = 1; 106 public static final int STATE_DENIED = 2; 107 108 private static final String SIP_REQUEST_MESSAGE_TYPE_INVITE = "INVITE"; 109 private static final String SIP_REQUEST_MESSAGE_TYPE_ACK = "ACK"; 110 private static final String SIP_REQUEST_MESSAGE_TYPE_OPTIONS = "OPTIONS"; 111 private static final String SIP_REQUEST_MESSAGE_TYPE_BYE = "BYE"; 112 private static final String SIP_REQUEST_MESSAGE_TYPE_CANCEL = "CANCEL"; 113 private static final String SIP_REQUEST_MESSAGE_TYPE_REGISTER = "REGISTER"; 114 private static final String SIP_REQUEST_MESSAGE_TYPE_PRACK = "PRACK"; 115 private static final String SIP_REQUEST_MESSAGE_TYPE_SUBSCRIBE = "SUBSCRIBE"; 116 private static final String SIP_REQUEST_MESSAGE_TYPE_NOTIFY = "NOTIFY"; 117 private static final String SIP_REQUEST_MESSAGE_TYPE_PUBLISH = "PUBLISH"; 118 private static final String SIP_REQUEST_MESSAGE_TYPE_INFO = "INFO"; 119 private static final String SIP_REQUEST_MESSAGE_TYPE_REFER = "REFER"; 120 private static final String SIP_REQUEST_MESSAGE_TYPE_MESSAGE = "MESSAGE"; 121 private static final String SIP_REQUEST_MESSAGE_TYPE_UPDATE = "UPDATE"; 122 123 /** 124 * Describe Feature Tags 125 * See frameworks/opt/net/ims/src/java/com/android/ims/rcs/uce/util/FeatureTags.java 126 * and int value matching the Feature Tags 127 * See stats/enums/telephony/enums.proto 128 */ 129 private static final Map<String, Integer> FEATURE_TAGS = new HashMap<>(); 130 131 static { 132 FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_STANDALONE_MSG.trim().toLowerCase(), 133 TelephonyProtoEnums.IMS_FEATURE_TAG_STANDALONE_MSG); 134 FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_CHAT_IM.trim().toLowerCase(), 135 TelephonyProtoEnums.IMS_FEATURE_TAG_CHAT_IM); 136 FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_CHAT_SESSION.trim().toLowerCase(), 137 TelephonyProtoEnums.IMS_FEATURE_TAG_CHAT_SESSION); 138 FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_FILE_TRANSFER.trim().toLowerCase(), 139 TelephonyProtoEnums.IMS_FEATURE_TAG_FILE_TRANSFER); 140 FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_FILE_TRANSFER_VIA_SMS.trim().toLowerCase(), 141 TelephonyProtoEnums.IMS_FEATURE_TAG_FILE_TRANSFER_VIA_SMS); 142 FEATURE_TAGS.put( 143 FeatureTags.FEATURE_TAG_CALL_COMPOSER_ENRICHED_CALLING.trim().toLowerCase(), 144 TelephonyProtoEnums.IMS_FEATURE_TAG_CALL_COMPOSER_ENRICHED_CALLING); 145 FEATURE_TAGS.put( 146 FeatureTags.FEATURE_TAG_CALL_COMPOSER_VIA_TELEPHONY.trim().toLowerCase(), 147 TelephonyProtoEnums.IMS_FEATURE_TAG_CALL_COMPOSER_VIA_TELEPHONY); 148 FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_POST_CALL.trim().toLowerCase(), 149 TelephonyProtoEnums.IMS_FEATURE_TAG_POST_CALL); 150 FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_SHARED_MAP.trim().toLowerCase(), 151 TelephonyProtoEnums.IMS_FEATURE_TAG_SHARED_MAP); 152 FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_SHARED_SKETCH.trim().toLowerCase(), 153 TelephonyProtoEnums.IMS_FEATURE_TAG_SHARED_SKETCH); 154 FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_GEO_PUSH.trim().toLowerCase(), 155 TelephonyProtoEnums.IMS_FEATURE_TAG_GEO_PUSH); 156 FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_GEO_PUSH_VIA_SMS.trim().toLowerCase(), 157 TelephonyProtoEnums.IMS_FEATURE_TAG_GEO_PUSH_VIA_SMS); 158 FEATURE_TAGS.put( 159 FeatureTags.FEATURE_TAG_CHATBOT_COMMUNICATION_USING_SESSION.trim().toLowerCase(), 160 TelephonyProtoEnums.IMS_FEATURE_TAG_CHATBOT_COMMUNICATION_USING_SESSION); 161 String FeatureTag = FeatureTags.FEATURE_TAG_CHATBOT_COMMUNICATION_USING_STANDALONE_MSG; 162 FEATURE_TAGS.put(FeatureTag.trim().toLowerCase(), 163 TelephonyProtoEnums.IMS_FEATURE_TAG_CHATBOT_COMMUNICATION_USING_STANDALONE_MSG); 164 FEATURE_TAGS.put( 165 FeatureTags.FEATURE_TAG_CHATBOT_VERSION_SUPPORTED.trim().toLowerCase(), 166 TelephonyProtoEnums.IMS_FEATURE_TAG_CHATBOT_VERSION_SUPPORTED); 167 FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_CHATBOT_ROLE.trim().toLowerCase(), 168 TelephonyProtoEnums.IMS_FEATURE_TAG_CHATBOT_ROLE); 169 FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_MMTEL.trim().toLowerCase(), 170 TelephonyProtoEnums.IMS_FEATURE_TAG_MMTEL); 171 FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_VIDEO.trim().toLowerCase(), 172 TelephonyProtoEnums.IMS_FEATURE_TAG_VIDEO); 173 FEATURE_TAGS.put(FeatureTags.FEATURE_TAG_PRESENCE.trim().toLowerCase(), 174 TelephonyProtoEnums.IMS_FEATURE_TAG_PRESENCE); 175 } 176 177 /** 178 * Describe Service IDs 179 * See frameworks/base/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java 180 * and int value matching the service IDs 181 * See frameworks/proto_logging/stats/atoms.proto 182 */ 183 private static final Map<String, Integer> SERVICE_IDS = new HashMap<>(); 184 185 static { 186 SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_MMTEL.trim().toLowerCase(), 187 IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_MMTEL); 188 SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_CHAT_V1.trim().toLowerCase(), 189 IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_CHAT_V1); 190 SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_CHAT_V2.trim().toLowerCase(), 191 IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_CHAT_V2); 192 SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_FT.trim().toLowerCase(), 193 IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_FT); 194 SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_FT_OVER_SMS.trim().toLowerCase(), 195 IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_FT_OVER_SMS); 196 SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_GEO_PUSH.trim().toLowerCase(), 197 IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_GEO_PUSH); 198 SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_GEO_PUSH_VIA_SMS.trim().toLowerCase(), 199 IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_GEO_PUSH_VIA_SMS); 200 SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_CALL_COMPOSER.trim().toLowerCase(), 201 IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_CALL_COMPOSER); 202 SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_POST_CALL.trim().toLowerCase(), 203 IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_POST_CALL); 204 SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_SHARED_MAP.trim().toLowerCase(), 205 IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_SHARED_MAP); 206 SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_SHARED_SKETCH.trim().toLowerCase(), 207 IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_SHARED_SKETCH); 208 SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_CHATBOT.trim().toLowerCase(), 209 IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_CHATBOT); 210 SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_CHATBOT_STANDALONE.trim().toLowerCase(), 211 IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_CHATBOT_STANDALONE 212 ); 213 SERVICE_IDS.put(RcsContactPresenceTuple.SERVICE_ID_CHATBOT_ROLE.trim().toLowerCase(), 214 IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_CHATBOT_ROLE); 215 } 216 217 /** 218 * Describe Message Method Type 219 * See stats/enums/telephony/enums.proto 220 */ 221 private static final Map<String, Integer> MESSAGE_TYPE = new HashMap<>(); 222 223 static { 224 MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_INVITE.trim().toLowerCase(), 225 TelephonyProtoEnums.SIP_REQUEST_INVITE); 226 MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_ACK.trim().toLowerCase(), 227 TelephonyProtoEnums.SIP_REQUEST_ACK); 228 MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_OPTIONS.trim().toLowerCase(), 229 TelephonyProtoEnums.SIP_REQUEST_OPTIONS); 230 MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_BYE.trim().toLowerCase(), 231 TelephonyProtoEnums.SIP_REQUEST_BYE); 232 MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_CANCEL.trim().toLowerCase(), 233 TelephonyProtoEnums.SIP_REQUEST_CANCEL); 234 MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_REGISTER.trim().toLowerCase(), 235 TelephonyProtoEnums.SIP_REQUEST_REGISTER); 236 MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_PRACK.trim().toLowerCase(), 237 TelephonyProtoEnums.SIP_REQUEST_PRACK); 238 MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_SUBSCRIBE.trim().toLowerCase(), 239 TelephonyProtoEnums.SIP_REQUEST_SUBSCRIBE); 240 MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_NOTIFY.trim().toLowerCase(), 241 TelephonyProtoEnums.SIP_REQUEST_NOTIFY); 242 MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_PUBLISH.trim().toLowerCase(), 243 TelephonyProtoEnums.SIP_REQUEST_PUBLISH); 244 MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_INFO.trim().toLowerCase(), 245 TelephonyProtoEnums.SIP_REQUEST_INFO); 246 MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_REFER.trim().toLowerCase(), 247 TelephonyProtoEnums.SIP_REQUEST_REFER); 248 MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_MESSAGE.trim().toLowerCase(), 249 TelephonyProtoEnums.SIP_REQUEST_MESSAGE); 250 MESSAGE_TYPE.put(SIP_REQUEST_MESSAGE_TYPE_UPDATE.trim().toLowerCase(), 251 TelephonyProtoEnums.SIP_REQUEST_UPDATE); 252 } 253 254 /** 255 * Describe Reasons 256 * See frameworks/opt/net/ims/src/java/com/android/ims/rcs/uce/request/ 257 * SubscriptionTerminatedHelper.java 258 * and int value matching the Reasons 259 * See frameworks/proto_logging/stats/atoms.proto 260 */ 261 private static final Map<String, Integer> NOTIFY_REASONS = new HashMap<>(); 262 263 static { 264 NOTIFY_REASONS.put("deactivated", PRESENCE_NOTIFY_EVENT__REASON__REASON_DEACTIVATED); 265 NOTIFY_REASONS.put("probation", PRESENCE_NOTIFY_EVENT__REASON__REASON_PROBATION); 266 NOTIFY_REASONS.put("rejected", PRESENCE_NOTIFY_EVENT__REASON__REASON_REJECTED); 267 NOTIFY_REASONS.put("timeout", PRESENCE_NOTIFY_EVENT__REASON__REASON_TIMEOUT); 268 NOTIFY_REASONS.put("giveup", PRESENCE_NOTIFY_EVENT__REASON__REASON_GIVEUP); 269 NOTIFY_REASONS.put("noresource", PRESENCE_NOTIFY_EVENT__REASON__REASON_NORESOURCE); 270 } 271 272 /** 273 * Describe Rcs Capability set 274 * See frameworks/base/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java 275 */ 276 private static final HashSet<String> RCS_SERVICE_ID_SET = new HashSet<>(); 277 static { 278 RCS_SERVICE_ID_SET.add(RcsContactPresenceTuple.SERVICE_ID_CHAT_V1); 279 RCS_SERVICE_ID_SET.add(RcsContactPresenceTuple.SERVICE_ID_CHAT_V2); 280 RCS_SERVICE_ID_SET.add(RcsContactPresenceTuple.SERVICE_ID_FT); 281 RCS_SERVICE_ID_SET.add(RcsContactPresenceTuple.SERVICE_ID_FT_OVER_SMS); 282 RCS_SERVICE_ID_SET.add(RcsContactPresenceTuple.SERVICE_ID_GEO_PUSH); 283 RCS_SERVICE_ID_SET.add(RcsContactPresenceTuple.SERVICE_ID_GEO_PUSH_VIA_SMS); 284 RCS_SERVICE_ID_SET.add(RcsContactPresenceTuple.SERVICE_ID_SHARED_MAP); 285 RCS_SERVICE_ID_SET.add(RcsContactPresenceTuple.SERVICE_ID_SHARED_SKETCH); 286 RCS_SERVICE_ID_SET.add(RcsContactPresenceTuple.SERVICE_ID_CHATBOT); 287 RCS_SERVICE_ID_SET.add(RcsContactPresenceTuple.SERVICE_ID_CHATBOT_STANDALONE); 288 RCS_SERVICE_ID_SET.add(RcsContactPresenceTuple.SERVICE_ID_CHATBOT_ROLE); 289 } 290 291 /** 292 * Describe Mmtel Capability set 293 * See frameworks/base/telephony/java/android/telephony/ims/RcsContactPresenceTuple.java 294 */ 295 private static final HashSet<String> MMTEL_SERVICE_ID_SET = new HashSet<>(); 296 static { 297 MMTEL_SERVICE_ID_SET.add(RcsContactPresenceTuple.SERVICE_ID_MMTEL); 298 MMTEL_SERVICE_ID_SET.add(RcsContactPresenceTuple.SERVICE_ID_CALL_COMPOSER); 299 MMTEL_SERVICE_ID_SET.add(RcsContactPresenceTuple.SERVICE_ID_POST_CALL); 300 } 301 302 private static final Map<Long, Integer> sSubscribeTaskIds = new HashMap<>(); 303 private static final int SUBSCRIBE_SUCCESS = 1; 304 private static final int SUBSCRIBE_NOTIFY = 2; 305 306 @VisibleForTesting 307 protected final Map<Integer, ImsDedicatedBearerListenerEvent> mDedicatedBearerListenerEventMap = 308 new HashMap<>(); 309 @VisibleForTesting 310 protected final List<RcsAcsProvisioningStats> mRcsAcsProvisioningStatsList = 311 new ArrayList<RcsAcsProvisioningStats>(); 312 @VisibleForTesting 313 protected final HashMap<Integer, RcsProvisioningCallback> mRcsProvisioningCallbackMap = 314 new HashMap<>(); 315 316 // Maps feature tag name -> ImsRegistrationFeatureTagStats. 317 private final List<ImsRegistrationFeatureTagStats> mImsRegistrationFeatureTagStatsList = 318 new ArrayList<>(); 319 320 // Maps service id -> ImsRegistrationServiceDescStats. 321 @VisibleForTesting 322 protected final List<ImsRegistrationServiceDescStats> mImsRegistrationServiceDescStatsList = 323 new ArrayList<>(); 324 325 private List<LastSipDelegateStat> mLastSipDelegateStatList = new ArrayList<>(); 326 private HashMap<Integer, SipTransportFeatureTags> mLastFeatureTagStatMap = new HashMap<>(); 327 private ArrayList<SipMessageArray> mSipMessageArray = new ArrayList<>(); 328 private ArrayList<SipTransportSessionArray> mSipTransportSessionArray = new ArrayList<>(); 329 private SipTransportSessionArray mSipTransportSession; 330 private SipMessageArray mSipMessage; 331 332 private class LastSipDelegateStat { 333 public int mSubId; 334 public SipDelegateStats mLastStat; 335 private Set<String> mSupportedTags; 336 LastSipDelegateStat(int subId, Set<String> supportedTags)337 LastSipDelegateStat(int subId, Set<String> supportedTags) { 338 mSubId = subId; 339 mSupportedTags = supportedTags; 340 } 341 createSipDelegateStat(int subId)342 public void createSipDelegateStat(int subId) { 343 mLastStat = getDefaultSipDelegateStat(subId); 344 mLastStat.uptimeMillis = getWallTimeMillis(); 345 mLastStat.destroyReason = NONE; 346 } 347 setSipDelegateDestroyReason(int destroyReason)348 public void setSipDelegateDestroyReason(int destroyReason) { 349 mLastStat.destroyReason = destroyReason; 350 } 351 isDestroyed()352 public boolean isDestroyed() { 353 return mLastStat.destroyReason > NONE; 354 } 355 conclude(long now)356 public void conclude(long now) { 357 long duration = now - mLastStat.uptimeMillis; 358 if (duration < MIN_DURATION_MILLIS) { 359 logd("concludeSipDelegateStat: discarding transient stats," 360 + " duration= " + duration); 361 } else { 362 mLastStat.uptimeMillis = duration; 363 mAtomsStorage.addSipDelegateStats(copyOf(mLastStat)); 364 } 365 mLastStat.uptimeMillis = now; 366 } 367 compare(int subId, Set<String> supportedTags)368 public boolean compare(int subId, Set<String> supportedTags) { 369 if (subId != mSubId || supportedTags == null || supportedTags.isEmpty()) { 370 return false; 371 } 372 for (String tag : supportedTags) { 373 if (!mSupportedTags.contains(tag)) { 374 return false; 375 } 376 } 377 return true; 378 } 379 getDefaultSipDelegateStat(int subId)380 private SipDelegateStats getDefaultSipDelegateStat(int subId) { 381 SipDelegateStats stat = new SipDelegateStats(); 382 stat.dimension = RANDOM.nextInt(); 383 stat.carrierId = getCarrierId(subId); 384 stat.slotId = getSlotId(subId); 385 return stat; 386 } 387 } 388 copyOf(@onNull SipDelegateStats source)389 private static SipDelegateStats copyOf(@NonNull SipDelegateStats source) { 390 SipDelegateStats newStat = new SipDelegateStats(); 391 392 newStat.dimension = source.dimension; 393 newStat.slotId = source.slotId; 394 newStat.carrierId = source.carrierId; 395 newStat.destroyReason = source.destroyReason; 396 newStat.uptimeMillis = source.uptimeMillis; 397 398 return newStat; 399 } 400 401 private class SipTransportFeatureTags { 402 private HashMap<String, LastFeatureTagState> mFeatureTagMap; 403 private int mSubId; 404 405 private class LastFeatureTagState { 406 public long timeStamp; 407 public int carrierId; 408 public int slotId; 409 public int state; 410 public int reason; 411 LastFeatureTagState(int carrierId, int slotId, int state, int reason, long timeStamp)412 LastFeatureTagState(int carrierId, int slotId, int state, int reason, long timeStamp) { 413 this.carrierId = carrierId; 414 this.slotId = slotId; 415 this.state = state; 416 this.reason = reason; 417 this.timeStamp = timeStamp; 418 } 419 update(int state, int reason, long timeStamp)420 public void update(int state, int reason, long timeStamp) { 421 this.state = state; 422 this.reason = reason; 423 this.timeStamp = timeStamp; 424 } 425 update(long timeStamp)426 public void update(long timeStamp) { 427 this.timeStamp = timeStamp; 428 } 429 } 430 SipTransportFeatureTags(int subId)431 SipTransportFeatureTags(int subId) { 432 mFeatureTagMap = new HashMap<>(); 433 mSubId = subId; 434 } 435 getLastTagStates()436 public HashMap<String, LastFeatureTagState> getLastTagStates() { 437 return mFeatureTagMap; 438 } 439 440 /*** Create or update featureTags whenever feature Tag states are changed */ updateLastFeatureTagState(String tagName, int state, int reason, long timeStamp)441 public synchronized void updateLastFeatureTagState(String tagName, int state, int reason, 442 long timeStamp) { 443 int carrierId = getCarrierId(mSubId); 444 int slotId = getSlotId(mSubId); 445 if (mFeatureTagMap.containsKey(tagName)) { 446 LastFeatureTagState lastFeatureTagState = mFeatureTagMap.get(tagName); 447 if (lastFeatureTagState != null) { 448 addFeatureTagStat(tagName, lastFeatureTagState, timeStamp); 449 lastFeatureTagState.update(state, reason, timeStamp); 450 } else { 451 create(tagName, carrierId, slotId, state, reason, timeStamp); 452 } 453 454 } else { 455 create(tagName, carrierId, slotId, state, reason, timeStamp); 456 } 457 } 458 459 /** Update current featureTags associated to active SipDelegates when metrics is pulled */ conclude(long timeStamp)460 public synchronized void conclude(long timeStamp) { 461 HashMap<String, LastFeatureTagState> featureTagsCopy = new HashMap<>(); 462 featureTagsCopy.putAll(mFeatureTagMap); 463 for (Map.Entry<String, LastFeatureTagState> last : featureTagsCopy.entrySet()) { 464 String tagName = last.getKey(); 465 LastFeatureTagState lastFeatureTagState = last.getValue(); 466 addFeatureTagStat(tagName, lastFeatureTagState, timeStamp); 467 updateTimeStamp(mSubId, tagName, timeStamp); 468 } 469 } 470 471 /** Finalizes the durations of the current featureTags associated to active SipDelegates */ addFeatureTagStat(@onNull String tagName, @NonNull LastFeatureTagState lastFeatureTagState, long now)472 private synchronized boolean addFeatureTagStat(@NonNull String tagName, 473 @NonNull LastFeatureTagState lastFeatureTagState, long now) { 474 long duration = now - lastFeatureTagState.timeStamp; 475 if (duration < MIN_DURATION_MILLIS 476 || !isValidCarrierId(lastFeatureTagState.carrierId)) { 477 logd("conclude: discarding transient stats, duration= " + duration 478 + ", carrierId = " + lastFeatureTagState.carrierId); 479 } else { 480 SipTransportFeatureTagStats sipFeatureTagStat = new SipTransportFeatureTagStats(); 481 switch (lastFeatureTagState.state) { 482 case STATE_DENIED: 483 sipFeatureTagStat.sipTransportDeniedReason = lastFeatureTagState.reason; 484 sipFeatureTagStat.sipTransportDeregisteredReason = NONE; 485 break; 486 case STATE_DEREGISTERED: 487 sipFeatureTagStat.sipTransportDeniedReason = NONE; 488 sipFeatureTagStat.sipTransportDeregisteredReason = 489 lastFeatureTagState.reason; 490 break; 491 default: 492 sipFeatureTagStat.sipTransportDeniedReason = NONE; 493 sipFeatureTagStat.sipTransportDeregisteredReason = NONE; 494 break; 495 } 496 497 sipFeatureTagStat.carrierId = lastFeatureTagState.carrierId; 498 sipFeatureTagStat.slotId = lastFeatureTagState.slotId; 499 sipFeatureTagStat.associatedMillis = duration; 500 sipFeatureTagStat.featureTagName = convertTagNameToValue(tagName); 501 mAtomsStorage.addSipTransportFeatureTagStats(sipFeatureTagStat); 502 return true; 503 } 504 return false; 505 } 506 updateTimeStamp(int subId, String tagName, long timeStamp)507 private void updateTimeStamp(int subId, String tagName, long timeStamp) { 508 SipTransportFeatureTags sipTransportFeatureTags = mLastFeatureTagStatMap.get(subId); 509 if (sipTransportFeatureTags != null) { 510 HashMap<String, LastFeatureTagState> lastTagStates = 511 sipTransportFeatureTags.getLastTagStates(); 512 if (lastTagStates != null && lastTagStates.containsKey(tagName)) { 513 LastFeatureTagState lastFeatureTagState = lastTagStates.get(tagName); 514 if (lastFeatureTagState != null) { 515 lastFeatureTagState.update(timeStamp); 516 } 517 } 518 } 519 } 520 create(String tagName, int carrierId, int slotId, int state, int reason, long timeStamp)521 private LastFeatureTagState create(String tagName, int carrierId, int slotId, int state, 522 int reason, long timeStamp) { 523 LastFeatureTagState lastFeatureTagState = new LastFeatureTagState(carrierId, slotId, 524 state, reason, timeStamp); 525 mFeatureTagMap.put(tagName, lastFeatureTagState); 526 return lastFeatureTagState; 527 } 528 } 529 530 class UceStatsWriterCallback implements UceStatsCallback { 531 private RcsStats mRcsStats; 532 UceStatsWriterCallback(RcsStats rcsStats)533 UceStatsWriterCallback(RcsStats rcsStats) { 534 logd("created Callback"); 535 mRcsStats = rcsStats; 536 } 537 onImsRegistrationFeatureTagStats(int subId, List<String> featureTagList, int registrationTech)538 public void onImsRegistrationFeatureTagStats(int subId, List<String> featureTagList, 539 int registrationTech) { 540 mRcsStats.onImsRegistrationFeatureTagStats(subId, featureTagList, registrationTech); 541 } 542 onStoreCompleteImsRegistrationFeatureTagStats(int subId)543 public void onStoreCompleteImsRegistrationFeatureTagStats(int subId) { 544 mRcsStats.onStoreCompleteImsRegistrationFeatureTagStats(subId); 545 } 546 onImsRegistrationServiceDescStats(int subId, List<String> serviceIdList, List<String> serviceIdVersionList, int registrationTech)547 public void onImsRegistrationServiceDescStats(int subId, List<String> serviceIdList, 548 List<String> serviceIdVersionList, int registrationTech) { 549 mRcsStats.onImsRegistrationServiceDescStats(subId, serviceIdList, serviceIdVersionList, 550 registrationTech); 551 } 552 onSubscribeResponse(int subId, long taskId, int networkResponse)553 public void onSubscribeResponse(int subId, long taskId, int networkResponse) { 554 if (networkResponse >= 200 && networkResponse <= 299) { 555 if (!sSubscribeTaskIds.containsKey(taskId)) { 556 sSubscribeTaskIds.put(taskId, SUBSCRIBE_SUCCESS); 557 } 558 } 559 mRcsStats.onUceEventStats(subId, UCE_EVENT_STATS__TYPE__SUBSCRIBE, 560 true, 0, networkResponse); 561 } 562 onUceEvent(int subId, int type, boolean successful, int commandCode, int networkResponse)563 public void onUceEvent(int subId, int type, boolean successful, int commandCode, 564 int networkResponse) { 565 int eventType = 0; 566 switch (type) { 567 case UceStatsWriter.PUBLISH_EVENT: 568 eventType = UCE_EVENT_STATS__TYPE__PUBLISH; 569 break; 570 case UceStatsWriter.SUBSCRIBE_EVENT: 571 eventType = UCE_EVENT_STATS__TYPE__SUBSCRIBE; 572 break; 573 case UceStatsWriter.INCOMING_OPTION_EVENT: 574 eventType = UCE_EVENT_STATS__TYPE__INCOMING_OPTION; 575 break; 576 case UceStatsWriter.OUTGOING_OPTION_EVENT: 577 eventType = UCE_EVENT_STATS__TYPE__OUTGOING_OPTION; 578 break; 579 default: 580 return; 581 } 582 mRcsStats.onUceEventStats(subId, eventType, successful, commandCode, networkResponse); 583 } 584 onSubscribeTerminated(int subId, long taskId, String reason)585 public void onSubscribeTerminated(int subId, long taskId, String reason) { 586 if (sSubscribeTaskIds.containsKey(taskId)) { 587 int previousSubscribeStatus = sSubscribeTaskIds.get(taskId); 588 sSubscribeTaskIds.remove(taskId); 589 // The device received a success response related to the subscription request. 590 // However, PIDF was not received due to reason value. 591 if (previousSubscribeStatus == SUBSCRIBE_SUCCESS) { 592 mRcsStats.onPresenceNotifyEvent(subId, reason, false, 593 false, false, false); 594 } 595 } 596 } 597 onPresenceNotifyEvent(int subId, long taskId, List<RcsContactUceCapability> updatedCapList)598 public void onPresenceNotifyEvent(int subId, long taskId, 599 List<RcsContactUceCapability> updatedCapList) { 600 if (updatedCapList == null || updatedCapList.isEmpty()) { 601 return; 602 } 603 if (sSubscribeTaskIds.containsKey(taskId)) { 604 sSubscribeTaskIds.replace(taskId, SUBSCRIBE_NOTIFY); 605 } 606 for (RcsContactUceCapability capability : updatedCapList) { 607 boolean rcsCap = false; 608 boolean mmtelCap = false; 609 boolean noCap = true; 610 List<RcsContactPresenceTuple> tupleList = capability.getCapabilityTuples(); 611 if (tupleList.isEmpty()) { 612 noCap = true; 613 mRcsStats.onPresenceNotifyEvent(subId, "", true, 614 rcsCap, mmtelCap, noCap); 615 continue; 616 } 617 for (RcsContactPresenceTuple tuple : tupleList) { 618 String serviceId = tuple.getServiceId(); 619 if (RCS_SERVICE_ID_SET.contains(serviceId)) { 620 rcsCap = true; 621 noCap = false; 622 } else if (MMTEL_SERVICE_ID_SET.contains(serviceId)) { 623 if (serviceId.equals(RcsContactPresenceTuple.SERVICE_ID_CALL_COMPOSER)) { 624 if ("1.0".equals(tuple.getServiceVersion())) { 625 rcsCap = true; 626 noCap = false; 627 continue; 628 } 629 } 630 mmtelCap = true; 631 noCap = false; 632 } 633 } 634 mRcsStats.onPresenceNotifyEvent(subId, "", true, rcsCap, 635 mmtelCap, noCap); 636 } 637 } 638 onStoreCompleteImsRegistrationServiceDescStats(int subId)639 public void onStoreCompleteImsRegistrationServiceDescStats(int subId) { 640 mRcsStats.onStoreCompleteImsRegistrationServiceDescStats(subId); 641 } 642 } 643 644 /** Callback class to receive RCS ACS result and to store metrics. */ 645 public class RcsProvisioningCallback extends IRcsConfigCallback.Stub { 646 private RcsStats mRcsStats; 647 private int mSubId; 648 private boolean mEnableSingleRegistration; 649 private boolean mRegistered; 650 RcsProvisioningCallback(RcsStats rcsStats, int subId, boolean enableSingleRegistration)651 RcsProvisioningCallback(RcsStats rcsStats, int subId, boolean enableSingleRegistration) { 652 logd("created RcsProvisioningCallback"); 653 mRcsStats = rcsStats; 654 mSubId = subId; 655 mEnableSingleRegistration = enableSingleRegistration; 656 mRegistered = false; 657 } 658 setEnableSingleRegistration(boolean enableSingleRegistration)659 public synchronized void setEnableSingleRegistration(boolean enableSingleRegistration) { 660 mEnableSingleRegistration = enableSingleRegistration; 661 } 662 getRegistered()663 public boolean getRegistered() { 664 return mRegistered; 665 } 666 setRegistered(boolean registered)667 public void setRegistered(boolean registered) { 668 mRegistered = registered; 669 } 670 671 @Override onConfigurationChanged(byte[] config)672 public void onConfigurationChanged(byte[] config) { 673 // this callback will not be handled. 674 } 675 676 @Override onAutoConfigurationErrorReceived(int errorCode, String errorString)677 public void onAutoConfigurationErrorReceived(int errorCode, String errorString) { 678 final long callingIdentity = Binder.clearCallingIdentity(); 679 try { 680 mRcsStats.onRcsAcsProvisioningStats(mSubId, errorCode, 681 RCS_ACS_PROVISIONING_STATS__RESPONSE_TYPE__ERROR, 682 mEnableSingleRegistration); 683 } finally { 684 restoreCallingIdentity(callingIdentity); 685 } 686 } 687 688 @Override onConfigurationReset()689 public void onConfigurationReset() { 690 // this callback will not be handled. 691 } 692 693 @Override onRemoved()694 public void onRemoved() { 695 final long callingIdentity = Binder.clearCallingIdentity(); 696 try { 697 // store cached metrics 698 mRcsStats.onStoreCompleteRcsAcsProvisioningStats(mSubId); 699 // remove this obj from Map 700 mRcsStats.removeRcsProvisioningCallback(mSubId); 701 } finally { 702 restoreCallingIdentity(callingIdentity); 703 } 704 } 705 706 @Override onPreProvisioningReceived(byte[] config)707 public void onPreProvisioningReceived(byte[] config) { 708 final long callingIdentity = Binder.clearCallingIdentity(); 709 try { 710 // Receiving pre provisioning means http 200 OK with body. 711 mRcsStats.onRcsAcsProvisioningStats(mSubId, 200, 712 RCS_ACS_PROVISIONING_STATS__RESPONSE_TYPE__PRE_PROVISIONING_XML, 713 mEnableSingleRegistration); 714 } finally { 715 restoreCallingIdentity(callingIdentity); 716 } 717 } 718 }; 719 720 private class SipMessageArray { 721 private String mMethod; 722 private String mCallId; 723 private int mDirection; 724 SipMessageArray(String method, int direction, String callId)725 SipMessageArray(String method, int direction, String callId) { 726 this.mMethod = method; 727 this.mCallId = callId; 728 this.mDirection = direction; 729 } 730 addSipMessageStat( @onNull int subId, @NonNull String sipMessageMethod, int sipMessageResponse, int sipMessageDirection, int messageError)731 private synchronized void addSipMessageStat( 732 @NonNull int subId, @NonNull String sipMessageMethod, 733 int sipMessageResponse, int sipMessageDirection, int messageError) { 734 int carrierId = getCarrierId(subId); 735 if (!isValidCarrierId(carrierId)) { 736 return; 737 } 738 SipMessageResponse proto = new SipMessageResponse(); 739 proto.carrierId = carrierId; 740 proto.slotId = getSlotId(subId); 741 proto.sipMessageMethod = convertMessageTypeToValue(sipMessageMethod); 742 proto.sipMessageResponse = sipMessageResponse; 743 proto.sipMessageDirection = sipMessageDirection; 744 proto.messageError = messageError; 745 proto.count = 1; 746 mAtomsStorage.addSipMessageResponse(proto); 747 } 748 } 749 750 private class SipTransportSessionArray { 751 private String mMethod; 752 private String mCallId; 753 private int mDirection; 754 private int mSipResponse; 755 SipTransportSessionArray(String method, int direction, String callId)756 SipTransportSessionArray(String method, int direction, String callId) { 757 this.mMethod = method; 758 this.mCallId = callId; 759 this.mDirection = direction; 760 this.mSipResponse = 0; 761 } 762 addSipTransportSessionStat( @onNull int subId, @NonNull String sessionMethod, int sipMessageDirection, int sipResponse, boolean isEndedGracefully)763 private synchronized void addSipTransportSessionStat( 764 @NonNull int subId, @NonNull String sessionMethod, int sipMessageDirection, 765 int sipResponse, boolean isEndedGracefully) { 766 int carrierId = getCarrierId(subId); 767 if (!isValidCarrierId(carrierId)) { 768 return; 769 } 770 SipTransportSession proto = new SipTransportSession(); 771 proto.carrierId = carrierId; 772 proto.slotId = getSlotId(subId); 773 proto.sessionMethod = convertMessageTypeToValue(sessionMethod); 774 proto.sipMessageDirection = sipMessageDirection; 775 proto.sipResponse = sipResponse; 776 proto.sessionCount = 1; 777 proto.endedGracefullyCount = 1; 778 proto.isEndedGracefully = isEndedGracefully; 779 mAtomsStorage.addCompleteSipTransportSession(proto); 780 } 781 } 782 783 @VisibleForTesting RcsStats()784 protected RcsStats() { 785 mCallback = null; 786 } 787 788 /** Gets a RcsStats instance. */ getInstance()789 public static RcsStats getInstance() { 790 synchronized (RcsStats.class) { 791 if (sInstance == null) { 792 Rlog.d(TAG, "RcsStats created."); 793 sInstance = new RcsStats(); 794 } 795 return sInstance; 796 } 797 } 798 799 /** register callback to UceStatsWriter. */ registerUceCallback()800 public void registerUceCallback() { 801 if (mCallback == null) { 802 mCallback = new UceStatsWriterCallback(sInstance); 803 Rlog.d(TAG, "UceStatsWriterCallback created."); 804 UceStatsWriter.init(mCallback); 805 } 806 } 807 808 /** Update or create new atom when RCS service registered. */ onImsRegistrationFeatureTagStats(int subId, List<String> featureTagList, int registrationTech)809 public void onImsRegistrationFeatureTagStats(int subId, List<String> featureTagList, 810 int registrationTech) { 811 synchronized (mImsRegistrationFeatureTagStatsList) { 812 int carrierId = getCarrierId(subId); 813 if (!isValidCarrierId(carrierId)) { 814 flushImsRegistrationFeatureTagStatsInvalid(); 815 return; 816 } 817 818 // update cached atom if exists 819 onStoreCompleteImsRegistrationFeatureTagStats(subId); 820 821 if (featureTagList == null) { 822 Rlog.d(TAG, "featureTagNames is null or empty"); 823 return; 824 } 825 826 for (String featureTag : featureTagList) { 827 ImsRegistrationFeatureTagStats proto = new ImsRegistrationFeatureTagStats(); 828 proto.carrierId = carrierId; 829 proto.slotId = getSlotId(subId); 830 proto.featureTagName = convertTagNameToValue(featureTag); 831 proto.registrationTech = registrationTech; 832 proto.registeredMillis = getWallTimeMillis(); 833 mImsRegistrationFeatureTagStatsList.add(proto); 834 } 835 } 836 } 837 838 /** Update duration, store and delete cached ImsRegistrationFeatureTagStats list to storage. */ onStoreCompleteImsRegistrationFeatureTagStats(int subId)839 public void onStoreCompleteImsRegistrationFeatureTagStats(int subId) { 840 synchronized (mImsRegistrationFeatureTagStatsList) { 841 int carrierId = getCarrierId(subId); 842 List<ImsRegistrationFeatureTagStats> deleteList = new ArrayList<>(); 843 long now = getWallTimeMillis(); 844 for (ImsRegistrationFeatureTagStats proto : mImsRegistrationFeatureTagStatsList) { 845 if (proto.carrierId == carrierId) { 846 proto.registeredMillis = now - proto.registeredMillis; 847 mAtomsStorage.addImsRegistrationFeatureTagStats(proto); 848 deleteList.add(proto); 849 } 850 } 851 for (ImsRegistrationFeatureTagStats proto : deleteList) { 852 mImsRegistrationFeatureTagStatsList.remove(proto); 853 } 854 } 855 } 856 857 /** Update duration and store cached ImsRegistrationFeatureTagStats when metrics are pulled */ onFlushIncompleteImsRegistrationFeatureTagStats()858 public void onFlushIncompleteImsRegistrationFeatureTagStats() { 859 synchronized (mImsRegistrationFeatureTagStatsList) { 860 long now = getWallTimeMillis(); 861 for (ImsRegistrationFeatureTagStats proto : mImsRegistrationFeatureTagStatsList) { 862 ImsRegistrationFeatureTagStats newProto = copyImsRegistrationFeatureTagStats(proto); 863 // the current time is a placeholder and total registered time will be 864 // calculated when generating final atoms 865 newProto.registeredMillis = now - proto.registeredMillis; 866 mAtomsStorage.addImsRegistrationFeatureTagStats(newProto); 867 proto.registeredMillis = now; 868 } 869 } 870 } 871 872 /** Create a new atom when RCS client stat changed. */ onRcsClientProvisioningStats(int subId, int event)873 public synchronized void onRcsClientProvisioningStats(int subId, int event) { 874 int carrierId = getCarrierId(subId); 875 876 if (!isValidCarrierId(carrierId)) { 877 return; 878 } 879 880 RcsClientProvisioningStats proto = new RcsClientProvisioningStats(); 881 proto.carrierId = carrierId; 882 proto.slotId = getSlotId(subId); 883 proto.event = event; 884 proto.count = 1; 885 mAtomsStorage.addRcsClientProvisioningStats(proto); 886 } 887 888 /** Update or create new atom when RCS ACS stat changed. */ onRcsAcsProvisioningStats(int subId, int responseCode, int responseType, boolean enableSingleRegistration)889 public void onRcsAcsProvisioningStats(int subId, int responseCode, int responseType, 890 boolean enableSingleRegistration) { 891 892 synchronized (mRcsAcsProvisioningStatsList) { 893 int carrierId = getCarrierId(subId); 894 if (!isValidCarrierId(carrierId)) { 895 flushRcsAcsProvisioningStatsInvalid(); 896 return; 897 } 898 899 // update cached atom if exists 900 onStoreCompleteRcsAcsProvisioningStats(subId); 901 902 // create new stats to cache 903 RcsAcsProvisioningStats newStats = new RcsAcsProvisioningStats(); 904 newStats.carrierId = carrierId; 905 newStats.slotId = getSlotId(subId); 906 newStats.responseCode = responseCode; 907 newStats.responseType = responseType; 908 newStats.isSingleRegistrationEnabled = enableSingleRegistration; 909 newStats.count = 1; 910 newStats.stateTimerMillis = getWallTimeMillis(); 911 912 // add new stats in list 913 mRcsAcsProvisioningStatsList.add(newStats); 914 } 915 } 916 917 /** Update duration, store and delete cached RcsAcsProvisioningStats */ onStoreCompleteRcsAcsProvisioningStats(int subId)918 public void onStoreCompleteRcsAcsProvisioningStats(int subId) { 919 synchronized (mRcsAcsProvisioningStatsList) { 920 // find cached RcsAcsProvisioningStats based sub ID 921 RcsAcsProvisioningStats existingStats = getRcsAcsProvisioningStats(subId); 922 if (existingStats != null) { 923 existingStats.stateTimerMillis = 924 getWallTimeMillis() - existingStats.stateTimerMillis; 925 mAtomsStorage.addRcsAcsProvisioningStats(existingStats); 926 // remove cached atom from list 927 mRcsAcsProvisioningStatsList.remove(existingStats); 928 } 929 } 930 } 931 932 /** Update duration and store cached RcsAcsProvisioningStats when metrics are pulled */ onFlushIncompleteRcsAcsProvisioningStats()933 public void onFlushIncompleteRcsAcsProvisioningStats() { 934 synchronized (mRcsAcsProvisioningStatsList) { 935 long now = getWallTimeMillis(); 936 for (RcsAcsProvisioningStats stats : mRcsAcsProvisioningStatsList) { 937 // we store a copy into atoms storage 938 // so that we can continue using the original object. 939 RcsAcsProvisioningStats proto = copyRcsAcsProvisioningStats(stats); 940 // the current time is a placeholder and total registered time will be 941 // calculated when generating final atoms 942 proto.stateTimerMillis = now - proto.stateTimerMillis; 943 mAtomsStorage.addRcsAcsProvisioningStats(proto); 944 // update cached atom's time 945 stats.stateTimerMillis = now; 946 } 947 } 948 } 949 950 /** Create SipDelegateStat when SipDelegate is created */ createSipDelegateStats(int subId, Set<String> supportedTags)951 public synchronized void createSipDelegateStats(int subId, Set<String> supportedTags) { 952 if (supportedTags != null && !supportedTags.isEmpty()) { 953 LastSipDelegateStat lastState = getLastSipDelegateStat(subId, supportedTags); 954 lastState.createSipDelegateStat(subId); 955 } 956 } 957 958 /** Update destroyReason and duration of SipDelegateStat when SipDelegate is destroyed */ onSipDelegateStats(int subId, Set<String> supportedTags, int destroyReason)959 public synchronized void onSipDelegateStats(int subId, Set<String> supportedTags, 960 int destroyReason) { 961 if (supportedTags != null && !supportedTags.isEmpty()) { 962 LastSipDelegateStat lastState = getLastSipDelegateStat(subId, supportedTags); 963 lastState.setSipDelegateDestroyReason(destroyReason); 964 concludeSipDelegateStat(); 965 } 966 } 967 968 /** Create/Update atoms when states of sipTransportFeatureTags are changed */ onSipTransportFeatureTagStats( int subId, Set<FeatureTagState> deniedTags, Set<FeatureTagState> deRegiTags, Set<String> regiTags)969 public synchronized void onSipTransportFeatureTagStats( 970 int subId, 971 Set<FeatureTagState> deniedTags, 972 Set<FeatureTagState> deRegiTags, 973 Set<String> regiTags) { 974 long now = getWallTimeMillis(); 975 SipTransportFeatureTags sipTransportFeatureTags = getLastFeatureTags(subId); 976 if (regiTags != null && !regiTags.isEmpty()) { 977 for (String tag : regiTags) { 978 sipTransportFeatureTags.updateLastFeatureTagState(tag, STATE_REGISTERED, 979 NONE, now); 980 } 981 } 982 if (deniedTags != null && !deniedTags.isEmpty()) { 983 for (FeatureTagState tag : deniedTags) { 984 sipTransportFeatureTags.updateLastFeatureTagState(tag.getFeatureTag(), STATE_DENIED, 985 tag.getState(), now); 986 } 987 } 988 if (deRegiTags != null && !deRegiTags.isEmpty()) { 989 for (FeatureTagState tag : deRegiTags) { 990 sipTransportFeatureTags.updateLastFeatureTagState( 991 tag.getFeatureTag(), STATE_DEREGISTERED, tag.getState(), now); 992 } 993 } 994 } 995 996 /** Update duration of sipTransportFeatureTags when metrics are pulled */ concludeSipTransportFeatureTagsStat()997 public synchronized void concludeSipTransportFeatureTagsStat() { 998 if (mLastFeatureTagStatMap.isEmpty()) { 999 return; 1000 } 1001 1002 long now = getWallTimeMillis(); 1003 HashMap<Integer, SipTransportFeatureTags> lastFeatureTagStatsCopy = new HashMap<>(); 1004 lastFeatureTagStatsCopy.putAll(mLastFeatureTagStatMap); 1005 for (SipTransportFeatureTags sipTransportFeatureTags : lastFeatureTagStatsCopy.values()) { 1006 if (sipTransportFeatureTags != null) { 1007 sipTransportFeatureTags.conclude(now); 1008 } 1009 } 1010 } 1011 1012 /** Request Message */ onSipMessageRequest(String callId, String sipMessageMethod, int sipMessageDirection)1013 public synchronized void onSipMessageRequest(String callId, String sipMessageMethod, 1014 int sipMessageDirection) { 1015 mSipMessage = new SipMessageArray(sipMessageMethod, sipMessageDirection, callId); 1016 mSipMessageArray.add(mSipMessage); 1017 } 1018 1019 /** invalidated result when Request message is sent */ invalidatedMessageResult(int subId, String sipMessageMethod, int sipMessageDirection, int messageError)1020 public synchronized void invalidatedMessageResult(int subId, String sipMessageMethod, 1021 int sipMessageDirection, int messageError) { 1022 mSipMessage.addSipMessageStat(subId, sipMessageMethod, 0, 1023 sipMessageDirection, messageError); 1024 } 1025 1026 /** Create a new atom when RCS SIP Message Response changed. */ onSipMessageResponse(int subId, String callId, int sipMessageResponse, int messageError)1027 public synchronized void onSipMessageResponse(int subId, String callId, 1028 int sipMessageResponse, int messageError) { 1029 SipMessageArray match = mSipMessageArray.stream() 1030 .filter(d -> d.mCallId.equals(callId)).findFirst().orElse(null); 1031 if (match != null) { 1032 mSipMessage.addSipMessageStat(subId, match.mMethod, sipMessageResponse, 1033 match.mDirection, messageError); 1034 mSipMessageArray.removeIf(d -> d.mCallId.equals(callId)); 1035 } 1036 } 1037 1038 /** Request SIP Method Message */ earlySipTransportSession(String sessionMethod, String callId, int sipMessageDirection)1039 public synchronized void earlySipTransportSession(String sessionMethod, String callId, 1040 int sipMessageDirection) { 1041 mSipTransportSession = new SipTransportSessionArray(sessionMethod, 1042 sipMessageDirection, callId); 1043 mSipTransportSessionArray.add(mSipTransportSession); 1044 } 1045 1046 /** Response Message */ confirmedSipTransportSession(String callId, int sipResponse)1047 public synchronized void confirmedSipTransportSession(String callId, 1048 int sipResponse) { 1049 SipTransportSessionArray match = mSipTransportSessionArray.stream() 1050 .filter(d -> d.mCallId.equals(callId)).findFirst().orElse(null); 1051 if (match != null) { 1052 match.mSipResponse = sipResponse; 1053 } 1054 } 1055 1056 /** Create a new atom when RCS SIP Transport Session changed. */ onSipTransportSessionClosed(int subId, String callId, int sipResponse, boolean isEndedGracefully)1057 public synchronized void onSipTransportSessionClosed(int subId, String callId, 1058 int sipResponse, boolean isEndedGracefully) { 1059 SipTransportSessionArray match = mSipTransportSessionArray.stream() 1060 .filter(d -> d.mCallId.equals(callId)).findFirst().orElse(null); 1061 if (match != null) { 1062 if (sipResponse != 0) { 1063 match.mSipResponse = sipResponse; 1064 } 1065 mSipTransportSession.addSipTransportSessionStat(subId, match.mMethod, match.mDirection, 1066 sipResponse, isEndedGracefully); 1067 mSipTransportSessionArray.removeIf(d -> d.mCallId.equals(callId)); 1068 } 1069 } 1070 1071 /** Add a listener to the hashmap for waiting upcoming DedicatedBearer established event */ onImsDedicatedBearerListenerAdded(@onNull final int listenerId, @NonNull final int slotId, @NonNull final int ratAtEnd, @NonNull final int qci)1072 public synchronized void onImsDedicatedBearerListenerAdded(@NonNull final int listenerId, 1073 @NonNull final int slotId, @NonNull final int ratAtEnd, @NonNull final int qci) { 1074 int subId = getSubId(slotId); 1075 int carrierId = getCarrierId(subId); 1076 1077 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID 1078 || !isValidCarrierId(carrierId)) { 1079 return; 1080 } 1081 1082 if (mDedicatedBearerListenerEventMap.containsKey(listenerId)) { 1083 return; 1084 } 1085 1086 ImsDedicatedBearerListenerEvent preProto = new ImsDedicatedBearerListenerEvent(); 1087 preProto.carrierId = carrierId; 1088 preProto.slotId = slotId; 1089 preProto.ratAtEnd = ratAtEnd; 1090 preProto.qci = qci; 1091 preProto.dedicatedBearerEstablished = false; 1092 preProto.eventCount = 1; 1093 1094 mDedicatedBearerListenerEventMap.put(listenerId, preProto); 1095 } 1096 1097 /** update previously added atom with dedicatedBearerEstablished = true when 1098 * DedicatedBearerListener Event changed. */ onImsDedicatedBearerListenerUpdateSession(final int listenerId, final int slotId, final int rat, final int qci, @NonNull final boolean dedicatedBearerEstablished)1099 public synchronized void onImsDedicatedBearerListenerUpdateSession(final int listenerId, 1100 final int slotId, final int rat, final int qci, 1101 @NonNull final boolean dedicatedBearerEstablished) { 1102 int subId = getSubId(slotId); 1103 int carrierId = getCarrierId(subId); 1104 1105 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID 1106 || !isValidCarrierId(carrierId)) { 1107 return; 1108 } 1109 1110 if (mDedicatedBearerListenerEventMap.containsKey(listenerId)) { 1111 ImsDedicatedBearerListenerEvent preProto = 1112 mDedicatedBearerListenerEventMap.get(listenerId); 1113 1114 preProto.ratAtEnd = rat; 1115 preProto.qci = qci; 1116 preProto.dedicatedBearerEstablished = dedicatedBearerEstablished; 1117 1118 mDedicatedBearerListenerEventMap.replace(listenerId, preProto); 1119 } else { 1120 ImsDedicatedBearerListenerEvent preProto = new ImsDedicatedBearerListenerEvent(); 1121 preProto.carrierId = carrierId; 1122 preProto.slotId = slotId; 1123 preProto.ratAtEnd = rat; 1124 preProto.qci = qci; 1125 preProto.dedicatedBearerEstablished = dedicatedBearerEstablished; 1126 preProto.eventCount = 1; 1127 1128 mDedicatedBearerListenerEventMap.put(listenerId, preProto); 1129 } 1130 } 1131 1132 /** add proto to atom when listener is removed, so that I can save the status of dedicatedbearer 1133 * establishment per listener id */ onImsDedicatedBearerListenerRemoved(@onNull final int listenerId)1134 public synchronized void onImsDedicatedBearerListenerRemoved(@NonNull final int listenerId) { 1135 if (mDedicatedBearerListenerEventMap.containsKey(listenerId)) { 1136 1137 ImsDedicatedBearerListenerEvent newProto = 1138 mDedicatedBearerListenerEventMap.get(listenerId); 1139 1140 mAtomsStorage.addImsDedicatedBearerListenerEvent(newProto); 1141 mDedicatedBearerListenerEventMap.remove(listenerId); 1142 } 1143 } 1144 1145 /** Create a new atom when DedicatedBearer Event changed. */ onImsDedicatedBearerEvent(int slotId, int ratAtEnd, int qci, int bearerState, boolean localConnectionInfoReceived, boolean remoteConnectionInfoReceived, boolean hasListeners)1146 public synchronized void onImsDedicatedBearerEvent(int slotId, int ratAtEnd, int qci, 1147 int bearerState, boolean localConnectionInfoReceived, 1148 boolean remoteConnectionInfoReceived, boolean hasListeners) { 1149 int subId = getSubId(slotId); 1150 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 1151 return; 1152 } 1153 1154 ImsDedicatedBearerEvent proto = new ImsDedicatedBearerEvent(); 1155 proto.carrierId = getCarrierId(subId); 1156 proto.slotId = getSlotId(subId); 1157 proto.ratAtEnd = ratAtEnd; 1158 proto.qci = qci; 1159 proto.bearerState = bearerState; 1160 proto.localConnectionInfoReceived = localConnectionInfoReceived; 1161 proto.remoteConnectionInfoReceived = remoteConnectionInfoReceived; 1162 proto.hasListeners = hasListeners; 1163 proto.count = 1; 1164 mAtomsStorage.addImsDedicatedBearerEvent(proto); 1165 } 1166 1167 /** 1168 * Update or Create a new atom when Ims Registration Service Desc state changed. 1169 * Use-related parts are already converted from UseStatsWriter based on RcsContactPresenceTuple. 1170 */ onImsRegistrationServiceDescStats(int subId, List<String> serviceIdList, List<String> serviceIdVersionList, int registrationTech)1171 public void onImsRegistrationServiceDescStats(int subId, List<String> serviceIdList, 1172 List<String> serviceIdVersionList, int registrationTech) { 1173 synchronized (mImsRegistrationServiceDescStatsList) { 1174 int carrierId = getCarrierId(subId); 1175 if (!isValidCarrierId(carrierId)) { 1176 handleImsRegistrationServiceDescStats(); 1177 return; 1178 } 1179 // update cached atom if exists 1180 onStoreCompleteImsRegistrationServiceDescStats(subId); 1181 1182 if (serviceIdList == null) { 1183 Rlog.d(TAG, "serviceIds is null or empty"); 1184 return; 1185 } 1186 1187 int index = 0; 1188 for (String serviceId : serviceIdList) { 1189 ImsRegistrationServiceDescStats mImsRegistrationServiceDescStats = 1190 new ImsRegistrationServiceDescStats(); 1191 1192 mImsRegistrationServiceDescStats.carrierId = carrierId; 1193 mImsRegistrationServiceDescStats.slotId = getSlotId(subId); 1194 mImsRegistrationServiceDescStats.serviceIdName = convertServiceIdToValue(serviceId); 1195 mImsRegistrationServiceDescStats.serviceIdVersion = 1196 Float.parseFloat(serviceIdVersionList.get(index++)); 1197 mImsRegistrationServiceDescStats.registrationTech = registrationTech; 1198 mImsRegistrationServiceDescStatsList.add(mImsRegistrationServiceDescStats); 1199 } 1200 } 1201 } 1202 1203 /** Update duration and cached of ImsRegistrationServiceDescStats when metrics are pulled */ onFlushIncompleteImsRegistrationServiceDescStats()1204 public void onFlushIncompleteImsRegistrationServiceDescStats() { 1205 synchronized (mImsRegistrationServiceDescStatsList) { 1206 for (ImsRegistrationServiceDescStats proto : mImsRegistrationServiceDescStatsList) { 1207 ImsRegistrationServiceDescStats newProto = 1208 copyImsRegistrationServiceDescStats(proto); 1209 long now = getWallTimeMillis(); 1210 // the current time is a placeholder and total registered time will be 1211 // calculated when generating final atoms 1212 newProto.publishedMillis = now - proto.publishedMillis; 1213 mAtomsStorage.addImsRegistrationServiceDescStats(newProto); 1214 proto.publishedMillis = now; 1215 } 1216 } 1217 } 1218 1219 /** Create a new atom when Uce Event Stats changed. */ onUceEventStats(int subId, int type, boolean successful, int commandCode, int networkResponse)1220 public synchronized void onUceEventStats(int subId, int type, boolean successful, 1221 int commandCode, int networkResponse) { 1222 UceEventStats proto = new UceEventStats(); 1223 1224 int carrierId = getCarrierId(subId); 1225 if (!isValidCarrierId(carrierId)) { 1226 handleImsRegistrationServiceDescStats(); 1227 return; 1228 } 1229 proto.carrierId = carrierId; 1230 proto.slotId = getSlotId(subId); 1231 proto.type = type; 1232 proto.successful = successful; 1233 proto.commandCode = commandCode; 1234 proto.networkResponse = networkResponse; 1235 proto.count = 1; 1236 mAtomsStorage.addUceEventStats(proto); 1237 1238 /** 1239 * The publishedMillis of ImsRegistrationServiceDescStat is the time gap between 1240 * Publish success and Un publish. 1241 * So, when the publish operation is successful, the corresponding time gap is set, 1242 * and in case of failure, the cached stat is deleted. 1243 */ 1244 if (type == UCE_EVENT_STATS__TYPE__PUBLISH) { 1245 if (successful) { 1246 setImsRegistrationServiceDescStatsTime(proto.carrierId); 1247 } else { 1248 deleteImsRegistrationServiceDescStats(proto.carrierId); 1249 } 1250 } 1251 } 1252 1253 /** Create a new atom when Presence Notify Event changed. */ onPresenceNotifyEvent(int subId, String reason, boolean contentBodyReceived, boolean rcsCaps, boolean mmtelCaps, boolean noCaps)1254 public synchronized void onPresenceNotifyEvent(int subId, String reason, 1255 boolean contentBodyReceived, boolean rcsCaps, boolean mmtelCaps, boolean noCaps) { 1256 PresenceNotifyEvent proto = new PresenceNotifyEvent(); 1257 1258 int carrierId = getCarrierId(subId); 1259 if (!isValidCarrierId(carrierId)) { 1260 handleImsRegistrationServiceDescStats(); 1261 return; 1262 } 1263 1264 proto.carrierId = carrierId; 1265 proto.slotId = getSlotId(subId); 1266 proto.reason = convertPresenceNotifyReason(reason); 1267 proto.contentBodyReceived = contentBodyReceived; 1268 proto.rcsCapsCount = rcsCaps ? 1 : 0; 1269 proto.mmtelCapsCount = mmtelCaps ? 1 : 0; 1270 proto.noCapsCount = noCaps ? 1 : 0; 1271 proto.count = 1; 1272 mAtomsStorage.addPresenceNotifyEvent(proto); 1273 } 1274 1275 /** Update duration a created Ims Registration Desc Stat atom when Un publish event happened. */ onStoreCompleteImsRegistrationServiceDescStats(int subId)1276 public void onStoreCompleteImsRegistrationServiceDescStats(int subId) { 1277 synchronized (mImsRegistrationServiceDescStatsList) { 1278 int carrierId = getCarrierId(subId); 1279 List<ImsRegistrationServiceDescStats> deleteList = new ArrayList<>(); 1280 for (ImsRegistrationServiceDescStats proto : mImsRegistrationServiceDescStatsList) { 1281 if (proto.carrierId == carrierId) { 1282 proto.publishedMillis = getWallTimeMillis() - proto.publishedMillis; 1283 mAtomsStorage.addImsRegistrationServiceDescStats(proto); 1284 deleteList.add(proto); 1285 } 1286 } 1287 for (ImsRegistrationServiceDescStats proto : deleteList) { 1288 mImsRegistrationServiceDescStatsList.remove(proto); 1289 } 1290 } 1291 } 1292 1293 /** Create a new atom when GBA Success Event changed. */ onGbaSuccessEvent(int subId)1294 public synchronized void onGbaSuccessEvent(int subId) { 1295 int carrierId = getCarrierId(subId); 1296 if (!isValidCarrierId(carrierId)) { 1297 return; 1298 } 1299 1300 GbaEvent proto = new GbaEvent(); 1301 proto.carrierId = carrierId; 1302 proto.slotId = getSlotId(subId); 1303 proto.successful = true; 1304 proto.failedReason = -1; 1305 proto.count = 1; 1306 mAtomsStorage.addGbaEvent(proto); 1307 } 1308 1309 /** Create a new atom when GBA Failure Event changed. */ onGbaFailureEvent(int subId, int reason)1310 public synchronized void onGbaFailureEvent(int subId, int reason) { 1311 int carrierId = getCarrierId(subId); 1312 if (!isValidCarrierId(carrierId)) { 1313 return; 1314 } 1315 1316 GbaEvent proto = new GbaEvent(); 1317 proto.carrierId = carrierId; 1318 proto.slotId = getSlotId(subId); 1319 proto.successful = false; 1320 proto.failedReason = reason; 1321 proto.count = 1; 1322 mAtomsStorage.addGbaEvent(proto); 1323 } 1324 1325 /** Create or return exist RcsProvisioningCallback based on subId. */ getRcsProvisioningCallback(int subId, boolean enableSingleRegistration)1326 public synchronized RcsProvisioningCallback getRcsProvisioningCallback(int subId, 1327 boolean enableSingleRegistration) { 1328 // find exist obj in Map 1329 RcsProvisioningCallback rcsProvisioningCallback = mRcsProvisioningCallbackMap.get(subId); 1330 if (rcsProvisioningCallback != null) { 1331 return rcsProvisioningCallback; 1332 } 1333 1334 // create new, add Map and return 1335 rcsProvisioningCallback = new RcsProvisioningCallback(this, subId, 1336 enableSingleRegistration); 1337 mRcsProvisioningCallbackMap.put(subId, rcsProvisioningCallback); 1338 return rcsProvisioningCallback; 1339 } 1340 1341 /** Set whether single registration is supported. */ setEnableSingleRegistration(int subId, boolean enableSingleRegistration)1342 public synchronized void setEnableSingleRegistration(int subId, 1343 boolean enableSingleRegistration) { 1344 // find exist obj and set 1345 RcsProvisioningCallback callbackBinder = mRcsProvisioningCallbackMap.get(subId); 1346 if (callbackBinder != null) { 1347 callbackBinder.setEnableSingleRegistration(enableSingleRegistration); 1348 } 1349 } 1350 removeRcsProvisioningCallback(int subId)1351 private synchronized void removeRcsProvisioningCallback(int subId) { 1352 // remove obj from Map based on subId 1353 mRcsProvisioningCallbackMap.remove(subId); 1354 } 1355 copyImsRegistrationFeatureTagStats( ImsRegistrationFeatureTagStats proto)1356 private ImsRegistrationFeatureTagStats copyImsRegistrationFeatureTagStats( 1357 ImsRegistrationFeatureTagStats proto) { 1358 ImsRegistrationFeatureTagStats newProto = new ImsRegistrationFeatureTagStats(); 1359 newProto.carrierId = proto.carrierId; 1360 newProto.slotId = proto.slotId; 1361 newProto.featureTagName = proto.featureTagName; 1362 newProto.registrationTech = proto.registrationTech; 1363 newProto.registeredMillis = proto.registeredMillis; 1364 1365 return newProto; 1366 } 1367 copyRcsAcsProvisioningStats(RcsAcsProvisioningStats proto)1368 private RcsAcsProvisioningStats copyRcsAcsProvisioningStats(RcsAcsProvisioningStats proto) { 1369 RcsAcsProvisioningStats newProto = new RcsAcsProvisioningStats(); 1370 newProto.carrierId = proto.carrierId; 1371 newProto.slotId = proto.slotId; 1372 newProto.responseCode = proto.responseCode; 1373 newProto.responseType = proto.responseType; 1374 newProto.isSingleRegistrationEnabled = proto.isSingleRegistrationEnabled; 1375 newProto.count = proto.count; 1376 newProto.stateTimerMillis = proto.stateTimerMillis; 1377 1378 return newProto; 1379 } 1380 copyImsRegistrationServiceDescStats( ImsRegistrationServiceDescStats proto)1381 private ImsRegistrationServiceDescStats copyImsRegistrationServiceDescStats( 1382 ImsRegistrationServiceDescStats proto) { 1383 ImsRegistrationServiceDescStats newProto = new ImsRegistrationServiceDescStats(); 1384 newProto.carrierId = proto.carrierId; 1385 newProto.slotId = proto.slotId; 1386 newProto.serviceIdName = proto.serviceIdName; 1387 newProto.serviceIdVersion = proto.serviceIdVersion; 1388 newProto.registrationTech = proto.registrationTech; 1389 return newProto; 1390 } 1391 setImsRegistrationServiceDescStatsTime(int carrierId)1392 private void setImsRegistrationServiceDescStatsTime(int carrierId) { 1393 synchronized (mImsRegistrationServiceDescStatsList) { 1394 for (ImsRegistrationServiceDescStats descStats : mImsRegistrationServiceDescStatsList) { 1395 if (descStats.carrierId == carrierId) { 1396 descStats.publishedMillis = getWallTimeMillis(); 1397 } 1398 } 1399 } 1400 } 1401 deleteImsRegistrationServiceDescStats(int carrierId)1402 private void deleteImsRegistrationServiceDescStats(int carrierId) { 1403 synchronized (mImsRegistrationServiceDescStatsList) { 1404 List<ImsRegistrationServiceDescStats> deleteList = new ArrayList<>(); 1405 for (ImsRegistrationServiceDescStats proto : mImsRegistrationServiceDescStatsList) { 1406 if (proto.carrierId == carrierId) { 1407 deleteList.add(proto); 1408 } 1409 } 1410 for (ImsRegistrationServiceDescStats stats : deleteList) { 1411 mImsRegistrationServiceDescStatsList.remove(stats); 1412 } 1413 } 1414 } 1415 handleImsRegistrationServiceDescStats()1416 private void handleImsRegistrationServiceDescStats() { 1417 synchronized (mImsRegistrationServiceDescStatsList) { 1418 List<ImsRegistrationServiceDescStats> deleteList = new ArrayList<>(); 1419 for (ImsRegistrationServiceDescStats proto : mImsRegistrationServiceDescStatsList) { 1420 int subId = getSubId(proto.slotId); 1421 int newCarrierId = getCarrierId(subId); 1422 if (proto.carrierId != newCarrierId) { 1423 deleteList.add(proto); 1424 if (proto.publishedMillis != 0) { 1425 proto.publishedMillis = getWallTimeMillis() - proto.publishedMillis; 1426 mAtomsStorage.addImsRegistrationServiceDescStats(proto); 1427 } 1428 } 1429 } 1430 for (ImsRegistrationServiceDescStats stats : deleteList) { 1431 mImsRegistrationServiceDescStatsList.remove(stats); 1432 } 1433 } 1434 } 1435 getRcsAcsProvisioningStats(int subId)1436 private RcsAcsProvisioningStats getRcsAcsProvisioningStats(int subId) { 1437 int carrierId = getCarrierId(subId); 1438 int slotId = getSlotId(subId); 1439 1440 for (RcsAcsProvisioningStats stats : mRcsAcsProvisioningStatsList) { 1441 if (stats == null) { 1442 continue; 1443 } 1444 if (stats.carrierId == carrierId && stats.slotId == slotId) { 1445 return stats; 1446 } 1447 } 1448 return null; 1449 } 1450 flushRcsAcsProvisioningStatsInvalid()1451 private void flushRcsAcsProvisioningStatsInvalid() { 1452 List<RcsAcsProvisioningStats> inValidList = new ArrayList<RcsAcsProvisioningStats>(); 1453 1454 int subId; 1455 int newCarrierId; 1456 1457 for (RcsAcsProvisioningStats stats : mRcsAcsProvisioningStatsList) { 1458 subId = getSubId(stats.slotId); 1459 newCarrierId = getCarrierId(subId); 1460 if (stats.carrierId != newCarrierId) { 1461 inValidList.add(stats); 1462 } 1463 } 1464 1465 for (RcsAcsProvisioningStats inValid : inValidList) { 1466 inValid.stateTimerMillis = getWallTimeMillis() - inValid.stateTimerMillis; 1467 mAtomsStorage.addRcsAcsProvisioningStats(inValid); 1468 mRcsAcsProvisioningStatsList.remove(inValid); 1469 } 1470 inValidList.clear(); 1471 } 1472 flushImsRegistrationFeatureTagStatsInvalid()1473 private void flushImsRegistrationFeatureTagStatsInvalid() { 1474 List<ImsRegistrationFeatureTagStats> inValidList = 1475 new ArrayList<ImsRegistrationFeatureTagStats>(); 1476 1477 int subId; 1478 int newCarrierId; 1479 1480 for (ImsRegistrationFeatureTagStats stats : mImsRegistrationFeatureTagStatsList) { 1481 subId = getSubId(stats.slotId); 1482 newCarrierId = getCarrierId(subId); 1483 if (stats.carrierId != newCarrierId) { 1484 inValidList.add(stats); 1485 } 1486 } 1487 1488 for (ImsRegistrationFeatureTagStats inValid : inValidList) { 1489 inValid.registeredMillis = getWallTimeMillis() - inValid.registeredMillis; 1490 mAtomsStorage.addImsRegistrationFeatureTagStats(inValid); 1491 mImsRegistrationFeatureTagStatsList.remove(inValid); 1492 } 1493 inValidList.clear(); 1494 } 1495 getLastSipDelegateStat(int subId, Set<String> supportedTags)1496 private LastSipDelegateStat getLastSipDelegateStat(int subId, Set<String> supportedTags) { 1497 LastSipDelegateStat stat = null; 1498 for (LastSipDelegateStat lastStat : mLastSipDelegateStatList) { 1499 if (lastStat.compare(subId, supportedTags)) { 1500 stat = lastStat; 1501 break; 1502 } 1503 } 1504 1505 if (stat == null) { 1506 stat = new LastSipDelegateStat(subId, supportedTags); 1507 mLastSipDelegateStatList.add(stat); 1508 } 1509 1510 return stat; 1511 } 1512 concludeSipDelegateStat()1513 private void concludeSipDelegateStat() { 1514 if (mLastSipDelegateStatList.isEmpty()) { 1515 return; 1516 } 1517 long now = getWallTimeMillis(); 1518 List<LastSipDelegateStat> sipDelegateStatsCopy = new ArrayList<>(mLastSipDelegateStatList); 1519 for (LastSipDelegateStat stat : sipDelegateStatsCopy) { 1520 if (stat.isDestroyed()) { 1521 stat.conclude(now); 1522 mLastSipDelegateStatList.remove(stat); 1523 } 1524 } 1525 } 1526 getLastFeatureTags(int subId)1527 private SipTransportFeatureTags getLastFeatureTags(int subId) { 1528 SipTransportFeatureTags sipTransportFeatureTags; 1529 if (mLastFeatureTagStatMap.containsKey(subId)) { 1530 sipTransportFeatureTags = mLastFeatureTagStatMap.get(subId); 1531 } else { 1532 sipTransportFeatureTags = new SipTransportFeatureTags(subId); 1533 mLastFeatureTagStatMap.put(subId, sipTransportFeatureTags); 1534 } 1535 return sipTransportFeatureTags; 1536 } 1537 @VisibleForTesting isValidCarrierId(int carrierId)1538 protected boolean isValidCarrierId(int carrierId) { 1539 return carrierId > TelephonyManager.UNKNOWN_CARRIER_ID; 1540 } 1541 1542 @VisibleForTesting getSlotId(int subId)1543 protected int getSlotId(int subId) { 1544 return SubscriptionManager.getPhoneId(subId); 1545 } 1546 1547 @VisibleForTesting getCarrierId(int subId)1548 protected int getCarrierId(int subId) { 1549 int phoneId = SubscriptionManager.getPhoneId(subId); 1550 Phone phone = PhoneFactory.getPhone(phoneId); 1551 return phone != null ? phone.getCarrierId() : TelephonyManager.UNKNOWN_CARRIER_ID; 1552 } 1553 1554 @VisibleForTesting getWallTimeMillis()1555 protected long getWallTimeMillis() { 1556 //time in UTC, preserved across reboots, but can be adjusted e.g. by the user or NTP 1557 return System.currentTimeMillis(); 1558 } 1559 1560 @VisibleForTesting logd(String msg)1561 protected void logd(String msg) { 1562 Rlog.d(TAG, msg); 1563 } 1564 1565 @VisibleForTesting getSubId(int slotId)1566 protected int getSubId(int slotId) { 1567 final int[] subIds = SubscriptionManager.getSubId(slotId); 1568 int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; 1569 if (subIds != null && subIds.length >= 1) { 1570 subId = subIds[0]; 1571 } 1572 return subId; 1573 } 1574 1575 /** Get a enum value from pre-defined feature tag name list */ 1576 @VisibleForTesting convertTagNameToValue(@onNull String tagName)1577 public int convertTagNameToValue(@NonNull String tagName) { 1578 return FEATURE_TAGS.getOrDefault(tagName.trim().toLowerCase(), 1579 TelephonyProtoEnums.IMS_FEATURE_TAG_CUSTOM); 1580 } 1581 1582 /** Get a enum value from pre-defined service id list */ 1583 @VisibleForTesting convertServiceIdToValue(@onNull String serviceId)1584 public int convertServiceIdToValue(@NonNull String serviceId) { 1585 return SERVICE_IDS.getOrDefault(serviceId.trim().toLowerCase(), 1586 IMS_REGISTRATION_SERVICE_DESC_STATS__SERVICE_ID_NAME__SERVICE_ID_CUSTOM); 1587 } 1588 1589 /** Get a enum value from pre-defined message type list */ 1590 @VisibleForTesting convertMessageTypeToValue(@onNull String messageType)1591 public int convertMessageTypeToValue(@NonNull String messageType) { 1592 return MESSAGE_TYPE.getOrDefault(messageType.trim().toLowerCase(), 1593 TelephonyProtoEnums.SIP_REQUEST_CUSTOM); 1594 } 1595 1596 /** Get a enum value from pre-defined reason list */ 1597 @VisibleForTesting convertPresenceNotifyReason(@onNull String reason)1598 public int convertPresenceNotifyReason(@NonNull String reason) { 1599 return NOTIFY_REASONS.getOrDefault(reason.trim().toLowerCase(), 1600 PRESENCE_NOTIFY_EVENT__REASON__REASON_CUSTOM); 1601 } 1602 1603 /** 1604 * Print all metrics data for debugging purposes 1605 * 1606 * @param rawWriter Print writer 1607 */ printAllMetrics(PrintWriter rawWriter)1608 public synchronized void printAllMetrics(PrintWriter rawWriter) { 1609 if (mAtomsStorage == null || mAtomsStorage.mAtoms == null) { 1610 return; 1611 } 1612 1613 final IndentingPrintWriter pw = new IndentingPrintWriter(rawWriter, " "); 1614 PersistAtomsProto.PersistAtoms metricAtoms = mAtomsStorage.mAtoms; 1615 1616 pw.println("RcsStats Metrics Proto: "); 1617 pw.println("------------------------------------------"); 1618 pw.println("ImsRegistrationFeatureTagStats:"); 1619 pw.increaseIndent(); 1620 for (ImsRegistrationFeatureTagStats stat : metricAtoms.imsRegistrationFeatureTagStats) { 1621 pw.println("[" + stat.carrierId + "]" 1622 + " [" + stat.slotId + "]" 1623 + " Feature Tag Name = " + stat.featureTagName 1624 + ", Registration Tech = " + stat.registrationTech 1625 + ", Registered Duration (ms) = " + stat.registeredMillis); 1626 } 1627 pw.decreaseIndent(); 1628 1629 pw.println("RcsClientProvisioningStats:"); 1630 pw.increaseIndent(); 1631 for (RcsClientProvisioningStats stat : metricAtoms.rcsClientProvisioningStats) { 1632 pw.println("[" + stat.carrierId + "]" 1633 + " [" + stat.slotId + "]" 1634 + " Event = " + stat.event 1635 + ", Count = " + stat.count); 1636 } 1637 pw.decreaseIndent(); 1638 1639 pw.println("RcsAcsProvisioningStats:"); 1640 pw.increaseIndent(); 1641 for (RcsAcsProvisioningStats stat : metricAtoms.rcsAcsProvisioningStats) { 1642 pw.println("[" + stat.carrierId + "]" 1643 + " [" + stat.slotId + "]" 1644 + " Response Code = " + stat.responseCode 1645 + ", Response Type = " + stat.responseType 1646 + ", Single Registration Enabled = " + stat.isSingleRegistrationEnabled 1647 + ", Count = " + stat.count 1648 + ", State Timer (ms) = " + stat.stateTimerMillis); 1649 } 1650 pw.decreaseIndent(); 1651 1652 pw.println("SipDelegateStats:"); 1653 pw.increaseIndent(); 1654 for (SipDelegateStats stat : metricAtoms.sipDelegateStats) { 1655 pw.println("[" + stat.carrierId + "]" 1656 + " [" + stat.slotId + "]" 1657 + " [" + stat.dimension + "]" 1658 + " Destroy Reason = " + stat.destroyReason 1659 + ", Uptime (ms) = " + stat.uptimeMillis); 1660 } 1661 pw.decreaseIndent(); 1662 1663 pw.println("SipTransportFeatureTagStats:"); 1664 pw.increaseIndent(); 1665 for (SipTransportFeatureTagStats stat : metricAtoms.sipTransportFeatureTagStats) { 1666 pw.println("[" + stat.carrierId + "]" 1667 + " [" + stat.slotId + "]" 1668 + " Feature Tag Name = " + stat.featureTagName 1669 + ", Denied Reason = " + stat.sipTransportDeniedReason 1670 + ", Deregistered Reason = " + stat.sipTransportDeregisteredReason 1671 + ", Associated Time (ms) = " + stat.associatedMillis); 1672 } 1673 pw.decreaseIndent(); 1674 1675 pw.println("SipMessageResponse:"); 1676 pw.increaseIndent(); 1677 for (SipMessageResponse stat : metricAtoms.sipMessageResponse) { 1678 pw.println("[" + stat.carrierId + "]" 1679 + " [" + stat.slotId + "]" 1680 + " Message Method = " + stat.sipMessageMethod 1681 + ", Response = " + stat.sipMessageResponse 1682 + ", Direction = " + stat.sipMessageDirection 1683 + ", Error = " + stat.messageError 1684 + ", Count = " + stat.count); 1685 } 1686 pw.decreaseIndent(); 1687 1688 pw.println("SipTransportSession:"); 1689 pw.increaseIndent(); 1690 for (SipTransportSession stat : metricAtoms.sipTransportSession) { 1691 pw.println("[" + stat.carrierId + "]" 1692 + " [" + stat.slotId + "]" 1693 + " Session Method = " + stat.sessionMethod 1694 + ", Direction = " + stat.sipMessageDirection 1695 + ", Response = " + stat.sipResponse 1696 + ", Count = " + stat.sessionCount 1697 + ", GraceFully Count = " + stat.endedGracefullyCount); 1698 } 1699 pw.decreaseIndent(); 1700 1701 pw.println("ImsDedicatedBearerListenerEvent:"); 1702 pw.increaseIndent(); 1703 for (ImsDedicatedBearerListenerEvent stat : metricAtoms.imsDedicatedBearerListenerEvent) { 1704 pw.println("[" + stat.carrierId + "]" 1705 + " [" + stat.slotId + "]" 1706 + " RAT = " + stat.ratAtEnd 1707 + ", QCI = " + stat.qci 1708 + ", Dedicated Bearer Established = " + stat.dedicatedBearerEstablished 1709 + ", Count = " + stat.eventCount); 1710 } 1711 pw.decreaseIndent(); 1712 1713 pw.println("ImsDedicatedBearerEvent:"); 1714 pw.increaseIndent(); 1715 for (ImsDedicatedBearerEvent stat : metricAtoms.imsDedicatedBearerEvent) { 1716 pw.println("[" + stat.carrierId + "]" 1717 + " [" + stat.slotId + "]" 1718 + " RAT = " + stat.ratAtEnd 1719 + ", QCI = " + stat.qci 1720 + ", Bearer State = " + stat.bearerState 1721 + ", Local Connection Info = " + stat.localConnectionInfoReceived 1722 + ", Remote Connection Info = " + stat.remoteConnectionInfoReceived 1723 + ", Listener Existence = " + stat.hasListeners 1724 + ", Count = " + stat.count); 1725 } 1726 pw.decreaseIndent(); 1727 1728 pw.println("ImsRegistrationServiceDescStats:"); 1729 pw.increaseIndent(); 1730 for (ImsRegistrationServiceDescStats stat : metricAtoms.imsRegistrationServiceDescStats) { 1731 pw.println("[" + stat.carrierId + "]" 1732 + " [" + stat.slotId + "]" 1733 + " Name = " + stat.serviceIdName 1734 + ", Version = " + stat.serviceIdVersion 1735 + ", Registration Tech = " + stat.registrationTech 1736 + ", Published Time (ms) = " + stat.publishedMillis); 1737 } 1738 pw.decreaseIndent(); 1739 1740 pw.println("UceEventStats:"); 1741 pw.increaseIndent(); 1742 for (UceEventStats stat : metricAtoms.uceEventStats) { 1743 pw.println("[" + stat.carrierId + "]" 1744 + " [" + stat.slotId + "]" 1745 + " Type = " + stat.type 1746 + ", Successful = " + stat.successful 1747 + ", Code = " + stat.commandCode 1748 + ", Response = " + stat.networkResponse 1749 + ", Count = " + stat.count); 1750 } 1751 pw.decreaseIndent(); 1752 1753 pw.println("PresenceNotifyEvent:"); 1754 pw.increaseIndent(); 1755 for (PresenceNotifyEvent stat : metricAtoms.presenceNotifyEvent) { 1756 pw.println("[" + stat.carrierId + "]" 1757 + " [" + stat.slotId + "]" 1758 + " Reason = " + stat.reason 1759 + ", Body = " + stat.contentBodyReceived 1760 + ", RCS Count = " + stat.rcsCapsCount 1761 + ", MMTEL Count = " + stat.mmtelCapsCount 1762 + ", NoCaps Count = " + stat.noCapsCount 1763 + ", Count = " + stat.count); 1764 } 1765 pw.decreaseIndent(); 1766 1767 pw.println("GbaEvent:"); 1768 pw.increaseIndent(); 1769 for (GbaEvent stat : metricAtoms.gbaEvent) { 1770 pw.println("[" + stat.carrierId + "]" 1771 + " [" + stat.slotId + "]" 1772 + " Successful = " + stat.successful 1773 + ", Fail Reason = " + stat.failedReason 1774 + ", Count = " + stat.count); 1775 } 1776 pw.decreaseIndent(); 1777 } 1778 } 1779