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