AnalyticsTests.java revision a0a43d51041c9efbe04f7c65236c9e90c3e79346
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.HashSet;
41import java.util.List;
42import java.util.Map;
43import java.util.Set;
44import java.util.concurrent.CountDownLatch;
45import java.util.concurrent.TimeUnit;
46
47import static org.mockito.Matchers.any;
48import static org.mockito.Matchers.anyInt;
49import static org.mockito.Mockito.doAnswer;
50import static org.mockito.Mockito.mock;
51
52public class AnalyticsTests extends TelecomSystemTest {
53    @MediumTest
54    public void testAnalyticsSingleCall() throws Exception {
55        IdPair testCall = startAndMakeActiveIncomingCall(
56                "650-555-1212",
57                mPhoneAccountA0.getAccountHandle(),
58                mConnectionServiceFixtureA);
59
60        Map<String, Analytics.CallInfoImpl> analyticsMap = Analytics.cloneData();
61
62        assertTrue(analyticsMap.containsKey(testCall.mCallId));
63
64        Analytics.CallInfoImpl callAnalytics = analyticsMap.get(testCall.mCallId);
65        assertTrue(callAnalytics.startTime > 0);
66        assertEquals(0, callAnalytics.endTime);
67        assertEquals(Analytics.INCOMING_DIRECTION, callAnalytics.callDirection);
68        assertFalse(callAnalytics.isInterrupted);
69        assertNull(callAnalytics.callTerminationReason);
70        assertEquals(mConnectionServiceComponentNameA.flattenToShortString(),
71                callAnalytics.connectionService);
72
73        mConnectionServiceFixtureA.
74                sendSetDisconnected(testCall.mConnectionId, DisconnectCause.ERROR);
75
76        analyticsMap = Analytics.cloneData();
77        callAnalytics = analyticsMap.get(testCall.mCallId);
78        assertTrue(callAnalytics.endTime > 0);
79        assertNotNull(callAnalytics.callTerminationReason);
80        assertEquals(DisconnectCause.ERROR, callAnalytics.callTerminationReason.getCode());
81
82        StringWriter sr = new StringWriter();
83        IndentingPrintWriter ip = new IndentingPrintWriter(sr, "    ");
84        Analytics.dump(ip);
85        String dumpResult = sr.toString();
86        String[] expectedFields = {"startTime", "endTime", "direction", "isAdditionalCall",
87                "isInterrupted", "callTechnologies", "callTerminationReason", "connectionService"};
88        for (String field : expectedFields) {
89            assertTrue(dumpResult.contains(field));
90        }
91    }
92
93    @MediumTest
94    public void testAnalyticsDumping() throws Exception {
95        Analytics.reset();
96        IdPair testCall = startAndMakeActiveIncomingCall(
97                "650-555-1212",
98                mPhoneAccountA0.getAccountHandle(),
99                mConnectionServiceFixtureA);
100
101        mConnectionServiceFixtureA.
102                sendSetDisconnected(testCall.mConnectionId, DisconnectCause.ERROR);
103        Analytics.CallInfoImpl expectedAnalytics = Analytics.cloneData().get(testCall.mCallId);
104
105        TelecomManager tm = (TelecomManager) mSpyContext.getSystemService(Context.TELECOM_SERVICE);
106        List<ParcelableCallAnalytics> analyticsList = tm.dumpAnalytics().getCallAnalytics();
107
108        assertEquals(1, analyticsList.size());
109        ParcelableCallAnalytics pCA = analyticsList.get(0);
110
111        assertTrue(Math.abs(expectedAnalytics.startTime - pCA.getStartTimeMillis()) <
112                ParcelableCallAnalytics.MILLIS_IN_5_MINUTES);
113        assertEquals(0, pCA.getStartTimeMillis() % ParcelableCallAnalytics.MILLIS_IN_5_MINUTES);
114        assertTrue(Math.abs((expectedAnalytics.endTime - expectedAnalytics.startTime) -
115                pCA.getCallDurationMillis()) < ParcelableCallAnalytics.MILLIS_IN_1_SECOND);
116        assertEquals(0, pCA.getCallDurationMillis() % ParcelableCallAnalytics.MILLIS_IN_1_SECOND);
117
118        assertEquals(expectedAnalytics.callDirection, pCA.getCallType());
119        assertEquals(expectedAnalytics.isAdditionalCall, pCA.isAdditionalCall());
120        assertEquals(expectedAnalytics.isInterrupted, pCA.isInterrupted());
121        assertEquals(expectedAnalytics.callTechnologies, pCA.getCallTechnologies());
122        assertEquals(expectedAnalytics.callTerminationReason.getCode(),
123                pCA.getCallTerminationCode());
124        assertEquals(expectedAnalytics.connectionService, pCA.getConnectionService());
125        List<ParcelableCallAnalytics.AnalyticsEvent> analyticsEvents = pCA.analyticsEvents();
126        Set<Integer> capturedEvents = new HashSet<>();
127        for (ParcelableCallAnalytics.AnalyticsEvent e : analyticsEvents) {
128            capturedEvents.add(e.getEventName());
129            assertIsRoundedToOneSigFig(e.getTimeSinceLastEvent());
130        }
131        assertTrue(capturedEvents.contains(ParcelableCallAnalytics.AnalyticsEvent.SET_ACTIVE));
132        assertTrue(capturedEvents.contains(
133                ParcelableCallAnalytics.AnalyticsEvent.FILTERING_INITIATED));
134    }
135
136    @MediumTest
137    public void testAnalyticsTwoCalls() throws Exception {
138        IdPair testCall1 = startAndMakeActiveIncomingCall(
139                "650-555-1212",
140                mPhoneAccountA0.getAccountHandle(),
141                mConnectionServiceFixtureA);
142        IdPair testCall2 = startAndMakeActiveOutgoingCall(
143                "650-555-1213",
144                mPhoneAccountA0.getAccountHandle(),
145                mConnectionServiceFixtureA);
146
147        Map<String, Analytics.CallInfoImpl> analyticsMap = Analytics.cloneData();
148        assertTrue(analyticsMap.containsKey(testCall1.mCallId));
149        assertTrue(analyticsMap.containsKey(testCall2.mCallId));
150
151        Analytics.CallInfoImpl callAnalytics1 = analyticsMap.get(testCall1.mCallId);
152        Analytics.CallInfoImpl callAnalytics2 = analyticsMap.get(testCall2.mCallId);
153        assertTrue(callAnalytics1.startTime > 0);
154        assertTrue(callAnalytics2.startTime > 0);
155        assertEquals(0, callAnalytics1.endTime);
156        assertEquals(0, callAnalytics2.endTime);
157
158        assertEquals(Analytics.INCOMING_DIRECTION, callAnalytics1.callDirection);
159        assertEquals(Analytics.OUTGOING_DIRECTION, callAnalytics2.callDirection);
160
161        assertTrue(callAnalytics1.isInterrupted);
162        assertTrue(callAnalytics2.isAdditionalCall);
163
164        assertNull(callAnalytics1.callTerminationReason);
165        assertNull(callAnalytics2.callTerminationReason);
166
167        assertEquals(mConnectionServiceComponentNameA.flattenToShortString(),
168                callAnalytics1.connectionService);
169        assertEquals(mConnectionServiceComponentNameA.flattenToShortString(),
170                callAnalytics1.connectionService);
171
172        mConnectionServiceFixtureA.
173                sendSetDisconnected(testCall2.mConnectionId, DisconnectCause.REMOTE);
174        mConnectionServiceFixtureA.
175                sendSetDisconnected(testCall1.mConnectionId, DisconnectCause.ERROR);
176
177        analyticsMap = Analytics.cloneData();
178        callAnalytics1 = analyticsMap.get(testCall1.mCallId);
179        callAnalytics2 = analyticsMap.get(testCall2.mCallId);
180        assertTrue(callAnalytics1.endTime > 0);
181        assertTrue(callAnalytics2.endTime > 0);
182        assertNotNull(callAnalytics1.callTerminationReason);
183        assertNotNull(callAnalytics2.callTerminationReason);
184        assertEquals(DisconnectCause.ERROR, callAnalytics1.callTerminationReason.getCode());
185        assertEquals(DisconnectCause.REMOTE, callAnalytics2.callTerminationReason.getCode());
186    }
187
188    @MediumTest
189    public void testAnalyticsVideo() throws Exception {
190        Analytics.reset();
191        IdPair callIds = startAndMakeActiveOutgoingCall(
192                "650-555-1212",
193                mPhoneAccountA0.getAccountHandle(),
194                mConnectionServiceFixtureA);
195
196        CountDownLatch counter = new CountDownLatch(1);
197        InCallService.VideoCall.Callback callback = mock(InCallService.VideoCall.Callback.class);
198
199        doAnswer(invocation -> {
200            counter.countDown();
201            return null;
202        }).when(callback)
203                .onSessionModifyResponseReceived(anyInt(), any(VideoProfile.class),
204                        any(VideoProfile.class));
205
206        mConnectionServiceFixtureA.sendSetVideoProvider(
207                mConnectionServiceFixtureA.mLatestConnectionId);
208        InCallService.VideoCall videoCall =
209                mInCallServiceFixtureX.getCall(callIds.mCallId).getVideoCallImpl(
210                        mInCallServiceComponentNameX.getPackageName());
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    private void assertIsRoundedToOneSigFig(long x) {
343        assertEquals(x, Analytics.roundToOneSigFig(x));
344    }
345}
346