AnalyticsTests.java revision 8449ca41a012b4a659c8aef1d8dd41a6790adf27
1/* 2 * Copyright (C) 2016 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 17package com.android.server.telecom.tests; 18 19import android.content.Context; 20import android.telecom.Connection; 21import android.telecom.DisconnectCause; 22import android.telecom.InCallService; 23import android.telecom.Log; 24import android.telecom.ParcelableCallAnalytics; 25import android.telecom.TelecomAnalytics; 26import android.telecom.TelecomManager; 27import android.telecom.VideoCallImpl; 28import android.telecom.VideoProfile; 29import android.test.suitebuilder.annotation.MediumTest; 30import android.test.suitebuilder.annotation.SmallTest; 31import android.util.Base64; 32 33import com.android.internal.util.IndentingPrintWriter; 34import com.android.server.telecom.Analytics; 35import com.android.server.telecom.LogUtils; 36import com.android.server.telecom.TelecomLogClass; 37 38import java.io.PrintWriter; 39import java.io.StringWriter; 40import java.util.Arrays; 41import java.util.HashSet; 42import java.util.List; 43import java.util.Map; 44import java.util.Set; 45import java.util.concurrent.CountDownLatch; 46import java.util.concurrent.TimeUnit; 47 48import static org.mockito.Matchers.any; 49import static org.mockito.Matchers.anyInt; 50import static org.mockito.Mockito.doAnswer; 51import static org.mockito.Mockito.mock; 52 53public class AnalyticsTests extends TelecomSystemTest { 54 @MediumTest 55 public void testAnalyticsSingleCall() throws Exception { 56 IdPair testCall = startAndMakeActiveIncomingCall( 57 "650-555-1212", 58 mPhoneAccountA0.getAccountHandle(), 59 mConnectionServiceFixtureA); 60 61 Map<String, Analytics.CallInfoImpl> analyticsMap = Analytics.cloneData(); 62 63 assertTrue(analyticsMap.containsKey(testCall.mCallId)); 64 65 Analytics.CallInfoImpl callAnalytics = analyticsMap.get(testCall.mCallId); 66 assertTrue(callAnalytics.startTime > 0); 67 assertEquals(0, callAnalytics.endTime); 68 assertEquals(Analytics.INCOMING_DIRECTION, callAnalytics.callDirection); 69 assertFalse(callAnalytics.isInterrupted); 70 assertNull(callAnalytics.callTerminationReason); 71 assertEquals(mConnectionServiceComponentNameA.flattenToShortString(), 72 callAnalytics.connectionService); 73 74 mConnectionServiceFixtureA. 75 sendSetDisconnected(testCall.mConnectionId, DisconnectCause.ERROR); 76 77 analyticsMap = Analytics.cloneData(); 78 callAnalytics = analyticsMap.get(testCall.mCallId); 79 assertTrue(callAnalytics.endTime > 0); 80 assertNotNull(callAnalytics.callTerminationReason); 81 assertEquals(DisconnectCause.ERROR, callAnalytics.callTerminationReason.getCode()); 82 83 StringWriter sr = new StringWriter(); 84 IndentingPrintWriter ip = new IndentingPrintWriter(sr, " "); 85 Analytics.dump(ip); 86 String dumpResult = sr.toString(); 87 String[] expectedFields = {"startTime", "endTime", "direction", "isAdditionalCall", 88 "isInterrupted", "callTechnologies", "callTerminationReason", "connectionService"}; 89 for (String field : expectedFields) { 90 assertTrue(dumpResult.contains(field)); 91 } 92 } 93 94 @MediumTest 95 public void testAnalyticsDumping() throws Exception { 96 Analytics.reset(); 97 IdPair testCall = startAndMakeActiveIncomingCall( 98 "650-555-1212", 99 mPhoneAccountA0.getAccountHandle(), 100 mConnectionServiceFixtureA); 101 102 mConnectionServiceFixtureA. 103 sendSetDisconnected(testCall.mConnectionId, DisconnectCause.ERROR); 104 Analytics.CallInfoImpl expectedAnalytics = Analytics.cloneData().get(testCall.mCallId); 105 106 TelecomManager tm = (TelecomManager) mSpyContext.getSystemService(Context.TELECOM_SERVICE); 107 List<ParcelableCallAnalytics> analyticsList = tm.dumpAnalytics().getCallAnalytics(); 108 109 assertEquals(1, analyticsList.size()); 110 ParcelableCallAnalytics pCA = analyticsList.get(0); 111 112 assertTrue(Math.abs(expectedAnalytics.startTime - pCA.getStartTimeMillis()) < 113 ParcelableCallAnalytics.MILLIS_IN_5_MINUTES); 114 assertEquals(0, pCA.getStartTimeMillis() % ParcelableCallAnalytics.MILLIS_IN_5_MINUTES); 115 assertTrue(Math.abs((expectedAnalytics.endTime - expectedAnalytics.startTime) - 116 pCA.getCallDurationMillis()) < ParcelableCallAnalytics.MILLIS_IN_1_SECOND); 117 assertEquals(0, pCA.getCallDurationMillis() % ParcelableCallAnalytics.MILLIS_IN_1_SECOND); 118 119 assertEquals(expectedAnalytics.callDirection, pCA.getCallType()); 120 assertEquals(expectedAnalytics.isAdditionalCall, pCA.isAdditionalCall()); 121 assertEquals(expectedAnalytics.isInterrupted, pCA.isInterrupted()); 122 assertEquals(expectedAnalytics.callTechnologies, pCA.getCallTechnologies()); 123 assertEquals(expectedAnalytics.callTerminationReason.getCode(), 124 pCA.getCallTerminationCode()); 125 assertEquals(expectedAnalytics.connectionService, pCA.getConnectionService()); 126 List<ParcelableCallAnalytics.AnalyticsEvent> analyticsEvents = pCA.analyticsEvents(); 127 Set<Integer> capturedEvents = new HashSet<>(); 128 for (ParcelableCallAnalytics.AnalyticsEvent e : analyticsEvents) { 129 capturedEvents.add(e.getEventName()); 130 assertIsRoundedToOneSigFig(e.getTimeSinceLastEvent()); 131 } 132 assertTrue(capturedEvents.contains(ParcelableCallAnalytics.AnalyticsEvent.SET_ACTIVE)); 133 assertTrue(capturedEvents.contains( 134 ParcelableCallAnalytics.AnalyticsEvent.FILTERING_INITIATED)); 135 } 136 137 @MediumTest 138 public void testAnalyticsTwoCalls() throws Exception { 139 IdPair testCall1 = startAndMakeActiveIncomingCall( 140 "650-555-1212", 141 mPhoneAccountA0.getAccountHandle(), 142 mConnectionServiceFixtureA); 143 IdPair testCall2 = startAndMakeActiveOutgoingCall( 144 "650-555-1213", 145 mPhoneAccountA0.getAccountHandle(), 146 mConnectionServiceFixtureA); 147 148 Map<String, Analytics.CallInfoImpl> analyticsMap = Analytics.cloneData(); 149 assertTrue(analyticsMap.containsKey(testCall1.mCallId)); 150 assertTrue(analyticsMap.containsKey(testCall2.mCallId)); 151 152 Analytics.CallInfoImpl callAnalytics1 = analyticsMap.get(testCall1.mCallId); 153 Analytics.CallInfoImpl callAnalytics2 = analyticsMap.get(testCall2.mCallId); 154 assertTrue(callAnalytics1.startTime > 0); 155 assertTrue(callAnalytics2.startTime > 0); 156 assertEquals(0, callAnalytics1.endTime); 157 assertEquals(0, callAnalytics2.endTime); 158 159 assertEquals(Analytics.INCOMING_DIRECTION, callAnalytics1.callDirection); 160 assertEquals(Analytics.OUTGOING_DIRECTION, callAnalytics2.callDirection); 161 162 assertTrue(callAnalytics1.isInterrupted); 163 assertTrue(callAnalytics2.isAdditionalCall); 164 165 assertNull(callAnalytics1.callTerminationReason); 166 assertNull(callAnalytics2.callTerminationReason); 167 168 assertEquals(mConnectionServiceComponentNameA.flattenToShortString(), 169 callAnalytics1.connectionService); 170 assertEquals(mConnectionServiceComponentNameA.flattenToShortString(), 171 callAnalytics1.connectionService); 172 173 mConnectionServiceFixtureA. 174 sendSetDisconnected(testCall2.mConnectionId, DisconnectCause.REMOTE); 175 mConnectionServiceFixtureA. 176 sendSetDisconnected(testCall1.mConnectionId, DisconnectCause.ERROR); 177 178 analyticsMap = Analytics.cloneData(); 179 callAnalytics1 = analyticsMap.get(testCall1.mCallId); 180 callAnalytics2 = analyticsMap.get(testCall2.mCallId); 181 assertTrue(callAnalytics1.endTime > 0); 182 assertTrue(callAnalytics2.endTime > 0); 183 assertNotNull(callAnalytics1.callTerminationReason); 184 assertNotNull(callAnalytics2.callTerminationReason); 185 assertEquals(DisconnectCause.ERROR, callAnalytics1.callTerminationReason.getCode()); 186 assertEquals(DisconnectCause.REMOTE, callAnalytics2.callTerminationReason.getCode()); 187 } 188 189 @MediumTest 190 public void testAnalyticsVideo() throws Exception { 191 Analytics.reset(); 192 IdPair callIds = startAndMakeActiveOutgoingCall( 193 "650-555-1212", 194 mPhoneAccountA0.getAccountHandle(), 195 mConnectionServiceFixtureA); 196 197 CountDownLatch counter = new CountDownLatch(1); 198 InCallService.VideoCall.Callback callback = mock(InCallService.VideoCall.Callback.class); 199 200 doAnswer(invocation -> { 201 counter.countDown(); 202 return null; 203 }).when(callback) 204 .onSessionModifyResponseReceived(anyInt(), any(VideoProfile.class), 205 any(VideoProfile.class)); 206 207 mConnectionServiceFixtureA.sendSetVideoProvider( 208 mConnectionServiceFixtureA.mLatestConnectionId); 209 InCallService.VideoCall videoCall = 210 mInCallServiceFixtureX.getCall(callIds.mCallId).getVideoCallImpl(); 211 videoCall.registerCallback(callback); 212 ((VideoCallImpl) videoCall).setVideoState(VideoProfile.STATE_BIDIRECTIONAL); 213 214 videoCall.sendSessionModifyRequest(new VideoProfile(VideoProfile.STATE_RX_ENABLED)); 215 counter.await(10000, TimeUnit.MILLISECONDS); 216 217 StringWriter sw = new StringWriter(); 218 PrintWriter pw = new PrintWriter(sw); 219 Analytics.dumpToEncodedProto(pw, new String[]{}); 220 TelecomLogClass.TelecomLog analyticsProto = 221 TelecomLogClass.TelecomLog.parseFrom(Base64.decode(sw.toString(), Base64.DEFAULT)); 222 223 assertEquals(1, analyticsProto.callLogs.length); 224 TelecomLogClass.VideoEvent[] videoEvents = analyticsProto.callLogs[0].videoEvents; 225 assertEquals(2, videoEvents.length); 226 227 assertEquals(Analytics.SEND_LOCAL_SESSION_MODIFY_REQUEST, videoEvents[0].getEventName()); 228 assertEquals(VideoProfile.STATE_RX_ENABLED, videoEvents[0].getVideoState()); 229 assertEquals(-1, videoEvents[0].getTimeSinceLastEventMillis()); 230 231 assertEquals(Analytics.RECEIVE_REMOTE_SESSION_MODIFY_RESPONSE, 232 videoEvents[1].getEventName()); 233 assertEquals(VideoProfile.STATE_RX_ENABLED, videoEvents[1].getVideoState()); 234 assertIsRoundedToOneSigFig(videoEvents[1].getTimeSinceLastEventMillis()); 235 } 236 237 @SmallTest 238 public void testAnalyticsRounding() { 239 long[] testVals = {0, -1, -10, -100, -57836, 1, 10, 100, 1000, 458457}; 240 long[] expected = {0, -1, -10, -100, -60000, 1, 10, 100, 1000, 500000}; 241 for (int i = 0; i < testVals.length; i++) { 242 assertEquals(expected[i], Analytics.roundToOneSigFig(testVals[i])); 243 } 244 } 245 246 @SmallTest 247 public void testAnalyticsLogSessionTiming() throws Exception { 248 long minTime = 50; 249 Log.startSession(LogUtils.Sessions.CSW_ADD_CONFERENCE_CALL); 250 Thread.sleep(minTime); 251 Log.endSession(); 252 TelecomManager tm = (TelecomManager) mSpyContext.getSystemService(Context.TELECOM_SERVICE); 253 List<TelecomAnalytics.SessionTiming> sessions = tm.dumpAnalytics().getSessionTimings(); 254 sessions.stream() 255 .filter(s -> LogUtils.Sessions.CSW_ADD_CONFERENCE_CALL.equals( 256 Analytics.sSessionIdToLogSession.get(s.getKey()))) 257 .forEach(s -> assertTrue(s.getTime() >= minTime)); 258 } 259 260 @MediumTest 261 public void testAnalyticsDumpToProto() throws Exception { 262 Analytics.reset(); 263 IdPair testCall = startAndMakeActiveIncomingCall( 264 "650-555-1212", 265 mPhoneAccountA0.getAccountHandle(), 266 mConnectionServiceFixtureA); 267 268 mConnectionServiceFixtureA. 269 sendSetDisconnected(testCall.mConnectionId, DisconnectCause.ERROR); 270 Analytics.CallInfoImpl expectedAnalytics = Analytics.cloneData().get(testCall.mCallId); 271 272 StringWriter sw = new StringWriter(); 273 PrintWriter pw = new PrintWriter(sw); 274 Analytics.dumpToEncodedProto(pw, new String[]{}); 275 TelecomLogClass.TelecomLog analyticsProto = 276 TelecomLogClass.TelecomLog.parseFrom(Base64.decode(sw.toString(), Base64.DEFAULT)); 277 278 assertEquals(1, analyticsProto.callLogs.length); 279 TelecomLogClass.CallLog callLog = analyticsProto.callLogs[0]; 280 281 assertTrue(Math.abs(expectedAnalytics.startTime - callLog.getStartTime5Min()) < 282 ParcelableCallAnalytics.MILLIS_IN_5_MINUTES); 283 assertEquals(0, callLog.getStartTime5Min() % ParcelableCallAnalytics.MILLIS_IN_5_MINUTES); 284 assertTrue(Math.abs((expectedAnalytics.endTime - expectedAnalytics.startTime) - 285 callLog.getCallDurationMillis()) < ParcelableCallAnalytics.MILLIS_IN_1_SECOND); 286 assertEquals(0, 287 callLog.getCallDurationMillis() % ParcelableCallAnalytics.MILLIS_IN_1_SECOND); 288 289 assertEquals(expectedAnalytics.callDirection, callLog.getType()); 290 assertEquals(expectedAnalytics.isAdditionalCall, callLog.getIsAdditionalCall()); 291 assertEquals(expectedAnalytics.isInterrupted, callLog.getIsInterrupted()); 292 assertEquals(expectedAnalytics.callTechnologies, callLog.getCallTechnologies()); 293 assertEquals(expectedAnalytics.callTerminationReason.getCode(), 294 callLog.getCallTerminationCode()); 295 assertEquals(expectedAnalytics.connectionService, callLog.connectionService[0]); 296 TelecomLogClass.Event[] analyticsEvents = callLog.callEvents; 297 Set<Integer> capturedEvents = new HashSet<>(); 298 for (TelecomLogClass.Event e : analyticsEvents) { 299 capturedEvents.add(e.getEventName()); 300 assertIsRoundedToOneSigFig(e.getTimeSinceLastEventMillis()); 301 } 302 assertTrue(capturedEvents.contains(ParcelableCallAnalytics.AnalyticsEvent.SET_ACTIVE)); 303 assertTrue(capturedEvents.contains( 304 ParcelableCallAnalytics.AnalyticsEvent.FILTERING_INITIATED)); 305 } 306 307 @MediumTest 308 public void testAnalyticsConnectionProperties() throws Exception { 309 Analytics.reset(); 310 IdPair testCall = startAndMakeActiveIncomingCall( 311 "650-555-1212", 312 mPhoneAccountA0.getAccountHandle(), 313 mConnectionServiceFixtureA); 314 315 int properties1 = Connection.PROPERTY_IS_DOWNGRADED_CONFERENCE 316 | Connection.PROPERTY_WIFI 317 | Connection.PROPERTY_EMERGENCY_CALLBACK_MODE; 318 int properties2 = Connection.PROPERTY_HIGH_DEF_AUDIO 319 | Connection.PROPERTY_WIFI; 320 int expectedProperties = properties1 | properties2; 321 322 mConnectionServiceFixtureA.mConnectionById.get(testCall.mConnectionId).properties = 323 properties1; 324 mConnectionServiceFixtureA.sendSetConnectionProperties(testCall.mConnectionId); 325 mConnectionServiceFixtureA.mConnectionById.get(testCall.mConnectionId).properties = 326 properties2; 327 mConnectionServiceFixtureA.sendSetConnectionProperties(testCall.mConnectionId); 328 329 mConnectionServiceFixtureA. 330 sendSetDisconnected(testCall.mConnectionId, DisconnectCause.ERROR); 331 332 StringWriter sw = new StringWriter(); 333 PrintWriter pw = new PrintWriter(sw); 334 Analytics.dumpToEncodedProto(pw, new String[]{}); 335 TelecomLogClass.TelecomLog analyticsProto = 336 TelecomLogClass.TelecomLog.parseFrom(Base64.decode(sw.toString(), Base64.DEFAULT)); 337 338 assertEquals(expectedProperties, 339 analyticsProto.callLogs[0].getConnectionProperties() & expectedProperties); 340 } 341 342 @SmallTest 343 public void testAnalyticsMaxSize() throws Exception { 344 Analytics.reset(); 345 for (int i = 0; i < Analytics.MAX_NUM_CALLS_TO_STORE * 2; i++) { 346 Analytics.initiateCallAnalytics(String.valueOf(i), Analytics.INCOMING_DIRECTION) 347 .addCallTechnology(i); 348 } 349 350 StringWriter sw = new StringWriter(); 351 PrintWriter pw = new PrintWriter(sw); 352 Analytics.dumpToEncodedProto(pw, new String[]{}); 353 TelecomLogClass.TelecomLog analyticsProto = 354 TelecomLogClass.TelecomLog.parseFrom(Base64.decode(sw.toString(), Base64.DEFAULT)); 355 356 assertEquals(Analytics.MAX_NUM_CALLS_TO_STORE, analyticsProto.callLogs.length); 357 assertEquals(Arrays.stream(analyticsProto.callLogs) 358 .filter(x -> x.getCallTechnologies() < 100) 359 .count(), 0); 360 } 361 362 private void assertIsRoundedToOneSigFig(long x) { 363 assertEquals(x, Analytics.roundToOneSigFig(x)); 364 } 365} 366