Loading src/java/com/android/internal/telephony/metrics/ImsStats.java +134 −2 Original line number Original line Diff line number Diff line Loading @@ -27,6 +27,7 @@ import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TE import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_LTE; import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_LTE; import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_NONE; import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_NONE; import static android.text.format.DateUtils.SECOND_IN_MILLIS; import static android.text.format.DateUtils.SECOND_IN_MILLIS; import static android.util.Patterns.EMAIL_ADDRESS; import android.annotation.Nullable; import android.annotation.Nullable; import android.os.SystemClock; import android.os.SystemClock; Loading @@ -51,6 +52,8 @@ import com.android.internal.telephony.nano.PersistAtomsProto.ImsRegistrationStat import com.android.internal.telephony.nano.PersistAtomsProto.ImsRegistrationTermination; import com.android.internal.telephony.nano.PersistAtomsProto.ImsRegistrationTermination; import com.android.telephony.Rlog; import com.android.telephony.Rlog; import java.util.regex.Pattern; /** Tracks IMS registration metrics for each phone. */ /** Tracks IMS registration metrics for each phone. */ public class ImsStats { public class ImsStats { private static final String TAG = ImsStats.class.getSimpleName(); private static final String TAG = ImsStats.class.getSimpleName(); Loading @@ -70,6 +73,123 @@ public class ImsStats { */ */ private static final int MAX_EXTRA_MESSAGE_LENGTH = 128; private static final int MAX_EXTRA_MESSAGE_LENGTH = 128; /** Pattern used to match UUIDs in IMS extra messages for filtering. */ private static final Pattern PATTERN_UUID = Pattern.compile( "[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}"); /** Replacement for UUIDs. */ private static final String REPLACEMENT_UUID = "<UUID_REDACTED>"; /** * Pattern used to match URI (e.g. sip, tel) in IMS extra messages for filtering. * * <p>NOTE: this simple pattern aims to catch the most common URI schemes. It is not meant to be * RFC-complaint. */ private static final Pattern PATTERN_URI = Pattern.compile("([a-zA-Z]{2,}:)" + EMAIL_ADDRESS.pattern()); /** Replacement for URI. */ private static final String REPLACEMENT_URI = "$1<REDACTED>"; /** * Pattern used to match IPv4 addresses in IMS extra messages for filtering. * * <p>This is a copy of {@code android.util.Patterns.IP_ADDRESS}, which is deprecated and might * be removed in the future. */ private static final Pattern PATTERN_IPV4 = Pattern.compile( "((25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.(25[0-5]|2[0-4]" + "[0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1]" + "[0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}" + "|[1-9][0-9]|[0-9]))"); /** Replacement for IPv4 addresses. */ private static final String REPLACEMENT_IPV4 = "<IPV4_REDACTED>"; /** * Pattern used to match IPv6 addresses in IMS extra messages for filtering. * * <p>NOTE: this pattern aims to catch the most common IPv6 addresses. It is not meant to be * RFC-complaint or free of false positives. */ private static final Pattern PATTERN_IPV6 = Pattern.compile( // Full address "([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}" // Abbreviated address, e.g. 2001:4860:4860::8888 + "|([0-9a-fA-F]{1,4}:){1,6}(:[0-9a-fA-F]{1,4}){1,6}" // Abbreviated network address, e.g. 2607:F8B0:: + "|([0-9a-fA-F]{1,4}:){1,7}:" // Abbreviated address, e.g. ::1 + "|:(:[0-9a-fA-F]{1,4}){1,7}"); /** Replacement for IPv6 addresses. */ private static final String REPLACEMENT_IPV6 = "<IPV6_REDACTED>"; /** * Pattern used to match potential IMEI values in IMS extra messages for filtering. * * <p>This includes segmented IMEI or IMEI/SV, as well as unsegmented IMEI/SV. */ private static final Pattern PATTERN_IMEI = Pattern.compile( "(^|[^0-9])(?:" // IMEI, AABBBBBB-CCCCCC-D format; IMEI/SV, AABBBBBB-CCCCCC-EE format + "[0-9]{8}-[0-9]{6}-[0-9][0-9]?" // IMEI, AA-BBBBBB-CCCCCC-D format; IMEI/SV, AA-BBBBBB-CCCCCC-EE format + "|[0-9]{2}-[0-9]{6}-[0-9]{6}-[0-9][0-9]?" // IMEI/SV, unsegmented + "|[0-9]{16}" + ")($|[^0-9])"); /** Replacement for IMEI. */ private static final String REPLACEMENT_IMEI = "$1<IMEI_REDACTED>$2"; /** * Pattern used to match potential unsegmented IMEI/IMSI values in IMS extra messages for * filtering. */ private static final Pattern PATTERN_UNSEGMENTED_IMEI_IMSI = Pattern.compile("(^|[^0-9])[0-9]{15}($|[^0-9])"); /** Replacement for unsegmented IMEI/IMSI. */ private static final String REPLACEMENT_UNSEGMENTED_IMEI_IMSI = "$1<IMEI_IMSI_REDACTED>$2"; /** * Pattern used to match hostnames in IMS extra messages for filtering. * * <p>This pattern differs from {@link android.util.Patterns.DOMAIN_NAME} in a few ways: it * requires the name to have at least 3 segments (shorter names are nearly always public or * typos, i.e. missing space after period), does not check the validity of TLDs, and does not * support punycodes in TLDs. */ private static final Pattern PATTERN_HOSTNAME = Pattern.compile("([0-9a-zA-Z][0-9a-zA-Z_\\-]{0,61}[0-9a-zA-Z]\\.){2,}[a-zA-Z]{2,}"); /** Replacement for hostnames. */ private static final String REPLACEMENT_HOSTNAME = "<HOSTNAME_REDACTED>"; /** * Pattern used to match potential IDs in IMS extra messages for filtering. * * <p>This pattern target numbers that are potential IDs in unknown formats. It should be * replaced after all other replacements are done to ensure complete and correct filtering. * * <p>Specifically, this pattern looks for any number (including hex) that is separated by dots * or dashes has at least 6 significant digits, and any unsegmented numbers that has at least 5 * significant digits. */ private static final Pattern PATTERN_UNKNOWN_ID = Pattern.compile( "(^|[^0-9a-fA-F])(([-\\.]?0)*[1-9a-fA-F]([-\\.]?[0-9a-fA-F]){5,}" + "|0*[1-9a-fA-F]([0-9a-fA-F]){4,})"); /** Replacement for potential IDs. */ private static final String REPLACEMENT_UNKNOWN_ID = "$1<ID_REDACTED>"; private final ImsPhone mPhone; private final ImsPhone mPhone; private final PersistAtomsStorage mStorage; private final PersistAtomsStorage mStorage; Loading Loading @@ -204,7 +324,7 @@ public class ImsStats { termination.setupFailed = (mLastRegistrationState != REGISTRATION_STATE_REGISTERED); termination.setupFailed = (mLastRegistrationState != REGISTRATION_STATE_REGISTERED); termination.reasonCode = reasonInfo.getCode(); termination.reasonCode = reasonInfo.getCode(); termination.extraCode = reasonInfo.getExtraCode(); termination.extraCode = reasonInfo.getExtraCode(); termination.extraMessage = sanitizeExtraMessage(reasonInfo.getExtraMessage()); termination.extraMessage = filterExtraMessage(reasonInfo.getExtraMessage()); termination.count = 1; termination.count = 1; mStorage.addImsRegistrationTermination(termination); mStorage.addImsRegistrationTermination(termination); Loading Loading @@ -303,10 +423,22 @@ public class ImsStats { return SystemClock.elapsedRealtime(); return SystemClock.elapsedRealtime(); } } private static String sanitizeExtraMessage(@Nullable String str) { /** Filters IMS extra messages to ensure length limit and remove IDs. */ public static String filterExtraMessage(@Nullable String str) { if (str == null) { if (str == null) { return ""; return ""; } } str = PATTERN_UUID.matcher(str).replaceAll(REPLACEMENT_UUID); str = PATTERN_URI.matcher(str).replaceAll(REPLACEMENT_URI); str = PATTERN_HOSTNAME.matcher(str).replaceAll(REPLACEMENT_HOSTNAME); str = PATTERN_IPV4.matcher(str).replaceAll(REPLACEMENT_IPV4); str = PATTERN_IPV6.matcher(str).replaceAll(REPLACEMENT_IPV6); str = PATTERN_IMEI.matcher(str).replaceAll(REPLACEMENT_IMEI); str = PATTERN_UNSEGMENTED_IMEI_IMSI.matcher(str) .replaceAll(REPLACEMENT_UNSEGMENTED_IMEI_IMSI); str = PATTERN_UNKNOWN_ID.matcher(str).replaceAll(REPLACEMENT_UNKNOWN_ID); return str.length() > MAX_EXTRA_MESSAGE_LENGTH return str.length() > MAX_EXTRA_MESSAGE_LENGTH ? str.substring(0, MAX_EXTRA_MESSAGE_LENGTH) ? str.substring(0, MAX_EXTRA_MESSAGE_LENGTH) : str; : str; Loading src/java/com/android/internal/telephony/metrics/VoiceCallSessionStats.java +1 −1 Original line number Original line Diff line number Diff line Loading @@ -533,7 +533,7 @@ public class VoiceCallSessionStats { proto.bearerAtEnd = VOICE_CALL_SESSION__BEARER_AT_END__CALL_BEARER_IMS; proto.bearerAtEnd = VOICE_CALL_SESSION__BEARER_AT_END__CALL_BEARER_IMS; proto.disconnectReasonCode = reasonInfo.mCode; proto.disconnectReasonCode = reasonInfo.mCode; proto.disconnectExtraCode = reasonInfo.mExtraCode; proto.disconnectExtraCode = reasonInfo.mExtraCode; proto.disconnectExtraMessage = reasonInfo.mExtraMessage; proto.disconnectExtraMessage = ImsStats.filterExtraMessage(reasonInfo.mExtraMessage); finishCall(id); finishCall(id); } } Loading tests/telephonytests/src/com/android/internal/telephony/metrics/ImsStatsTest.java +124 −2 Original line number Original line Diff line number Diff line Loading @@ -50,12 +50,16 @@ import com.android.internal.telephony.nano.PersistAtomsProto.ImsRegistrationTerm import com.android.internal.telephony.uicc.IccCardStatus.CardState; import com.android.internal.telephony.uicc.IccCardStatus.CardState; import com.android.internal.telephony.uicc.UiccSlot; import com.android.internal.telephony.uicc.UiccSlot; import com.google.common.collect.ImmutableMap; import org.junit.After; import org.junit.After; import org.junit.Before; import org.junit.Before; import org.junit.Test; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.Mock; import java.util.Map; public class ImsStatsTest extends TelephonyTest { public class ImsStatsTest extends TelephonyTest { private static final long START_TIME_MILLIS = 2000L; private static final long START_TIME_MILLIS = 2000L; private static final int CARRIER1_ID = 1; private static final int CARRIER1_ID = 1; Loading Loading @@ -523,8 +527,8 @@ public class ImsStatsTest extends TelephonyTest { public void onImsUnregistered_longMessage() throws Exception { public void onImsUnregistered_longMessage() throws Exception { String longExtraMessage = String longExtraMessage = "This message is too long -- it has more than 128 characters: " "This message is too long -- it has more than 128 characters: " + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ" + " This is the end of the message."; + " This is the end of the message."; mImsStats.onImsUnregistered( mImsStats.onImsUnregistered( new ImsReasonInfo(ImsReasonInfo.CODE_REGISTRATION_ERROR, 0, longExtraMessage)); new ImsReasonInfo(ImsReasonInfo.CODE_REGISTRATION_ERROR, 0, longExtraMessage)); Loading @@ -545,6 +549,124 @@ public class ImsStatsTest extends TelephonyTest { verifyNoMoreInteractions(mPersistAtomsStorage); verifyNoMoreInteractions(mPersistAtomsStorage); } } @Test @SmallTest public void filterExtraMessage_noNeedToFilter() throws Exception { final String[] messages = { "Q.850;cause=16", "SIP;cause=200", "q.850", "600", "Call ended during conference merge process.", "cc_term_noreply_tmr_expired", "[e] user triggered", "normal end of call", "cc_q850_017_user_busy", "service unavailable (1:223)", "IP Change", "rtp-rtcp timeout", "0x0000030b", "CD-021: ISP Problem", "IP;cause=487;text=\"Originator canceled;Canceled(t),iCode=CC_SIP_REQUEST_TERMINATED\"", "pt: asr: insufficient_bearer_resources", "po: aaa: result_code=0 exp_result_code=5065", "a peer released.total external peer:1. allowed:2. clear the remain parties(o)," + "icode=cc_sip_request_timeout" }; for (String message : messages) { assertEquals(message, ImsStats.filterExtraMessage(message)); } } @Test @SmallTest public void filterExtraMessage_needToFilter() throws Exception { Map<String, String> originalAndExpectedMessages = ImmutableMap.<String, String>builder() // UUIDs .put( "Q.850;cause=34;text=\"12345678-abcd-ef12-34ab-000000000012;" + "User is busy and currently active on another call.\"", "Q.850;cause=34;text=\"<UUID_REDACTED>;" + "User is busy and currently active on another call.\"") .put( "Q.850;cause=34;text=\"12345678-ABCD-EF12-34AB-000000000012;" + "User is busy and currently active on another call.\"", "Q.850;cause=34;text=\"<UUID_REDACTED>;" + "User is busy and currently active on another call.\"") // URIs .put( "SIP;cause=500;text=\"sip:+1234567890@irps.voip.telefonica.de;user=phone" + " clear the call.;Canceled(t)\"", "SIP;cause=500;text=\"sip:<REDACTED>;user=phone" + " clear the call.;Canceled(t)\"") .put( "SIP;cause=500;text=\"SIP:+1234567890@irps.voip.telefonica.de;user=phone" + " clear the call.;Canceled(t)\"", "SIP;cause=500;text=\"SIP:<REDACTED>;user=phone" + " clear the call.;Canceled(t)\"") // IP addresses .put( "dtls handshake error[timeout][2607:F8B0::1] and client disconnected", "dtls handshake error[timeout][<IPV6_REDACTED>] and client disconnected") .put( "dtls handshake error[timeout][2607:f8b0::1] and client disconnected", "dtls handshake error[timeout][<IPV6_REDACTED>] and client disconnected") .put( "dtls handshake error 2607:f8b0:1:2:3:4:56:789", "dtls handshake error <IPV6_REDACTED>") .put( "dtls handshake error[timeout][8.8.8.8] and client disconnected", "dtls handshake error[timeout][<IPV4_REDACTED>] and client disconnected") .put("8.8.8.8 client disconnected", "<IPV4_REDACTED> client disconnected") // IMEIs/IMSIs .put( "call completed elsewhere by instance 313460000000001", "call completed elsewhere by instance <IMEI_IMSI_REDACTED>") .put( "call completed elsewhere by instance 31346000-000000-1", "call completed elsewhere by instance <IMEI_REDACTED>") .put( "call completed elsewhere by instance 31-346000-000000-1", "call completed elsewhere by instance <IMEI_REDACTED>") .put( "call completed elsewhere by instance 31-346000-000000-12", "call completed elsewhere by instance <IMEI_REDACTED>") .put( "399 123.4567.89.ATS.blah.ims.mnc123.mcc456.3gppnetwork.org" + " \"Failure cause code is sip status code.\"", "399 <HOSTNAME_REDACTED> \"Failure cause code is sip status code.\"") // Unknown IDs .put( "01200.30004.a.560.789.123.0.0.00045.00000006" + " released the session because of netfail by no media", // "123.0.0.0" looks like IPv4 "<ID_REDACTED><IPV4_REDACTED><ID_REDACTED>" + " released the session because of netfail by no media") .put( "example.cpp,1234,12-300-450-67-89123456:-12345678," + "tyringtimeout:timer b expired(t)", "example.cpp,1234,<ID_REDACTED>:-<ID_REDACTED>," + "tyringtimeout:timer b expired(t)") .put( "ss120000f123l1234 invite 2xx after cancel rsp has been received", "ss<ID_REDACTED>l1234 invite 2xx after cancel rsp has been received") .put( "X.int;reasoncode=0x00000123;add-info=0123.00AB.0001", "X.int;reasoncode=0x00000123;add-info=<ID_REDACTED>") .put( "X.int;reasoncode=0x00123abc;add-info=0123.00AB.0001", "X.int;reasoncode=0x<ID_REDACTED>;add-info=<ID_REDACTED>") .put( "Cx Unable To Comply 1203045067D8009", "Cx Unable To Comply <ID_REDACTED>") .build(); for (Map.Entry<String, String> entry : originalAndExpectedMessages.entrySet()) { assertEquals(entry.getValue(), ImsStats.filterExtraMessage(entry.getKey())); } } @Test @Test @SmallTest @SmallTest public void onImsUnregistered_multiSim() throws Exception { public void onImsUnregistered_multiSim() throws Exception { Loading Loading
src/java/com/android/internal/telephony/metrics/ImsStats.java +134 −2 Original line number Original line Diff line number Diff line Loading @@ -27,6 +27,7 @@ import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TE import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_LTE; import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_LTE; import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_NONE; import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_NONE; import static android.text.format.DateUtils.SECOND_IN_MILLIS; import static android.text.format.DateUtils.SECOND_IN_MILLIS; import static android.util.Patterns.EMAIL_ADDRESS; import android.annotation.Nullable; import android.annotation.Nullable; import android.os.SystemClock; import android.os.SystemClock; Loading @@ -51,6 +52,8 @@ import com.android.internal.telephony.nano.PersistAtomsProto.ImsRegistrationStat import com.android.internal.telephony.nano.PersistAtomsProto.ImsRegistrationTermination; import com.android.internal.telephony.nano.PersistAtomsProto.ImsRegistrationTermination; import com.android.telephony.Rlog; import com.android.telephony.Rlog; import java.util.regex.Pattern; /** Tracks IMS registration metrics for each phone. */ /** Tracks IMS registration metrics for each phone. */ public class ImsStats { public class ImsStats { private static final String TAG = ImsStats.class.getSimpleName(); private static final String TAG = ImsStats.class.getSimpleName(); Loading @@ -70,6 +73,123 @@ public class ImsStats { */ */ private static final int MAX_EXTRA_MESSAGE_LENGTH = 128; private static final int MAX_EXTRA_MESSAGE_LENGTH = 128; /** Pattern used to match UUIDs in IMS extra messages for filtering. */ private static final Pattern PATTERN_UUID = Pattern.compile( "[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}"); /** Replacement for UUIDs. */ private static final String REPLACEMENT_UUID = "<UUID_REDACTED>"; /** * Pattern used to match URI (e.g. sip, tel) in IMS extra messages for filtering. * * <p>NOTE: this simple pattern aims to catch the most common URI schemes. It is not meant to be * RFC-complaint. */ private static final Pattern PATTERN_URI = Pattern.compile("([a-zA-Z]{2,}:)" + EMAIL_ADDRESS.pattern()); /** Replacement for URI. */ private static final String REPLACEMENT_URI = "$1<REDACTED>"; /** * Pattern used to match IPv4 addresses in IMS extra messages for filtering. * * <p>This is a copy of {@code android.util.Patterns.IP_ADDRESS}, which is deprecated and might * be removed in the future. */ private static final Pattern PATTERN_IPV4 = Pattern.compile( "((25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.(25[0-5]|2[0-4]" + "[0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1]" + "[0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}" + "|[1-9][0-9]|[0-9]))"); /** Replacement for IPv4 addresses. */ private static final String REPLACEMENT_IPV4 = "<IPV4_REDACTED>"; /** * Pattern used to match IPv6 addresses in IMS extra messages for filtering. * * <p>NOTE: this pattern aims to catch the most common IPv6 addresses. It is not meant to be * RFC-complaint or free of false positives. */ private static final Pattern PATTERN_IPV6 = Pattern.compile( // Full address "([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}" // Abbreviated address, e.g. 2001:4860:4860::8888 + "|([0-9a-fA-F]{1,4}:){1,6}(:[0-9a-fA-F]{1,4}){1,6}" // Abbreviated network address, e.g. 2607:F8B0:: + "|([0-9a-fA-F]{1,4}:){1,7}:" // Abbreviated address, e.g. ::1 + "|:(:[0-9a-fA-F]{1,4}){1,7}"); /** Replacement for IPv6 addresses. */ private static final String REPLACEMENT_IPV6 = "<IPV6_REDACTED>"; /** * Pattern used to match potential IMEI values in IMS extra messages for filtering. * * <p>This includes segmented IMEI or IMEI/SV, as well as unsegmented IMEI/SV. */ private static final Pattern PATTERN_IMEI = Pattern.compile( "(^|[^0-9])(?:" // IMEI, AABBBBBB-CCCCCC-D format; IMEI/SV, AABBBBBB-CCCCCC-EE format + "[0-9]{8}-[0-9]{6}-[0-9][0-9]?" // IMEI, AA-BBBBBB-CCCCCC-D format; IMEI/SV, AA-BBBBBB-CCCCCC-EE format + "|[0-9]{2}-[0-9]{6}-[0-9]{6}-[0-9][0-9]?" // IMEI/SV, unsegmented + "|[0-9]{16}" + ")($|[^0-9])"); /** Replacement for IMEI. */ private static final String REPLACEMENT_IMEI = "$1<IMEI_REDACTED>$2"; /** * Pattern used to match potential unsegmented IMEI/IMSI values in IMS extra messages for * filtering. */ private static final Pattern PATTERN_UNSEGMENTED_IMEI_IMSI = Pattern.compile("(^|[^0-9])[0-9]{15}($|[^0-9])"); /** Replacement for unsegmented IMEI/IMSI. */ private static final String REPLACEMENT_UNSEGMENTED_IMEI_IMSI = "$1<IMEI_IMSI_REDACTED>$2"; /** * Pattern used to match hostnames in IMS extra messages for filtering. * * <p>This pattern differs from {@link android.util.Patterns.DOMAIN_NAME} in a few ways: it * requires the name to have at least 3 segments (shorter names are nearly always public or * typos, i.e. missing space after period), does not check the validity of TLDs, and does not * support punycodes in TLDs. */ private static final Pattern PATTERN_HOSTNAME = Pattern.compile("([0-9a-zA-Z][0-9a-zA-Z_\\-]{0,61}[0-9a-zA-Z]\\.){2,}[a-zA-Z]{2,}"); /** Replacement for hostnames. */ private static final String REPLACEMENT_HOSTNAME = "<HOSTNAME_REDACTED>"; /** * Pattern used to match potential IDs in IMS extra messages for filtering. * * <p>This pattern target numbers that are potential IDs in unknown formats. It should be * replaced after all other replacements are done to ensure complete and correct filtering. * * <p>Specifically, this pattern looks for any number (including hex) that is separated by dots * or dashes has at least 6 significant digits, and any unsegmented numbers that has at least 5 * significant digits. */ private static final Pattern PATTERN_UNKNOWN_ID = Pattern.compile( "(^|[^0-9a-fA-F])(([-\\.]?0)*[1-9a-fA-F]([-\\.]?[0-9a-fA-F]){5,}" + "|0*[1-9a-fA-F]([0-9a-fA-F]){4,})"); /** Replacement for potential IDs. */ private static final String REPLACEMENT_UNKNOWN_ID = "$1<ID_REDACTED>"; private final ImsPhone mPhone; private final ImsPhone mPhone; private final PersistAtomsStorage mStorage; private final PersistAtomsStorage mStorage; Loading Loading @@ -204,7 +324,7 @@ public class ImsStats { termination.setupFailed = (mLastRegistrationState != REGISTRATION_STATE_REGISTERED); termination.setupFailed = (mLastRegistrationState != REGISTRATION_STATE_REGISTERED); termination.reasonCode = reasonInfo.getCode(); termination.reasonCode = reasonInfo.getCode(); termination.extraCode = reasonInfo.getExtraCode(); termination.extraCode = reasonInfo.getExtraCode(); termination.extraMessage = sanitizeExtraMessage(reasonInfo.getExtraMessage()); termination.extraMessage = filterExtraMessage(reasonInfo.getExtraMessage()); termination.count = 1; termination.count = 1; mStorage.addImsRegistrationTermination(termination); mStorage.addImsRegistrationTermination(termination); Loading Loading @@ -303,10 +423,22 @@ public class ImsStats { return SystemClock.elapsedRealtime(); return SystemClock.elapsedRealtime(); } } private static String sanitizeExtraMessage(@Nullable String str) { /** Filters IMS extra messages to ensure length limit and remove IDs. */ public static String filterExtraMessage(@Nullable String str) { if (str == null) { if (str == null) { return ""; return ""; } } str = PATTERN_UUID.matcher(str).replaceAll(REPLACEMENT_UUID); str = PATTERN_URI.matcher(str).replaceAll(REPLACEMENT_URI); str = PATTERN_HOSTNAME.matcher(str).replaceAll(REPLACEMENT_HOSTNAME); str = PATTERN_IPV4.matcher(str).replaceAll(REPLACEMENT_IPV4); str = PATTERN_IPV6.matcher(str).replaceAll(REPLACEMENT_IPV6); str = PATTERN_IMEI.matcher(str).replaceAll(REPLACEMENT_IMEI); str = PATTERN_UNSEGMENTED_IMEI_IMSI.matcher(str) .replaceAll(REPLACEMENT_UNSEGMENTED_IMEI_IMSI); str = PATTERN_UNKNOWN_ID.matcher(str).replaceAll(REPLACEMENT_UNKNOWN_ID); return str.length() > MAX_EXTRA_MESSAGE_LENGTH return str.length() > MAX_EXTRA_MESSAGE_LENGTH ? str.substring(0, MAX_EXTRA_MESSAGE_LENGTH) ? str.substring(0, MAX_EXTRA_MESSAGE_LENGTH) : str; : str; Loading
src/java/com/android/internal/telephony/metrics/VoiceCallSessionStats.java +1 −1 Original line number Original line Diff line number Diff line Loading @@ -533,7 +533,7 @@ public class VoiceCallSessionStats { proto.bearerAtEnd = VOICE_CALL_SESSION__BEARER_AT_END__CALL_BEARER_IMS; proto.bearerAtEnd = VOICE_CALL_SESSION__BEARER_AT_END__CALL_BEARER_IMS; proto.disconnectReasonCode = reasonInfo.mCode; proto.disconnectReasonCode = reasonInfo.mCode; proto.disconnectExtraCode = reasonInfo.mExtraCode; proto.disconnectExtraCode = reasonInfo.mExtraCode; proto.disconnectExtraMessage = reasonInfo.mExtraMessage; proto.disconnectExtraMessage = ImsStats.filterExtraMessage(reasonInfo.mExtraMessage); finishCall(id); finishCall(id); } } Loading
tests/telephonytests/src/com/android/internal/telephony/metrics/ImsStatsTest.java +124 −2 Original line number Original line Diff line number Diff line Loading @@ -50,12 +50,16 @@ import com.android.internal.telephony.nano.PersistAtomsProto.ImsRegistrationTerm import com.android.internal.telephony.uicc.IccCardStatus.CardState; import com.android.internal.telephony.uicc.IccCardStatus.CardState; import com.android.internal.telephony.uicc.UiccSlot; import com.android.internal.telephony.uicc.UiccSlot; import com.google.common.collect.ImmutableMap; import org.junit.After; import org.junit.After; import org.junit.Before; import org.junit.Before; import org.junit.Test; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.Mock; import java.util.Map; public class ImsStatsTest extends TelephonyTest { public class ImsStatsTest extends TelephonyTest { private static final long START_TIME_MILLIS = 2000L; private static final long START_TIME_MILLIS = 2000L; private static final int CARRIER1_ID = 1; private static final int CARRIER1_ID = 1; Loading Loading @@ -523,8 +527,8 @@ public class ImsStatsTest extends TelephonyTest { public void onImsUnregistered_longMessage() throws Exception { public void onImsUnregistered_longMessage() throws Exception { String longExtraMessage = String longExtraMessage = "This message is too long -- it has more than 128 characters: " "This message is too long -- it has more than 128 characters: " + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ" + " This is the end of the message."; + " This is the end of the message."; mImsStats.onImsUnregistered( mImsStats.onImsUnregistered( new ImsReasonInfo(ImsReasonInfo.CODE_REGISTRATION_ERROR, 0, longExtraMessage)); new ImsReasonInfo(ImsReasonInfo.CODE_REGISTRATION_ERROR, 0, longExtraMessage)); Loading @@ -545,6 +549,124 @@ public class ImsStatsTest extends TelephonyTest { verifyNoMoreInteractions(mPersistAtomsStorage); verifyNoMoreInteractions(mPersistAtomsStorage); } } @Test @SmallTest public void filterExtraMessage_noNeedToFilter() throws Exception { final String[] messages = { "Q.850;cause=16", "SIP;cause=200", "q.850", "600", "Call ended during conference merge process.", "cc_term_noreply_tmr_expired", "[e] user triggered", "normal end of call", "cc_q850_017_user_busy", "service unavailable (1:223)", "IP Change", "rtp-rtcp timeout", "0x0000030b", "CD-021: ISP Problem", "IP;cause=487;text=\"Originator canceled;Canceled(t),iCode=CC_SIP_REQUEST_TERMINATED\"", "pt: asr: insufficient_bearer_resources", "po: aaa: result_code=0 exp_result_code=5065", "a peer released.total external peer:1. allowed:2. clear the remain parties(o)," + "icode=cc_sip_request_timeout" }; for (String message : messages) { assertEquals(message, ImsStats.filterExtraMessage(message)); } } @Test @SmallTest public void filterExtraMessage_needToFilter() throws Exception { Map<String, String> originalAndExpectedMessages = ImmutableMap.<String, String>builder() // UUIDs .put( "Q.850;cause=34;text=\"12345678-abcd-ef12-34ab-000000000012;" + "User is busy and currently active on another call.\"", "Q.850;cause=34;text=\"<UUID_REDACTED>;" + "User is busy and currently active on another call.\"") .put( "Q.850;cause=34;text=\"12345678-ABCD-EF12-34AB-000000000012;" + "User is busy and currently active on another call.\"", "Q.850;cause=34;text=\"<UUID_REDACTED>;" + "User is busy and currently active on another call.\"") // URIs .put( "SIP;cause=500;text=\"sip:+1234567890@irps.voip.telefonica.de;user=phone" + " clear the call.;Canceled(t)\"", "SIP;cause=500;text=\"sip:<REDACTED>;user=phone" + " clear the call.;Canceled(t)\"") .put( "SIP;cause=500;text=\"SIP:+1234567890@irps.voip.telefonica.de;user=phone" + " clear the call.;Canceled(t)\"", "SIP;cause=500;text=\"SIP:<REDACTED>;user=phone" + " clear the call.;Canceled(t)\"") // IP addresses .put( "dtls handshake error[timeout][2607:F8B0::1] and client disconnected", "dtls handshake error[timeout][<IPV6_REDACTED>] and client disconnected") .put( "dtls handshake error[timeout][2607:f8b0::1] and client disconnected", "dtls handshake error[timeout][<IPV6_REDACTED>] and client disconnected") .put( "dtls handshake error 2607:f8b0:1:2:3:4:56:789", "dtls handshake error <IPV6_REDACTED>") .put( "dtls handshake error[timeout][8.8.8.8] and client disconnected", "dtls handshake error[timeout][<IPV4_REDACTED>] and client disconnected") .put("8.8.8.8 client disconnected", "<IPV4_REDACTED> client disconnected") // IMEIs/IMSIs .put( "call completed elsewhere by instance 313460000000001", "call completed elsewhere by instance <IMEI_IMSI_REDACTED>") .put( "call completed elsewhere by instance 31346000-000000-1", "call completed elsewhere by instance <IMEI_REDACTED>") .put( "call completed elsewhere by instance 31-346000-000000-1", "call completed elsewhere by instance <IMEI_REDACTED>") .put( "call completed elsewhere by instance 31-346000-000000-12", "call completed elsewhere by instance <IMEI_REDACTED>") .put( "399 123.4567.89.ATS.blah.ims.mnc123.mcc456.3gppnetwork.org" + " \"Failure cause code is sip status code.\"", "399 <HOSTNAME_REDACTED> \"Failure cause code is sip status code.\"") // Unknown IDs .put( "01200.30004.a.560.789.123.0.0.00045.00000006" + " released the session because of netfail by no media", // "123.0.0.0" looks like IPv4 "<ID_REDACTED><IPV4_REDACTED><ID_REDACTED>" + " released the session because of netfail by no media") .put( "example.cpp,1234,12-300-450-67-89123456:-12345678," + "tyringtimeout:timer b expired(t)", "example.cpp,1234,<ID_REDACTED>:-<ID_REDACTED>," + "tyringtimeout:timer b expired(t)") .put( "ss120000f123l1234 invite 2xx after cancel rsp has been received", "ss<ID_REDACTED>l1234 invite 2xx after cancel rsp has been received") .put( "X.int;reasoncode=0x00000123;add-info=0123.00AB.0001", "X.int;reasoncode=0x00000123;add-info=<ID_REDACTED>") .put( "X.int;reasoncode=0x00123abc;add-info=0123.00AB.0001", "X.int;reasoncode=0x<ID_REDACTED>;add-info=<ID_REDACTED>") .put( "Cx Unable To Comply 1203045067D8009", "Cx Unable To Comply <ID_REDACTED>") .build(); for (Map.Entry<String, String> entry : originalAndExpectedMessages.entrySet()) { assertEquals(entry.getValue(), ImsStats.filterExtraMessage(entry.getKey())); } } @Test @Test @SmallTest @SmallTest public void onImsUnregistered_multiSim() throws Exception { public void onImsUnregistered_multiSim() throws Exception { Loading