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