• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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 com.android.internal.telephony.TelephonyStatsLog.VOICE_CALL_SESSION__BEARER_AT_END__CALL_BEARER_CS;
20 import static com.android.internal.telephony.TelephonyStatsLog.VOICE_CALL_SESSION__BEARER_AT_END__CALL_BEARER_IMS;
21 import static com.android.internal.telephony.TelephonyStatsLog.VOICE_CALL_SESSION__DIRECTION__CALL_DIRECTION_MO;
22 import static com.android.internal.telephony.TelephonyStatsLog.VOICE_CALL_SESSION__DIRECTION__CALL_DIRECTION_MT;
23 import static com.android.internal.telephony.TelephonyStatsLog.VOICE_CALL_SESSION__SETUP_DURATION__CALL_SETUP_DURATION_EXTREMELY_FAST;
24 import static com.android.internal.telephony.TelephonyStatsLog.VOICE_CALL_SESSION__SETUP_DURATION__CALL_SETUP_DURATION_VERY_FAST;
25 import static com.android.internal.telephony.TelephonyStatsLog.VOICE_CALL_SESSION__SETUP_DURATION__CALL_SETUP_DURATION_VERY_SLOW;
26 
27 import static org.junit.Assert.assertEquals;
28 import static org.junit.Assert.assertNotNull;
29 import static org.junit.Assert.assertNull;
30 import static org.junit.Assert.assertTrue;
31 import static org.mockito.Mockito.anyInt;
32 import static org.mockito.Mockito.anyString;
33 import static org.mockito.Mockito.doReturn;
34 import static org.mockito.Mockito.eq;
35 import static org.mockito.Mockito.inOrder;
36 import static org.mockito.Mockito.times;
37 
38 import android.annotation.Nullable;
39 import android.content.Context;
40 import android.os.Build;
41 import android.telephony.DisconnectCause;
42 import android.telephony.ServiceState;
43 import android.telephony.TelephonyManager;
44 import android.telephony.ims.ImsReasonInfo;
45 import android.test.suitebuilder.annotation.SmallTest;
46 
47 import com.android.internal.telephony.TelephonyTest;
48 import com.android.internal.telephony.nano.PersistAtomsProto.CellularDataServiceSwitch;
49 import com.android.internal.telephony.nano.PersistAtomsProto.CellularServiceState;
50 import com.android.internal.telephony.nano.PersistAtomsProto.ImsRegistrationStats;
51 import com.android.internal.telephony.nano.PersistAtomsProto.ImsRegistrationTermination;
52 import com.android.internal.telephony.nano.PersistAtomsProto.PersistAtoms;
53 import com.android.internal.telephony.nano.PersistAtomsProto.VoiceCallRatUsage;
54 import com.android.internal.telephony.nano.PersistAtomsProto.VoiceCallSession;
55 import com.android.internal.telephony.nano.TelephonyProto.TelephonyCallSession.Event.AudioCodec;
56 import com.android.internal.telephony.protobuf.nano.MessageNano;
57 
58 import org.junit.After;
59 import org.junit.Before;
60 import org.junit.Rule;
61 import org.junit.Test;
62 import org.junit.rules.TemporaryFolder;
63 import org.mockito.ArgumentCaptor;
64 import org.mockito.InOrder;
65 import org.mockito.Mock;
66 
67 import java.io.File;
68 import java.io.FileOutputStream;
69 import java.nio.charset.StandardCharsets;
70 import java.util.Arrays;
71 import java.util.Comparator;
72 import java.util.LinkedList;
73 import java.util.Queue;
74 
75 public class PersistAtomsStorageTest extends TelephonyTest {
76     private static final String TEST_FILE = "PersistAtomsStorageTest.pb";
77     private static final int MAX_NUM_CALL_SESSIONS = 50;
78     private static final long START_TIME_MILLIS = 2000L;
79     private static final int CARRIER1_ID = 1;
80     private static final int CARRIER2_ID = 1187;
81     private static final int CARRIER3_ID = 1435;
82 
83     @Mock private FileOutputStream mTestFileOutputStream;
84 
85     @Rule public TemporaryFolder mFolder = new TemporaryFolder();
86 
87     private File mTestFile;
88 
89     // call with SRVCC
90     private VoiceCallSession mCall1Proto;
91 
92     // call held after another incoming call, ended before the other call
93     private VoiceCallSession mCall2Proto;
94     private VoiceCallSession mCall3Proto;
95 
96     // failed call
97     private VoiceCallSession mCall4Proto;
98 
99     private VoiceCallRatUsage mCarrier1LteUsageProto;
100     private VoiceCallRatUsage mCarrier1UmtsUsageProto;
101     private VoiceCallRatUsage mCarrier2LteUsageProto;
102     private VoiceCallRatUsage mCarrier3LteUsageProto;
103     private VoiceCallRatUsage mCarrier3GsmUsageProto;
104 
105     private VoiceCallSession[] mVoiceCallSessions;
106     private VoiceCallRatUsage[] mVoiceCallRatUsages;
107 
108     // data service state switch for slot 0 and 1
109     private CellularDataServiceSwitch mServiceSwitch1Proto;
110     private CellularDataServiceSwitch mServiceSwitch2Proto;
111 
112     // service states for slot 0 and 1
113     private CellularServiceState mServiceState1Proto;
114     private CellularServiceState mServiceState2Proto;
115     private CellularServiceState mServiceState3Proto;
116     private CellularServiceState mServiceState4Proto;
117 
118     private CellularDataServiceSwitch[] mServiceSwitches;
119     private CellularServiceState[] mServiceStates;
120 
121     // IMS registrations for slot 0 and 1
122     private ImsRegistrationStats mImsRegistrationStatsLte0;
123     private ImsRegistrationStats mImsRegistrationStatsWifi0;
124     private ImsRegistrationStats mImsRegistrationStatsLte1;
125 
126     // IMS registration terminations for slot 0 and 1
127     private ImsRegistrationTermination mImsRegistrationTerminationLte;
128     private ImsRegistrationTermination mImsRegistrationTerminationWifi;
129 
130     private ImsRegistrationStats[] mImsRegistrationStats;
131     private ImsRegistrationTermination[] mImsRegistrationTerminations;
132 
makeTestData()133     private void makeTestData() {
134         // MO call with SRVCC (LTE to UMTS)
135         mCall1Proto = new VoiceCallSession();
136         mCall1Proto.bearerAtStart = VOICE_CALL_SESSION__BEARER_AT_END__CALL_BEARER_IMS;
137         mCall1Proto.bearerAtEnd = VOICE_CALL_SESSION__BEARER_AT_END__CALL_BEARER_CS;
138         mCall1Proto.direction = VOICE_CALL_SESSION__DIRECTION__CALL_DIRECTION_MO;
139         mCall1Proto.setupDuration =
140                 VOICE_CALL_SESSION__SETUP_DURATION__CALL_SETUP_DURATION_VERY_FAST;
141         mCall1Proto.setupFailed = false;
142         mCall1Proto.disconnectReasonCode = DisconnectCause.LOCAL;
143         mCall1Proto.disconnectExtraCode = 0;
144         mCall1Proto.disconnectExtraMessage = "";
145         mCall1Proto.ratAtStart = TelephonyManager.NETWORK_TYPE_LTE;
146         mCall1Proto.ratAtEnd = TelephonyManager.NETWORK_TYPE_UMTS;
147         mCall1Proto.ratSwitchCount = 1L;
148         mCall1Proto.codecBitmask =
149                 (1 << AudioCodec.AUDIO_CODEC_EVS_SWB) | (1 << AudioCodec.AUDIO_CODEC_AMR);
150         mCall1Proto.concurrentCallCountAtStart = 0;
151         mCall1Proto.concurrentCallCountAtEnd = 0;
152         mCall1Proto.simSlotIndex = 0;
153         mCall1Proto.isMultiSim = false;
154         mCall1Proto.isEsim = false;
155         mCall1Proto.carrierId = CARRIER1_ID;
156         mCall1Proto.srvccCompleted = true;
157         mCall1Proto.srvccFailureCount = 0L;
158         mCall1Proto.srvccCancellationCount = 0L;
159         mCall1Proto.rttEnabled = false;
160         mCall1Proto.isEmergency = false;
161         mCall1Proto.isRoaming = false;
162 
163         // VoLTE MT call on DSDS/eSIM, hanged up by remote
164         // concurrent with mCall3Proto, started first and ended first
165         mCall2Proto = new VoiceCallSession();
166         mCall2Proto.bearerAtStart = VOICE_CALL_SESSION__BEARER_AT_END__CALL_BEARER_IMS;
167         mCall2Proto.bearerAtEnd = VOICE_CALL_SESSION__BEARER_AT_END__CALL_BEARER_IMS;
168         mCall2Proto.direction = VOICE_CALL_SESSION__DIRECTION__CALL_DIRECTION_MT;
169         mCall2Proto.setupDuration =
170                 VOICE_CALL_SESSION__SETUP_DURATION__CALL_SETUP_DURATION_VERY_FAST;
171         mCall2Proto.setupFailed = false;
172         mCall2Proto.disconnectReasonCode = ImsReasonInfo.CODE_USER_TERMINATED_BY_REMOTE;
173         mCall2Proto.disconnectExtraCode = 0;
174         mCall2Proto.disconnectExtraMessage = "normal call clearing";
175         mCall2Proto.ratAtStart = TelephonyManager.NETWORK_TYPE_LTE;
176         mCall2Proto.ratAtEnd = TelephonyManager.NETWORK_TYPE_LTE;
177         mCall2Proto.ratSwitchCount = 0L;
178         mCall2Proto.codecBitmask = (1 << AudioCodec.AUDIO_CODEC_EVS_SWB);
179         mCall2Proto.concurrentCallCountAtStart = 0;
180         mCall2Proto.concurrentCallCountAtEnd = 1;
181         mCall2Proto.simSlotIndex = 1;
182         mCall2Proto.isMultiSim = true;
183         mCall2Proto.isEsim = true;
184         mCall2Proto.carrierId = CARRIER2_ID;
185         mCall2Proto.srvccCompleted = false;
186         mCall2Proto.srvccFailureCount = 0L;
187         mCall2Proto.srvccCancellationCount = 0L;
188         mCall2Proto.rttEnabled = false;
189         mCall2Proto.isEmergency = false;
190         mCall2Proto.isRoaming = false;
191 
192         // VoLTE MT call on DSDS/eSIM, hanged up by local, with RTT
193         // concurrent with mCall2Proto, started last and ended last
194         mCall3Proto = new VoiceCallSession();
195         mCall3Proto.bearerAtStart = VOICE_CALL_SESSION__BEARER_AT_END__CALL_BEARER_IMS;
196         mCall3Proto.bearerAtEnd = VOICE_CALL_SESSION__BEARER_AT_END__CALL_BEARER_IMS;
197         mCall3Proto.direction = VOICE_CALL_SESSION__DIRECTION__CALL_DIRECTION_MT;
198         mCall3Proto.setupDuration =
199                 VOICE_CALL_SESSION__SETUP_DURATION__CALL_SETUP_DURATION_EXTREMELY_FAST;
200         mCall3Proto.setupFailed = false;
201         mCall3Proto.disconnectReasonCode = ImsReasonInfo.CODE_USER_TERMINATED;
202         mCall3Proto.disconnectExtraCode = 0;
203         mCall3Proto.disconnectExtraMessage = "normal call clearing";
204         mCall3Proto.ratAtStart = TelephonyManager.NETWORK_TYPE_LTE;
205         mCall3Proto.ratAtEnd = TelephonyManager.NETWORK_TYPE_LTE;
206         mCall3Proto.ratSwitchCount = 0L;
207         mCall3Proto.codecBitmask = (1 << AudioCodec.AUDIO_CODEC_EVS_SWB);
208         mCall3Proto.concurrentCallCountAtStart = 1;
209         mCall3Proto.concurrentCallCountAtEnd = 0;
210         mCall3Proto.simSlotIndex = 1;
211         mCall3Proto.isMultiSim = true;
212         mCall3Proto.isEsim = true;
213         mCall3Proto.carrierId = CARRIER2_ID;
214         mCall3Proto.srvccCompleted = false;
215         mCall3Proto.srvccFailureCount = 0L;
216         mCall3Proto.srvccCancellationCount = 0L;
217         mCall3Proto.rttEnabled = true;
218         mCall3Proto.isEmergency = false;
219         mCall3Proto.isRoaming = false;
220 
221         // CS MO call while camped on LTE
222         mCall4Proto = new VoiceCallSession();
223         mCall4Proto.bearerAtStart = VOICE_CALL_SESSION__BEARER_AT_END__CALL_BEARER_CS;
224         mCall4Proto.bearerAtEnd = VOICE_CALL_SESSION__BEARER_AT_END__CALL_BEARER_CS;
225         mCall4Proto.direction = VOICE_CALL_SESSION__DIRECTION__CALL_DIRECTION_MO;
226         mCall4Proto.setupDuration =
227                 VOICE_CALL_SESSION__SETUP_DURATION__CALL_SETUP_DURATION_VERY_SLOW;
228         mCall4Proto.setupFailed = true;
229         mCall4Proto.disconnectReasonCode = DisconnectCause.NORMAL;
230         mCall4Proto.disconnectExtraCode = 0;
231         mCall4Proto.disconnectExtraMessage = "";
232         mCall4Proto.ratAtStart = TelephonyManager.NETWORK_TYPE_LTE;
233         mCall4Proto.ratAtEnd = TelephonyManager.NETWORK_TYPE_GSM;
234         mCall4Proto.ratSwitchCount = 1L;
235         mCall4Proto.codecBitmask = (1 << AudioCodec.AUDIO_CODEC_AMR);
236         mCall4Proto.concurrentCallCountAtStart = 0;
237         mCall4Proto.concurrentCallCountAtEnd = 0;
238         mCall4Proto.simSlotIndex = 0;
239         mCall4Proto.isMultiSim = true;
240         mCall4Proto.isEsim = false;
241         mCall4Proto.carrierId = CARRIER3_ID;
242         mCall4Proto.srvccCompleted = false;
243         mCall4Proto.srvccFailureCount = 0L;
244         mCall4Proto.srvccCancellationCount = 0L;
245         mCall4Proto.rttEnabled = false;
246         mCall4Proto.isEmergency = false;
247         mCall4Proto.isRoaming = true;
248 
249         mCarrier1LteUsageProto = new VoiceCallRatUsage();
250         mCarrier1LteUsageProto.carrierId = CARRIER1_ID;
251         mCarrier1LteUsageProto.rat = TelephonyManager.NETWORK_TYPE_LTE;
252         mCarrier1LteUsageProto.callCount = 1L;
253         mCarrier1LteUsageProto.totalDurationMillis = 8000L;
254 
255         mCarrier1UmtsUsageProto = new VoiceCallRatUsage();
256         mCarrier1UmtsUsageProto.carrierId = CARRIER1_ID;
257         mCarrier1UmtsUsageProto.rat = TelephonyManager.NETWORK_TYPE_UMTS;
258         mCarrier1UmtsUsageProto.callCount = 1L;
259         mCarrier1UmtsUsageProto.totalDurationMillis = 6000L;
260 
261         mCarrier2LteUsageProto = new VoiceCallRatUsage();
262         mCarrier2LteUsageProto.carrierId = CARRIER2_ID;
263         mCarrier2LteUsageProto.rat = TelephonyManager.NETWORK_TYPE_LTE;
264         mCarrier2LteUsageProto.callCount = 2L;
265         mCarrier2LteUsageProto.totalDurationMillis = 20000L;
266 
267         mCarrier3LteUsageProto = new VoiceCallRatUsage();
268         mCarrier3LteUsageProto.carrierId = CARRIER3_ID;
269         mCarrier3LteUsageProto.rat = TelephonyManager.NETWORK_TYPE_LTE;
270         mCarrier3LteUsageProto.callCount = 1L;
271         mCarrier3LteUsageProto.totalDurationMillis = 1000L;
272 
273         mCarrier3GsmUsageProto = new VoiceCallRatUsage();
274         mCarrier3GsmUsageProto.carrierId = CARRIER3_ID;
275         mCarrier3GsmUsageProto.rat = TelephonyManager.NETWORK_TYPE_GSM;
276         mCarrier3GsmUsageProto.callCount = 1L;
277         mCarrier3GsmUsageProto.totalDurationMillis = 100000L;
278 
279         mVoiceCallRatUsages =
280                 new VoiceCallRatUsage[] {
281                     mCarrier1UmtsUsageProto,
282                     mCarrier1LteUsageProto,
283                     mCarrier2LteUsageProto,
284                     mCarrier3LteUsageProto,
285                     mCarrier3GsmUsageProto
286                 };
287         mVoiceCallSessions =
288                 new VoiceCallSession[] {mCall1Proto, mCall2Proto, mCall3Proto, mCall4Proto};
289 
290         // OOS to LTE on slot 0
291         mServiceSwitch1Proto = new CellularDataServiceSwitch();
292         mServiceSwitch1Proto.ratFrom = TelephonyManager.NETWORK_TYPE_UNKNOWN;
293         mServiceSwitch1Proto.ratTo = TelephonyManager.NETWORK_TYPE_LTE;
294         mServiceSwitch1Proto.simSlotIndex = 0;
295         mServiceSwitch1Proto.isMultiSim = true;
296         mServiceSwitch1Proto.carrierId = CARRIER1_ID;
297         mServiceSwitch1Proto.switchCount = 1;
298 
299         // LTE to UMTS on slot 1
300         mServiceSwitch2Proto = new CellularDataServiceSwitch();
301         mServiceSwitch2Proto.ratFrom = TelephonyManager.NETWORK_TYPE_LTE;
302         mServiceSwitch2Proto.ratTo = TelephonyManager.NETWORK_TYPE_UMTS;
303         mServiceSwitch2Proto.simSlotIndex = 0;
304         mServiceSwitch2Proto.isMultiSim = true;
305         mServiceSwitch2Proto.carrierId = CARRIER2_ID;
306         mServiceSwitch2Proto.switchCount = 2;
307 
308         // OOS on slot 0
309         mServiceState1Proto = new CellularServiceState();
310         mServiceState1Proto.voiceRat = TelephonyManager.NETWORK_TYPE_UNKNOWN;
311         mServiceState1Proto.dataRat = TelephonyManager.NETWORK_TYPE_UNKNOWN;
312         mServiceState1Proto.voiceRoamingType = ServiceState.ROAMING_TYPE_NOT_ROAMING;
313         mServiceState1Proto.dataRoamingType = ServiceState.ROAMING_TYPE_NOT_ROAMING;
314         mServiceState1Proto.isEndc = false;
315         mServiceState1Proto.simSlotIndex = 0;
316         mServiceState1Proto.isMultiSim = true;
317         mServiceState1Proto.carrierId = CARRIER1_ID;
318         mServiceState1Proto.totalTimeMillis = 5000L;
319 
320         // LTE with ENDC on slot 0
321         mServiceState2Proto = new CellularServiceState();
322         mServiceState2Proto.voiceRat = TelephonyManager.NETWORK_TYPE_LTE;
323         mServiceState2Proto.dataRat = TelephonyManager.NETWORK_TYPE_LTE;
324         mServiceState2Proto.voiceRoamingType = ServiceState.ROAMING_TYPE_NOT_ROAMING;
325         mServiceState2Proto.dataRoamingType = ServiceState.ROAMING_TYPE_NOT_ROAMING;
326         mServiceState2Proto.isEndc = true;
327         mServiceState2Proto.simSlotIndex = 0;
328         mServiceState2Proto.isMultiSim = true;
329         mServiceState2Proto.carrierId = CARRIER1_ID;
330         mServiceState2Proto.totalTimeMillis = 15000L;
331 
332         // LTE with WFC and roaming on slot 1
333         mServiceState3Proto = new CellularServiceState();
334         mServiceState3Proto.voiceRat = TelephonyManager.NETWORK_TYPE_IWLAN;
335         mServiceState3Proto.dataRat = TelephonyManager.NETWORK_TYPE_LTE;
336         mServiceState3Proto.voiceRoamingType = ServiceState.ROAMING_TYPE_INTERNATIONAL;
337         mServiceState3Proto.dataRoamingType = ServiceState.ROAMING_TYPE_INTERNATIONAL;
338         mServiceState3Proto.isEndc = false;
339         mServiceState3Proto.simSlotIndex = 1;
340         mServiceState3Proto.isMultiSim = true;
341         mServiceState3Proto.carrierId = CARRIER2_ID;
342         mServiceState3Proto.totalTimeMillis = 10000L;
343 
344         // UMTS with roaming on slot 1
345         mServiceState4Proto = new CellularServiceState();
346         mServiceState4Proto.voiceRat = TelephonyManager.NETWORK_TYPE_UMTS;
347         mServiceState4Proto.dataRat = TelephonyManager.NETWORK_TYPE_UMTS;
348         mServiceState4Proto.voiceRoamingType = ServiceState.ROAMING_TYPE_INTERNATIONAL;
349         mServiceState4Proto.dataRoamingType = ServiceState.ROAMING_TYPE_INTERNATIONAL;
350         mServiceState4Proto.isEndc = false;
351         mServiceState4Proto.simSlotIndex = 1;
352         mServiceState4Proto.isMultiSim = true;
353         mServiceState4Proto.carrierId = CARRIER2_ID;
354         mServiceState4Proto.totalTimeMillis = 10000L;
355 
356         mServiceSwitches =
357                 new CellularDataServiceSwitch[] {mServiceSwitch1Proto, mServiceSwitch2Proto};
358         mServiceStates =
359                 new CellularServiceState[] {
360                     mServiceState1Proto,
361                     mServiceState2Proto,
362                     mServiceState3Proto,
363                     mServiceState4Proto
364                 };
365 
366         // IMS over LTE on slot 0, registered for 5 seconds
367         mImsRegistrationStatsLte0 = new ImsRegistrationStats();
368         mImsRegistrationStatsLte0.carrierId = CARRIER1_ID;
369         mImsRegistrationStatsLte0.simSlotIndex = 0;
370         mImsRegistrationStatsLte0.rat = TelephonyManager.NETWORK_TYPE_LTE;
371         mImsRegistrationStatsLte0.registeredMillis = 5000L;
372         mImsRegistrationStatsLte0.voiceCapableMillis = 5000L;
373         mImsRegistrationStatsLte0.voiceAvailableMillis = 5000L;
374         mImsRegistrationStatsLte0.smsCapableMillis = 5000L;
375         mImsRegistrationStatsLte0.smsAvailableMillis = 5000L;
376         mImsRegistrationStatsLte0.videoCapableMillis = 5000L;
377         mImsRegistrationStatsLte0.videoAvailableMillis = 5000L;
378         mImsRegistrationStatsLte0.utCapableMillis = 5000L;
379         mImsRegistrationStatsLte0.utAvailableMillis = 5000L;
380 
381         // IMS over WiFi on slot 0, registered for 10 seconds (voice only)
382         mImsRegistrationStatsWifi0 = new ImsRegistrationStats();
383         mImsRegistrationStatsWifi0.carrierId = CARRIER2_ID;
384         mImsRegistrationStatsWifi0.simSlotIndex = 0;
385         mImsRegistrationStatsWifi0.rat = TelephonyManager.NETWORK_TYPE_IWLAN;
386         mImsRegistrationStatsWifi0.registeredMillis = 10000L;
387         mImsRegistrationStatsWifi0.voiceCapableMillis = 10000L;
388         mImsRegistrationStatsWifi0.voiceAvailableMillis = 10000L;
389 
390         // IMS over LTE on slot 1, registered for 20 seconds
391         mImsRegistrationStatsLte1 = new ImsRegistrationStats();
392         mImsRegistrationStatsLte1.carrierId = CARRIER1_ID;
393         mImsRegistrationStatsLte1.simSlotIndex = 0;
394         mImsRegistrationStatsLte1.rat = TelephonyManager.NETWORK_TYPE_LTE;
395         mImsRegistrationStatsLte1.registeredMillis = 20000L;
396         mImsRegistrationStatsLte1.voiceCapableMillis = 20000L;
397         mImsRegistrationStatsLte1.voiceAvailableMillis = 20000L;
398         mImsRegistrationStatsLte1.smsCapableMillis = 20000L;
399         mImsRegistrationStatsLte1.smsAvailableMillis = 20000L;
400         mImsRegistrationStatsLte1.videoCapableMillis = 20000L;
401         mImsRegistrationStatsLte1.videoAvailableMillis = 20000L;
402         mImsRegistrationStatsLte1.utCapableMillis = 20000L;
403         mImsRegistrationStatsLte1.utAvailableMillis = 20000L;
404 
405         // IMS terminations on LTE
406         mImsRegistrationTerminationLte = new ImsRegistrationTermination();
407         mImsRegistrationTerminationLte.carrierId = CARRIER1_ID;
408         mImsRegistrationTerminationLte.isMultiSim = true;
409         mImsRegistrationTerminationLte.ratAtEnd = TelephonyManager.NETWORK_TYPE_LTE;
410         mImsRegistrationTerminationLte.setupFailed = false;
411         mImsRegistrationTerminationLte.reasonCode = ImsReasonInfo.CODE_REGISTRATION_ERROR;
412         mImsRegistrationTerminationLte.extraCode = 999;
413         mImsRegistrationTerminationLte.extraMessage = "Request Timeout";
414         mImsRegistrationTerminationLte.count = 2;
415 
416         // IMS terminations on WiFi
417         mImsRegistrationTerminationWifi = new ImsRegistrationTermination();
418         mImsRegistrationTerminationWifi.carrierId = CARRIER2_ID;
419         mImsRegistrationTerminationWifi.isMultiSim = true;
420         mImsRegistrationTerminationWifi.ratAtEnd = TelephonyManager.NETWORK_TYPE_IWLAN;
421         mImsRegistrationTerminationWifi.setupFailed = false;
422         mImsRegistrationTerminationWifi.reasonCode = ImsReasonInfo.CODE_REGISTRATION_ERROR;
423         mImsRegistrationTerminationWifi.extraCode = 0;
424         mImsRegistrationTerminationWifi.extraMessage = "";
425         mImsRegistrationTerminationWifi.count = 1;
426 
427         mImsRegistrationStats =
428                 new ImsRegistrationStats[] {
429                     mImsRegistrationStatsLte0, mImsRegistrationStatsWifi0, mImsRegistrationStatsLte1
430                 };
431         mImsRegistrationTerminations =
432                 new ImsRegistrationTermination[] {
433                     mImsRegistrationTerminationLte, mImsRegistrationTerminationWifi
434                 };
435     }
436 
437     private static class TestablePersistAtomsStorage extends PersistAtomsStorage {
438         private long mTimeMillis = START_TIME_MILLIS;
439 
TestablePersistAtomsStorage(Context context)440         TestablePersistAtomsStorage(Context context) {
441             super(context);
442             // Remove delay for saving to persistent storage during tests.
443             mSaveImmediately = true;
444         }
445 
446         @Override
getWallTimeMillis()447         protected long getWallTimeMillis() {
448             // NOTE: super class constructor will be executed before private field is set, which
449             // gives the wrong start time (mTimeMillis will have its default value of 0L)
450             return mTimeMillis == 0L ? START_TIME_MILLIS : mTimeMillis;
451         }
452 
setTimeMillis(long timeMillis)453         private void setTimeMillis(long timeMillis) {
454             mTimeMillis = timeMillis;
455         }
456 
incTimeMillis(long timeMillis)457         private void incTimeMillis(long timeMillis) {
458             mTimeMillis += timeMillis;
459         }
460 
getAtomsProto()461         private PersistAtoms getAtomsProto() {
462             // NOTE: unlike other methods in PersistAtomsStorage, this is not synchronized, but
463             // should be fine since the test is single-threaded
464             return mAtoms;
465         }
466     }
467 
468     private TestablePersistAtomsStorage mPersistAtomsStorage;
469 
470     private static final Comparator<MessageNano> sProtoComparator =
471             new Comparator<>() {
472                 @Override
473                 public int compare(MessageNano o1, MessageNano o2) {
474                     if (o1 == o2) {
475                         return 0;
476                     }
477                     if (o1 == null) {
478                         return -1;
479                     }
480                     if (o2 == null) {
481                         return 1;
482                     }
483                     assertEquals(o1.getClass(), o2.getClass());
484                     return o1.toString().compareTo(o2.toString());
485                 }
486             };
487 
488     @Before
setUp()489     public void setUp() throws Exception {
490         super.setUp(getClass().getSimpleName());
491         makeTestData();
492 
493         // by default, test loading with real file IO and saving with mocks
494         mTestFile = mFolder.newFile(TEST_FILE);
495         doReturn(mTestFileOutputStream).when(mContext).openFileOutput(anyString(), anyInt());
496         doReturn(mTestFile).when(mContext).getFileStreamPath(anyString());
497     }
498 
499     @After
tearDown()500     public void tearDown() throws Exception {
501         mTestFile.delete();
502         super.tearDown();
503     }
504 
505     @Test
506     @SmallTest
loadAtoms_fileNotExist()507     public void loadAtoms_fileNotExist() throws Exception {
508         mTestFile.delete();
509 
510         mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
511         mPersistAtomsStorage.incTimeMillis(100L);
512 
513         // no exception should be thrown, storage should be empty, pull time should be start time
514         assertAllPullTimestampEquals(START_TIME_MILLIS);
515         assertStorageIsEmptyForAllAtoms();
516     }
517 
518     @Test
519     @SmallTest
loadAtoms_unreadable()520     public void loadAtoms_unreadable() throws Exception {
521         createEmptyTestFile();
522         mTestFile.setReadable(false);
523 
524         mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
525         mPersistAtomsStorage.incTimeMillis(100L);
526 
527         // no exception should be thrown, storage should be empty, pull time should be start time
528         assertAllPullTimestampEquals(START_TIME_MILLIS);
529         assertStorageIsEmptyForAllAtoms();
530     }
531 
532     @Test
533     @SmallTest
loadAtoms_emptyProto()534     public void loadAtoms_emptyProto() throws Exception {
535         createEmptyTestFile();
536 
537         mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
538         mPersistAtomsStorage.incTimeMillis(100L);
539 
540         // no exception should be thrown, storage should be empty, pull time should be start time
541         assertAllPullTimestampEquals(START_TIME_MILLIS);
542         assertStorageIsEmptyForAllAtoms();
543     }
544 
545     @Test
546     @SmallTest
loadAtoms_malformedFile()547     public void loadAtoms_malformedFile() throws Exception {
548         FileOutputStream stream = new FileOutputStream(mTestFile);
549         stream.write("This is not a proto file.".getBytes(StandardCharsets.UTF_8));
550         stream.close();
551 
552         mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
553         mPersistAtomsStorage.incTimeMillis(100L);
554 
555         // no exception should be thrown, storage should be empty, pull time should be start time
556         assertAllPullTimestampEquals(START_TIME_MILLIS);
557         assertStorageIsEmptyForAllAtoms();
558     }
559 
560     @Test
561     @SmallTest
loadAtoms_pullTimeMissing()562     public void loadAtoms_pullTimeMissing() throws Exception {
563         // create test file with lastPullTimeMillis = 0L, i.e. default/unknown
564         createTestFile(0L);
565 
566         mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
567         mPersistAtomsStorage.incTimeMillis(100L);
568 
569         // no exception should be thrown, storage should be match, pull time should be start time
570         assertAllPullTimestampEquals(START_TIME_MILLIS);
571         assertProtoArrayEquals(mVoiceCallRatUsages, mPersistAtomsStorage.getVoiceCallRatUsages(0L));
572         assertProtoArrayEquals(mVoiceCallSessions, mPersistAtomsStorage.getVoiceCallSessions(0L));
573         assertProtoArrayEqualsIgnoringOrder(
574                 mServiceStates, mPersistAtomsStorage.getCellularServiceStates(0L));
575         assertProtoArrayEqualsIgnoringOrder(
576                 mServiceSwitches, mPersistAtomsStorage.getCellularDataServiceSwitches(0L));
577     }
578 
579     @Test
580     @SmallTest
loadAtoms_validContents()581     public void loadAtoms_validContents() throws Exception {
582         createTestFile(/* lastPullTimeMillis= */ 100L);
583 
584         mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
585 
586         // no exception should be thrown, storage and pull time should match
587         assertAllPullTimestampEquals(100L);
588         assertProtoArrayEquals(mVoiceCallRatUsages, mPersistAtomsStorage.getVoiceCallRatUsages(0L));
589         assertProtoArrayEquals(mVoiceCallSessions, mPersistAtomsStorage.getVoiceCallSessions(0L));
590         assertProtoArrayEqualsIgnoringOrder(
591                 mServiceStates, mPersistAtomsStorage.getCellularServiceStates(0L));
592         assertProtoArrayEqualsIgnoringOrder(
593                 mServiceSwitches, mPersistAtomsStorage.getCellularDataServiceSwitches(0L));
594     }
595 
596     @Test
597     @SmallTest
addVoiceCallSession_emptyProto()598     public void addVoiceCallSession_emptyProto() throws Exception {
599         createEmptyTestFile();
600 
601         mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
602         mPersistAtomsStorage.addVoiceCallSession(mCall1Proto);
603         mPersistAtomsStorage.incTimeMillis(100L);
604 
605         // call should be added successfully, there should be no RAT usage, changes should be saved
606         verifyCurrentStateSavedToFileOnce();
607         assertProtoArrayIsEmpty(mPersistAtomsStorage.getVoiceCallRatUsages(0L));
608         VoiceCallSession[] voiceCallSession = mPersistAtomsStorage.getVoiceCallSessions(0L);
609         assertProtoArrayEquals(new VoiceCallSession[] {mCall1Proto}, voiceCallSession);
610     }
611 
612     @Test
613     @SmallTest
addVoiceCallSession_withExistingCalls()614     public void addVoiceCallSession_withExistingCalls() throws Exception {
615         createTestFile(START_TIME_MILLIS);
616 
617         mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
618         mPersistAtomsStorage.addVoiceCallSession(mCall1Proto);
619         mPersistAtomsStorage.incTimeMillis(100L);
620 
621         // call should be added successfully, RAT usages should not change, changes should be saved
622         assertProtoArrayEquals(mVoiceCallRatUsages, mPersistAtomsStorage.getVoiceCallRatUsages(0L));
623         VoiceCallSession[] expectedVoiceCallSessions =
624                 new VoiceCallSession[] {
625                     mCall1Proto, mCall1Proto, mCall2Proto, mCall3Proto, mCall4Proto
626                 };
627         // call list is randomized at this point
628         verifyCurrentStateSavedToFileOnce();
629         assertProtoArrayEqualsIgnoringOrder(
630                 expectedVoiceCallSessions, mPersistAtomsStorage.getVoiceCallSessions(0L));
631     }
632 
633     @Test
634     @SmallTest
addVoiceCallSession_tooManyCalls()635     public void addVoiceCallSession_tooManyCalls() throws Exception {
636         createEmptyTestFile();
637 
638         mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
639         addRepeatedCalls(mPersistAtomsStorage, mCall1Proto, 50);
640         mPersistAtomsStorage.addVoiceCallSession(mCall2Proto);
641         mPersistAtomsStorage.incTimeMillis(100L);
642 
643         // one previous call should be evicted, the new call should be added
644         verifyCurrentStateSavedToFileOnce();
645         VoiceCallSession[] calls = mPersistAtomsStorage.getVoiceCallSessions(0L);
646         assertHasCall(calls, mCall1Proto, /* expectedCount= */ 49);
647         assertHasCall(calls, mCall2Proto, /* expectedCount= */ 1);
648     }
649 
650     @Test
651     @SmallTest
addVoiceCallRatUsage_emptyProto()652     public void addVoiceCallRatUsage_emptyProto() throws Exception {
653         createEmptyTestFile();
654         VoiceCallRatTracker ratTracker = VoiceCallRatTracker.fromProto(mVoiceCallRatUsages);
655 
656         mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
657         mPersistAtomsStorage.addVoiceCallRatUsage(ratTracker);
658         mPersistAtomsStorage.incTimeMillis(100L);
659 
660         // RAT should be added successfully, calls should not change, changes should be saved
661         verifyCurrentStateSavedToFileOnce();
662         assertProtoArrayEqualsIgnoringOrder(
663                 mVoiceCallRatUsages, mPersistAtomsStorage.getVoiceCallRatUsages(0L));
664         assertProtoArrayIsEmpty(mPersistAtomsStorage.getVoiceCallSessions(0L));
665     }
666 
667     @Test
668     @SmallTest
addVoiceCallRatUsage_withExistingUsages()669     public void addVoiceCallRatUsage_withExistingUsages() throws Exception {
670         createTestFile(START_TIME_MILLIS);
671         VoiceCallRatTracker ratTracker = VoiceCallRatTracker.fromProto(mVoiceCallRatUsages);
672 
673         mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
674         mPersistAtomsStorage.addVoiceCallRatUsage(ratTracker);
675         mPersistAtomsStorage.incTimeMillis(100L);
676 
677         // RAT should be added successfully, calls should not change, changes should be saved
678         // call count and duration should become doubled since mVoiceCallRatUsages applied through
679         // both file and addVoiceCallRatUsage()
680         verifyCurrentStateSavedToFileOnce();
681         VoiceCallRatUsage[] expectedVoiceCallRatUsage =
682                 multiplyVoiceCallRatUsage(mVoiceCallRatUsages, 2);
683         assertProtoArrayEqualsIgnoringOrder(
684                 expectedVoiceCallRatUsage, mPersistAtomsStorage.getVoiceCallRatUsages(0L));
685         assertProtoArrayEquals(mVoiceCallSessions, mPersistAtomsStorage.getVoiceCallSessions(0L));
686     }
687 
688     @Test
689     @SmallTest
addVoiceCallRatUsage_empty()690     public void addVoiceCallRatUsage_empty() throws Exception {
691         createEmptyTestFile();
692         VoiceCallRatTracker ratTracker = VoiceCallRatTracker.fromProto(new VoiceCallRatUsage[0]);
693 
694         mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
695         mPersistAtomsStorage.addVoiceCallRatUsage(ratTracker);
696         mPersistAtomsStorage.incTimeMillis(100L);
697 
698         // RAT should be added successfully, calls should not change
699         // in this case saving is unnecessarily
700         assertProtoArrayIsEmpty(mPersistAtomsStorage.getVoiceCallRatUsages(0L));
701         assertProtoArrayIsEmpty(mPersistAtomsStorage.getVoiceCallSessions(0L));
702     }
703 
704     @Test
705     @SmallTest
getVoiceCallRatUsages_tooFrequent()706     public void getVoiceCallRatUsages_tooFrequent() throws Exception {
707         createTestFile(START_TIME_MILLIS);
708 
709         mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
710         mPersistAtomsStorage.incTimeMillis(50L); // pull interval less than minimum
711         VoiceCallRatUsage[] voiceCallRatUsage = mPersistAtomsStorage.getVoiceCallRatUsages(100L);
712 
713         // should be denied
714         assertNull(voiceCallRatUsage);
715     }
716 
717     @Test
718     @SmallTest
getVoiceCallRatUsages_withSavedAtoms()719     public void getVoiceCallRatUsages_withSavedAtoms() throws Exception {
720         createTestFile(START_TIME_MILLIS);
721 
722         mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
723         mPersistAtomsStorage.incTimeMillis(100L);
724         VoiceCallRatUsage[] voiceCallRatUsage1 = mPersistAtomsStorage.getVoiceCallRatUsages(50L);
725         mPersistAtomsStorage.incTimeMillis(100L);
726         VoiceCallRatUsage[] voiceCallRatUsage2 = mPersistAtomsStorage.getVoiceCallRatUsages(50L);
727         long voiceCallSessionPullTimestampMillis =
728                 mPersistAtomsStorage.getAtomsProto().voiceCallSessionPullTimestampMillis;
729         VoiceCallSession[] voiceCallSession = mPersistAtomsStorage.getVoiceCallSessions(50L);
730 
731         // first set of results should equal to file contents, second should be empty, corresponding
732         // pull timestamp should be updated and saved, other fields should be unaffected
733         assertProtoArrayEquals(mVoiceCallRatUsages, voiceCallRatUsage1);
734         assertProtoArrayIsEmpty(voiceCallRatUsage2);
735         assertEquals(
736                 START_TIME_MILLIS + 200L,
737                 mPersistAtomsStorage.getAtomsProto().voiceCallRatUsagePullTimestampMillis);
738         assertProtoArrayEquals(mVoiceCallSessions, voiceCallSession);
739         assertEquals(START_TIME_MILLIS, voiceCallSessionPullTimestampMillis);
740         InOrder inOrder = inOrder(mTestFileOutputStream);
741         assertEquals(
742                 START_TIME_MILLIS + 100L,
743                 getAtomsWritten(inOrder).voiceCallRatUsagePullTimestampMillis);
744         assertEquals(
745                 START_TIME_MILLIS + 200L,
746                 getAtomsWritten(inOrder).voiceCallRatUsagePullTimestampMillis);
747         assertEquals(
748                 START_TIME_MILLIS + 200L,
749                 getAtomsWritten(inOrder).voiceCallSessionPullTimestampMillis);
750         inOrder.verifyNoMoreInteractions();
751     }
752 
753     @Test
754     @SmallTest
getVoiceCallSessions_tooFrequent()755     public void getVoiceCallSessions_tooFrequent() throws Exception {
756         createTestFile(START_TIME_MILLIS);
757 
758         mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
759         mPersistAtomsStorage.incTimeMillis(50L); // pull interval less than minimum
760         VoiceCallSession[] voiceCallSession = mPersistAtomsStorage.getVoiceCallSessions(100L);
761 
762         // should be denied
763         assertNull(voiceCallSession);
764     }
765 
766     @Test
767     @SmallTest
getVoiceCallSessions_withSavedAtoms()768     public void getVoiceCallSessions_withSavedAtoms() throws Exception {
769         createTestFile(START_TIME_MILLIS);
770 
771         mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
772         mPersistAtomsStorage.incTimeMillis(100L);
773         VoiceCallSession[] voiceCallSession1 = mPersistAtomsStorage.getVoiceCallSessions(50L);
774         mPersistAtomsStorage.incTimeMillis(100L);
775         VoiceCallSession[] voiceCallSession2 = mPersistAtomsStorage.getVoiceCallSessions(50L);
776         long voiceCallRatUsagePullTimestampMillis =
777                 mPersistAtomsStorage.getAtomsProto().voiceCallRatUsagePullTimestampMillis;
778         VoiceCallRatUsage[] voiceCallRatUsage = mPersistAtomsStorage.getVoiceCallRatUsages(50L);
779 
780         // first set of results should equal to file contents, second should be empty, corresponding
781         // pull timestamp should be updated and saved, other fields should be unaffected
782         assertProtoArrayEquals(mVoiceCallSessions, voiceCallSession1);
783         assertProtoArrayIsEmpty(voiceCallSession2);
784         assertEquals(
785                 START_TIME_MILLIS + 200L,
786                 mPersistAtomsStorage.getAtomsProto().voiceCallSessionPullTimestampMillis);
787         assertProtoArrayEquals(mVoiceCallRatUsages, voiceCallRatUsage);
788         assertEquals(START_TIME_MILLIS, voiceCallRatUsagePullTimestampMillis);
789         InOrder inOrder = inOrder(mTestFileOutputStream);
790         assertEquals(
791                 START_TIME_MILLIS + 100L,
792                 getAtomsWritten(inOrder).voiceCallSessionPullTimestampMillis);
793         assertEquals(
794                 START_TIME_MILLIS + 200L,
795                 getAtomsWritten(inOrder).voiceCallSessionPullTimestampMillis);
796         assertEquals(
797                 START_TIME_MILLIS + 200L,
798                 getAtomsWritten(inOrder).voiceCallRatUsagePullTimestampMillis);
799         inOrder.verifyNoMoreInteractions();
800     }
801 
802     @Test
803     @SmallTest
addCellularServiceStateAndCellularDataServiceSwitch_emptyProto()804     public void addCellularServiceStateAndCellularDataServiceSwitch_emptyProto() throws Exception {
805         createEmptyTestFile();
806 
807         mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
808         mPersistAtomsStorage.addCellularServiceStateAndCellularDataServiceSwitch(
809                 mServiceState1Proto, mServiceSwitch1Proto);
810         mPersistAtomsStorage.incTimeMillis(100L);
811 
812         // service state and service switch should be added successfully
813         verifyCurrentStateSavedToFileOnce();
814         CellularServiceState[] serviceStates = mPersistAtomsStorage.getCellularServiceStates(0L);
815         CellularDataServiceSwitch[] serviceSwitches =
816                 mPersistAtomsStorage.getCellularDataServiceSwitches(0L);
817         assertProtoArrayEquals(new CellularServiceState[] {mServiceState1Proto}, serviceStates);
818         assertProtoArrayEquals(
819                 new CellularDataServiceSwitch[] {mServiceSwitch1Proto}, serviceSwitches);
820     }
821 
822     @Test
823     @SmallTest
addCellularServiceStateAndCellularDataServiceSwitch_withExistingEntries()824     public void addCellularServiceStateAndCellularDataServiceSwitch_withExistingEntries()
825             throws Exception {
826         createEmptyTestFile();
827         mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
828         mPersistAtomsStorage.addCellularServiceStateAndCellularDataServiceSwitch(
829                 mServiceState1Proto, mServiceSwitch1Proto);
830 
831         mPersistAtomsStorage.addCellularServiceStateAndCellularDataServiceSwitch(
832                 mServiceState2Proto, mServiceSwitch2Proto);
833         mPersistAtomsStorage.incTimeMillis(100L);
834 
835         // service state and service switch should be added successfully
836         verifyCurrentStateSavedToFileOnce();
837         CellularServiceState[] serviceStates = mPersistAtomsStorage.getCellularServiceStates(0L);
838         CellularDataServiceSwitch[] serviceSwitches =
839                 mPersistAtomsStorage.getCellularDataServiceSwitches(0L);
840         assertProtoArrayEqualsIgnoringOrder(
841                 new CellularServiceState[] {mServiceState1Proto, mServiceState2Proto},
842                 serviceStates);
843         assertProtoArrayEqualsIgnoringOrder(
844                 new CellularDataServiceSwitch[] {mServiceSwitch1Proto, mServiceSwitch2Proto},
845                 serviceSwitches);
846     }
847 
848     @Test
849     @SmallTest
addCellularServiceStateAndCellularDataServiceSwitch_updateExistingEntries()850     public void addCellularServiceStateAndCellularDataServiceSwitch_updateExistingEntries()
851             throws Exception {
852         createTestFile(START_TIME_MILLIS);
853         CellularServiceState newServiceState1Proto = copyOf(mServiceState1Proto);
854         CellularDataServiceSwitch newServiceSwitch1Proto = copyOf(mServiceSwitch1Proto);
855         mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
856 
857         mPersistAtomsStorage.addCellularServiceStateAndCellularDataServiceSwitch(
858                 copyOf(mServiceState1Proto), copyOf(mServiceSwitch1Proto));
859         mPersistAtomsStorage.incTimeMillis(100L);
860 
861         // mServiceState1Proto's duration and mServiceSwitch1Proto's switch should be doubled
862         verifyCurrentStateSavedToFileOnce();
863         CellularServiceState[] serviceStates = mPersistAtomsStorage.getCellularServiceStates(0L);
864         newServiceState1Proto.totalTimeMillis *= 2;
865         assertProtoArrayEqualsIgnoringOrder(
866                 new CellularServiceState[] {
867                     newServiceState1Proto,
868                     mServiceState2Proto,
869                     mServiceState3Proto,
870                     mServiceState4Proto
871                 },
872                 serviceStates);
873         CellularDataServiceSwitch[] serviceSwitches =
874                 mPersistAtomsStorage.getCellularDataServiceSwitches(0L);
875         newServiceSwitch1Proto.switchCount *= 2;
876         assertProtoArrayEqualsIgnoringOrder(
877                 new CellularDataServiceSwitch[] {newServiceSwitch1Proto, mServiceSwitch2Proto},
878                 serviceSwitches);
879     }
880 
881     @Test
882     @SmallTest
addCellularServiceStateAndCellularDataServiceSwitch_tooManyServiceStates()883     public void addCellularServiceStateAndCellularDataServiceSwitch_tooManyServiceStates()
884             throws Exception {
885         createEmptyTestFile();
886         mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
887         Queue<CellularServiceState> expectedServiceStates = new LinkedList<>();
888         Queue<CellularDataServiceSwitch> expectedServiceSwitches = new LinkedList<>();
889 
890         // Add 51 service states, with the first being least recent
891         for (int i = 0; i < 51; i++) {
892             CellularServiceState state = new CellularServiceState();
893             state.voiceRat = i / 10;
894             state.dataRat = i % 10;
895             expectedServiceStates.add(state);
896             CellularDataServiceSwitch serviceSwitch = new CellularDataServiceSwitch();
897             serviceSwitch.ratFrom = i / 10;
898             serviceSwitch.ratTo = i % 10;
899             expectedServiceSwitches.add(serviceSwitch);
900             mPersistAtomsStorage.addCellularServiceStateAndCellularDataServiceSwitch(
901                     copyOf(state), copyOf(serviceSwitch));
902             mPersistAtomsStorage.incTimeMillis(100L);
903         }
904 
905         // The least recent (the first) service state should be evicted
906         verifyCurrentStateSavedToFileOnce();
907         CellularServiceState[] serviceStates = mPersistAtomsStorage.getCellularServiceStates(0L);
908         expectedServiceStates.remove();
909         assertProtoArrayEqualsIgnoringOrder(
910                 expectedServiceStates.toArray(new CellularServiceState[0]), serviceStates);
911         CellularDataServiceSwitch[] serviceSwitches =
912                 mPersistAtomsStorage.getCellularDataServiceSwitches(0L);
913         expectedServiceSwitches.remove();
914         assertProtoArrayEqualsIgnoringOrder(
915                 expectedServiceSwitches.toArray(new CellularDataServiceSwitch[0]), serviceSwitches);
916     }
917 
918     @Test
919     @SmallTest
getCellularDataServiceSwitches_tooFrequent()920     public void getCellularDataServiceSwitches_tooFrequent() throws Exception {
921         createTestFile(START_TIME_MILLIS);
922 
923         mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
924         mPersistAtomsStorage.incTimeMillis(50L); // pull interval less than minimum
925         CellularDataServiceSwitch[] serviceSwitches =
926                 mPersistAtomsStorage.getCellularDataServiceSwitches(100L);
927 
928         // should be denied
929         assertNull(serviceSwitches);
930     }
931 
932     @Test
933     @SmallTest
getCellularDataServiceSwitches_withSavedAtoms()934     public void getCellularDataServiceSwitches_withSavedAtoms() throws Exception {
935         createTestFile(START_TIME_MILLIS);
936 
937         mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
938         mPersistAtomsStorage.incTimeMillis(100L);
939         CellularDataServiceSwitch[] serviceSwitches1 =
940                 mPersistAtomsStorage.getCellularDataServiceSwitches(50L);
941         mPersistAtomsStorage.incTimeMillis(100L);
942         CellularDataServiceSwitch[] serviceSwitches2 =
943                 mPersistAtomsStorage.getCellularDataServiceSwitches(50L);
944 
945         // first set of results should equal to file contents, second should be empty, corresponding
946         // pull timestamp should be updated and saved
947         assertProtoArrayEqualsIgnoringOrder(
948                 new CellularDataServiceSwitch[] {mServiceSwitch1Proto, mServiceSwitch2Proto},
949                 serviceSwitches1);
950         assertProtoArrayEquals(new CellularDataServiceSwitch[0], serviceSwitches2);
951         assertEquals(
952                 START_TIME_MILLIS + 200L,
953                 mPersistAtomsStorage.getAtomsProto().cellularDataServiceSwitchPullTimestampMillis);
954         InOrder inOrder = inOrder(mTestFileOutputStream);
955         assertEquals(
956                 START_TIME_MILLIS + 100L,
957                 getAtomsWritten(inOrder).cellularDataServiceSwitchPullTimestampMillis);
958         assertEquals(
959                 START_TIME_MILLIS + 200L,
960                 getAtomsWritten(inOrder).cellularDataServiceSwitchPullTimestampMillis);
961         inOrder.verifyNoMoreInteractions();
962     }
963 
964     @Test
965     @SmallTest
getCellularServiceStates_tooFrequent()966     public void getCellularServiceStates_tooFrequent() throws Exception {
967         createTestFile(START_TIME_MILLIS);
968 
969         mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
970         mPersistAtomsStorage.incTimeMillis(50L); // pull interval less than minimum
971         CellularServiceState[] serviceStates = mPersistAtomsStorage.getCellularServiceStates(100L);
972 
973         // should be denied
974         assertNull(serviceStates);
975     }
976 
977     @Test
978     @SmallTest
getCellularServiceStates_withSavedAtoms()979     public void getCellularServiceStates_withSavedAtoms() throws Exception {
980         createTestFile(START_TIME_MILLIS);
981 
982         mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
983         mPersistAtomsStorage.incTimeMillis(100L);
984         CellularServiceState[] serviceStates1 = mPersistAtomsStorage.getCellularServiceStates(50L);
985         mPersistAtomsStorage.incTimeMillis(100L);
986         CellularServiceState[] serviceStates2 = mPersistAtomsStorage.getCellularServiceStates(50L);
987 
988         // first set of results should equal to file contents, second should be empty, corresponding
989         // pull timestamp should be updated and saved
990         assertProtoArrayEqualsIgnoringOrder(
991                 new CellularServiceState[] {
992                     mServiceState1Proto,
993                     mServiceState2Proto,
994                     mServiceState3Proto,
995                     mServiceState4Proto
996                 },
997                 serviceStates1);
998         assertProtoArrayEquals(new CellularServiceState[0], serviceStates2);
999         assertEquals(
1000                 START_TIME_MILLIS + 200L,
1001                 mPersistAtomsStorage.getAtomsProto().cellularServiceStatePullTimestampMillis);
1002         InOrder inOrder = inOrder(mTestFileOutputStream);
1003         assertEquals(
1004                 START_TIME_MILLIS + 100L,
1005                 getAtomsWritten(inOrder).cellularServiceStatePullTimestampMillis);
1006         assertEquals(
1007                 START_TIME_MILLIS + 200L,
1008                 getAtomsWritten(inOrder).cellularServiceStatePullTimestampMillis);
1009         inOrder.verifyNoMoreInteractions();
1010     }
1011 
1012     @Test
1013     @SmallTest
addImsRegistrationStats_emptyProto()1014     public void addImsRegistrationStats_emptyProto() throws Exception {
1015         createEmptyTestFile();
1016 
1017         mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
1018         mPersistAtomsStorage.addImsRegistrationStats(mImsRegistrationStatsLte0);
1019         mPersistAtomsStorage.incTimeMillis(100L);
1020 
1021         // service state and service switch should be added successfully
1022         verifyCurrentStateSavedToFileOnce();
1023         ImsRegistrationStats[] regStats = mPersistAtomsStorage.getImsRegistrationStats(0L);
1024         assertProtoArrayEquals(new ImsRegistrationStats[] {mImsRegistrationStatsLte0}, regStats);
1025     }
1026 
1027     @Test
1028     @SmallTest
addImsRegistrationStats_withExistingEntries()1029     public void addImsRegistrationStats_withExistingEntries() throws Exception {
1030         createEmptyTestFile();
1031         mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
1032         mPersistAtomsStorage.addImsRegistrationStats(mImsRegistrationStatsLte0);
1033 
1034         mPersistAtomsStorage.addImsRegistrationStats(mImsRegistrationStatsWifi0);
1035         mPersistAtomsStorage.incTimeMillis(100L);
1036 
1037         // service state and service switch should be added successfully
1038         verifyCurrentStateSavedToFileOnce();
1039         ImsRegistrationStats[] regStats = mPersistAtomsStorage.getImsRegistrationStats(0L);
1040         assertProtoArrayEqualsIgnoringOrder(
1041                 new ImsRegistrationStats[] {mImsRegistrationStatsLte0, mImsRegistrationStatsWifi0},
1042                 regStats);
1043     }
1044 
1045     @Test
1046     @SmallTest
addImsRegistrationStats_updateExistingEntries()1047     public void addImsRegistrationStats_updateExistingEntries() throws Exception {
1048         createTestFile(START_TIME_MILLIS);
1049         ImsRegistrationStats newImsRegistrationStatsLte0 = copyOf(mImsRegistrationStatsLte0);
1050         mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
1051 
1052         mPersistAtomsStorage.addImsRegistrationStats(copyOf(mImsRegistrationStatsLte0));
1053         mPersistAtomsStorage.incTimeMillis(100L);
1054 
1055         // mImsRegistrationStatsLte0's durations should be doubled
1056         verifyCurrentStateSavedToFileOnce();
1057         ImsRegistrationStats[] serviceStates = mPersistAtomsStorage.getImsRegistrationStats(0L);
1058         newImsRegistrationStatsLte0.registeredMillis *= 2;
1059         newImsRegistrationStatsLte0.voiceCapableMillis *= 2;
1060         newImsRegistrationStatsLte0.voiceAvailableMillis *= 2;
1061         newImsRegistrationStatsLte0.smsCapableMillis *= 2;
1062         newImsRegistrationStatsLte0.smsAvailableMillis *= 2;
1063         newImsRegistrationStatsLte0.videoCapableMillis *= 2;
1064         newImsRegistrationStatsLte0.videoAvailableMillis *= 2;
1065         newImsRegistrationStatsLte0.utCapableMillis *= 2;
1066         newImsRegistrationStatsLte0.utAvailableMillis *= 2;
1067         assertProtoArrayEqualsIgnoringOrder(
1068                 new ImsRegistrationStats[] {
1069                     newImsRegistrationStatsLte0,
1070                     mImsRegistrationStatsWifi0,
1071                     mImsRegistrationStatsLte1
1072                 },
1073                 serviceStates);
1074     }
1075 
1076     @Test
1077     @SmallTest
addImsRegistrationStats_tooManyRegistrationStats()1078     public void addImsRegistrationStats_tooManyRegistrationStats() throws Exception {
1079         createEmptyTestFile();
1080         mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
1081         Queue<ImsRegistrationStats> expectedRegistrationStats = new LinkedList<>();
1082 
1083         // Add 11 registration stats
1084         for (int i = 0; i < 11; i++) {
1085             ImsRegistrationStats stats = copyOf(mImsRegistrationStatsLte0);
1086             stats.rat = i;
1087             expectedRegistrationStats.add(stats);
1088             mPersistAtomsStorage.addImsRegistrationStats(stats);
1089             mPersistAtomsStorage.incTimeMillis(100L);
1090         }
1091 
1092         // The least recent (the first) registration stats should be evicted
1093         verifyCurrentStateSavedToFileOnce();
1094         ImsRegistrationStats[] stats = mPersistAtomsStorage.getImsRegistrationStats(0L);
1095         expectedRegistrationStats.remove();
1096         assertProtoArrayEqualsIgnoringOrder(
1097                 expectedRegistrationStats.toArray(new ImsRegistrationStats[0]), stats);
1098     }
1099 
1100     @Test
1101     @SmallTest
addImsRegistrationTermination_emptyProto()1102     public void addImsRegistrationTermination_emptyProto() throws Exception {
1103         createEmptyTestFile();
1104 
1105         mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
1106         mPersistAtomsStorage.addImsRegistrationTermination(mImsRegistrationTerminationLte);
1107         mPersistAtomsStorage.incTimeMillis(100L);
1108 
1109         // service state and service switch should be added successfully
1110         verifyCurrentStateSavedToFileOnce();
1111         ImsRegistrationTermination[] terminations =
1112                 mPersistAtomsStorage.getImsRegistrationTerminations(0L);
1113         assertProtoArrayEquals(
1114                 new ImsRegistrationTermination[] {mImsRegistrationTerminationLte}, terminations);
1115     }
1116 
1117     @Test
1118     @SmallTest
addImsRegistrationTermination_withExistingEntries()1119     public void addImsRegistrationTermination_withExistingEntries() throws Exception {
1120         createEmptyTestFile();
1121         mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
1122         mPersistAtomsStorage.addImsRegistrationTermination(mImsRegistrationTerminationLte);
1123 
1124         mPersistAtomsStorage.addImsRegistrationTermination(mImsRegistrationTerminationWifi);
1125         mPersistAtomsStorage.incTimeMillis(100L);
1126 
1127         // service state and service switch should be added successfully
1128         verifyCurrentStateSavedToFileOnce();
1129         ImsRegistrationTermination[] terminations =
1130                 mPersistAtomsStorage.getImsRegistrationTerminations(0L);
1131         assertProtoArrayEqualsIgnoringOrder(
1132                 new ImsRegistrationTermination[] {
1133                     mImsRegistrationTerminationLte, mImsRegistrationTerminationWifi
1134                 },
1135                 terminations);
1136     }
1137 
1138     @Test
1139     @SmallTest
addImsRegistrationTermination_updateExistingEntries()1140     public void addImsRegistrationTermination_updateExistingEntries() throws Exception {
1141         createTestFile(START_TIME_MILLIS);
1142         ImsRegistrationTermination newTermination = copyOf(mImsRegistrationTerminationWifi);
1143         mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
1144 
1145         mPersistAtomsStorage.addImsRegistrationTermination(copyOf(mImsRegistrationTerminationWifi));
1146         mPersistAtomsStorage.incTimeMillis(100L);
1147 
1148         // mImsRegistrationTerminationWifi's count should be doubled
1149         verifyCurrentStateSavedToFileOnce();
1150         ImsRegistrationTermination[] terminations =
1151                 mPersistAtomsStorage.getImsRegistrationTerminations(0L);
1152         newTermination.count *= 2;
1153         assertProtoArrayEqualsIgnoringOrder(
1154                 new ImsRegistrationTermination[] {mImsRegistrationTerminationLte, newTermination},
1155                 terminations);
1156     }
1157 
1158     @Test
1159     @SmallTest
addImsRegistrationTermination_tooManyTerminations()1160     public void addImsRegistrationTermination_tooManyTerminations() throws Exception {
1161         createEmptyTestFile();
1162         mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
1163         Queue<ImsRegistrationTermination> expectedTerminations = new LinkedList<>();
1164 
1165         // Add 11 registration terminations
1166         for (int i = 0; i < 11; i++) {
1167             ImsRegistrationTermination termination = copyOf(mImsRegistrationTerminationLte);
1168             termination.reasonCode = i;
1169             expectedTerminations.add(termination);
1170             mPersistAtomsStorage.addImsRegistrationTermination(termination);
1171             mPersistAtomsStorage.incTimeMillis(100L);
1172         }
1173 
1174         // The least recent (the first) registration termination should be evicted
1175         verifyCurrentStateSavedToFileOnce();
1176         ImsRegistrationTermination[] terminations =
1177                 mPersistAtomsStorage.getImsRegistrationTerminations(0L);
1178         expectedTerminations.remove();
1179         assertProtoArrayEqualsIgnoringOrder(
1180                 expectedTerminations.toArray(new ImsRegistrationTermination[0]), terminations);
1181     }
1182 
1183     @Test
1184     @SmallTest
getImsRegistrationStats_tooFrequent()1185     public void getImsRegistrationStats_tooFrequent() throws Exception {
1186         createTestFile(START_TIME_MILLIS);
1187 
1188         mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
1189         mPersistAtomsStorage.incTimeMillis(50L); // pull interval less than minimum
1190         ImsRegistrationStats[] stats = mPersistAtomsStorage.getImsRegistrationStats(100L);
1191 
1192         // should be denied
1193         assertNull(stats);
1194     }
1195 
1196     @Test
1197     @SmallTest
getImsRegistrationStats_withSavedAtoms()1198     public void getImsRegistrationStats_withSavedAtoms() throws Exception {
1199         createTestFile(START_TIME_MILLIS);
1200 
1201         mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
1202         mPersistAtomsStorage.incTimeMillis(100L);
1203         ImsRegistrationStats[] stats1 = mPersistAtomsStorage.getImsRegistrationStats(50L);
1204         mPersistAtomsStorage.incTimeMillis(100L);
1205         ImsRegistrationStats[] stats2 = mPersistAtomsStorage.getImsRegistrationStats(50L);
1206 
1207         // first set of results should equal to file contents, second should be empty, corresponding
1208         // pull timestamp should be updated and saved
1209         assertProtoArrayEqualsIgnoringOrder(
1210                 new ImsRegistrationStats[] {
1211                     mImsRegistrationStatsLte0, mImsRegistrationStatsWifi0, mImsRegistrationStatsLte1
1212                 },
1213                 stats1);
1214         assertProtoArrayEquals(new ImsRegistrationStats[0], stats2);
1215         assertEquals(
1216                 START_TIME_MILLIS + 200L,
1217                 mPersistAtomsStorage.getAtomsProto().imsRegistrationStatsPullTimestampMillis);
1218         InOrder inOrder = inOrder(mTestFileOutputStream);
1219         assertEquals(
1220                 START_TIME_MILLIS + 100L,
1221                 getAtomsWritten(inOrder).imsRegistrationStatsPullTimestampMillis);
1222         assertEquals(
1223                 START_TIME_MILLIS + 200L,
1224                 getAtomsWritten(inOrder).imsRegistrationStatsPullTimestampMillis);
1225         inOrder.verifyNoMoreInteractions();
1226     }
1227 
1228     @Test
1229     @SmallTest
getImsRegistrationTerminations_tooFrequent()1230     public void getImsRegistrationTerminations_tooFrequent() throws Exception {
1231         createTestFile(START_TIME_MILLIS);
1232 
1233         mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
1234         mPersistAtomsStorage.incTimeMillis(50L); // pull interval less than minimum
1235         ImsRegistrationTermination[] terminations =
1236                 mPersistAtomsStorage.getImsRegistrationTerminations(100L);
1237 
1238         // should be denied
1239         assertNull(terminations);
1240     }
1241 
1242     @Test
1243     @SmallTest
getImsRegistrationTerminations_withSavedAtoms()1244     public void getImsRegistrationTerminations_withSavedAtoms() throws Exception {
1245         createTestFile(START_TIME_MILLIS);
1246 
1247         mPersistAtomsStorage = new TestablePersistAtomsStorage(mContext);
1248         mPersistAtomsStorage.incTimeMillis(100L);
1249         ImsRegistrationTermination[] terminations1 =
1250                 mPersistAtomsStorage.getImsRegistrationTerminations(50L);
1251         mPersistAtomsStorage.incTimeMillis(100L);
1252         ImsRegistrationTermination[] terminations2 =
1253                 mPersistAtomsStorage.getImsRegistrationTerminations(50L);
1254 
1255         // first set of results should equal to file contents, second should be empty, corresponding
1256         // pull timestamp should be updated and saved
1257         assertProtoArrayEqualsIgnoringOrder(
1258                 new ImsRegistrationTermination[] {
1259                     mImsRegistrationTerminationLte, mImsRegistrationTerminationWifi
1260                 },
1261                 terminations1);
1262         assertProtoArrayEquals(new ImsRegistrationTermination[0], terminations2);
1263         assertEquals(
1264                 START_TIME_MILLIS + 200L,
1265                 mPersistAtomsStorage.getAtomsProto().imsRegistrationTerminationPullTimestampMillis);
1266         InOrder inOrder = inOrder(mTestFileOutputStream);
1267         assertEquals(
1268                 START_TIME_MILLIS + 100L,
1269                 getAtomsWritten(inOrder).imsRegistrationTerminationPullTimestampMillis);
1270         assertEquals(
1271                 START_TIME_MILLIS + 200L,
1272                 getAtomsWritten(inOrder).imsRegistrationTerminationPullTimestampMillis);
1273         inOrder.verifyNoMoreInteractions();
1274     }
1275 
1276     /* Utilities */
1277 
createEmptyTestFile()1278     private void createEmptyTestFile() throws Exception {
1279         PersistAtoms atoms = new PersistAtoms();
1280         FileOutputStream stream = new FileOutputStream(mTestFile);
1281         stream.write(PersistAtoms.toByteArray(atoms));
1282         stream.close();
1283     }
1284 
createTestFile(long lastPullTimeMillis)1285     private void createTestFile(long lastPullTimeMillis) throws Exception {
1286         PersistAtoms atoms = new PersistAtoms();
1287         atoms.buildFingerprint = Build.FINGERPRINT;
1288         atoms.voiceCallRatUsagePullTimestampMillis = lastPullTimeMillis;
1289         atoms.voiceCallRatUsage = mVoiceCallRatUsages;
1290         atoms.voiceCallSessionPullTimestampMillis = lastPullTimeMillis;
1291         atoms.voiceCallSession = mVoiceCallSessions;
1292         atoms.cellularServiceStatePullTimestampMillis = lastPullTimeMillis;
1293         atoms.cellularServiceState = mServiceStates;
1294         atoms.cellularDataServiceSwitchPullTimestampMillis = lastPullTimeMillis;
1295         atoms.cellularDataServiceSwitch = mServiceSwitches;
1296         atoms.imsRegistrationStatsPullTimestampMillis = lastPullTimeMillis;
1297         atoms.imsRegistrationStats = mImsRegistrationStats;
1298         atoms.imsRegistrationTerminationPullTimestampMillis = lastPullTimeMillis;
1299         atoms.imsRegistrationTermination = mImsRegistrationTerminations;
1300         FileOutputStream stream = new FileOutputStream(mTestFile);
1301         stream.write(PersistAtoms.toByteArray(atoms));
1302         stream.close();
1303     }
1304 
getAtomsWritten(@ullable InOrder inOrder)1305     private PersistAtoms getAtomsWritten(@Nullable InOrder inOrder) throws Exception {
1306         if (inOrder == null) {
1307             inOrder = inOrder(mTestFileOutputStream);
1308         }
1309         ArgumentCaptor bytesCaptor = ArgumentCaptor.forClass(Object.class);
1310         inOrder.verify(mTestFileOutputStream, times(1)).write((byte[]) bytesCaptor.capture());
1311         PersistAtoms savedAtoms = PersistAtoms.parseFrom((byte[]) bytesCaptor.getValue());
1312         inOrder.verify(mTestFileOutputStream, times(1)).close();
1313         return savedAtoms;
1314     }
1315 
addRepeatedCalls( PersistAtomsStorage storage, VoiceCallSession call, int count)1316     private static void addRepeatedCalls(
1317             PersistAtomsStorage storage, VoiceCallSession call, int count) {
1318         for (int i = 0; i < count; i++) {
1319             storage.addVoiceCallSession(call);
1320         }
1321     }
1322 
multiplyVoiceCallRatUsage( VoiceCallRatUsage[] usages, int times)1323     private static VoiceCallRatUsage[] multiplyVoiceCallRatUsage(
1324             VoiceCallRatUsage[] usages, int times) {
1325         VoiceCallRatUsage[] multipliedUsages = new VoiceCallRatUsage[usages.length];
1326         for (int i = 0; i < usages.length; i++) {
1327             multipliedUsages[i] = new VoiceCallRatUsage();
1328             multipliedUsages[i].carrierId = usages[i].carrierId;
1329             multipliedUsages[i].rat = usages[i].rat;
1330             multipliedUsages[i].callCount = usages[i].callCount * 2;
1331             multipliedUsages[i].totalDurationMillis = usages[i].totalDurationMillis * 2;
1332         }
1333         return multipliedUsages;
1334     }
1335 
copyOf(CellularServiceState source)1336     private static CellularServiceState copyOf(CellularServiceState source) throws Exception {
1337         return CellularServiceState.parseFrom(MessageNano.toByteArray(source));
1338     }
1339 
copyOf(CellularDataServiceSwitch source)1340     private static CellularDataServiceSwitch copyOf(CellularDataServiceSwitch source)
1341             throws Exception {
1342         return CellularDataServiceSwitch.parseFrom(MessageNano.toByteArray(source));
1343     }
1344 
copyOf(ImsRegistrationStats source)1345     private static ImsRegistrationStats copyOf(ImsRegistrationStats source) throws Exception {
1346         return ImsRegistrationStats.parseFrom(MessageNano.toByteArray(source));
1347     }
1348 
copyOf(ImsRegistrationTermination source)1349     private static ImsRegistrationTermination copyOf(ImsRegistrationTermination source)
1350             throws Exception {
1351         return ImsRegistrationTermination.parseFrom(MessageNano.toByteArray(source));
1352     }
1353 
assertAllPullTimestampEquals(long timestamp)1354     private void assertAllPullTimestampEquals(long timestamp) {
1355         assertEquals(
1356                 timestamp,
1357                 mPersistAtomsStorage.getAtomsProto().voiceCallRatUsagePullTimestampMillis);
1358         assertEquals(
1359                 timestamp,
1360                 mPersistAtomsStorage.getAtomsProto().voiceCallSessionPullTimestampMillis);
1361         assertEquals(
1362                 timestamp,
1363                 mPersistAtomsStorage.getAtomsProto().cellularServiceStatePullTimestampMillis);
1364         assertEquals(
1365                 timestamp,
1366                 mPersistAtomsStorage.getAtomsProto().cellularDataServiceSwitchPullTimestampMillis);
1367     }
1368 
assertStorageIsEmptyForAllAtoms()1369     private void assertStorageIsEmptyForAllAtoms() {
1370         assertProtoArrayIsEmpty(mPersistAtomsStorage.getVoiceCallRatUsages(0L));
1371         assertProtoArrayIsEmpty(mPersistAtomsStorage.getVoiceCallSessions(0L));
1372         assertProtoArrayIsEmpty(mPersistAtomsStorage.getCellularServiceStates(0L));
1373         assertProtoArrayIsEmpty(mPersistAtomsStorage.getCellularDataServiceSwitches(0L));
1374     }
1375 
assertProtoArrayIsEmpty(T[] array)1376     private static <T extends MessageNano> void assertProtoArrayIsEmpty(T[] array) {
1377         assertNotNull(array);
1378         assertEquals(0, array.length);
1379     }
1380 
assertProtoArrayEquals(MessageNano[] expected, MessageNano[] actual)1381     private static void assertProtoArrayEquals(MessageNano[] expected, MessageNano[] actual) {
1382         assertNotNull(expected);
1383         assertNotNull(actual);
1384         String message =
1385                 "Expected:\n" + Arrays.toString(expected) + "\nGot:\n" + Arrays.toString(actual);
1386         assertEquals(message, expected.length, actual.length);
1387         for (int i = 0; i < expected.length; i++) {
1388             assertTrue(message, MessageNano.messageNanoEquals(expected[i], actual[i]));
1389         }
1390     }
1391 
assertProtoArrayEqualsIgnoringOrder( MessageNano[] expected, MessageNano[] actual)1392     private static void assertProtoArrayEqualsIgnoringOrder(
1393             MessageNano[] expected, MessageNano[] actual) {
1394         assertNotNull(expected);
1395         assertNotNull(actual);
1396         expected = expected.clone();
1397         actual = actual.clone();
1398         Arrays.sort(expected, sProtoComparator);
1399         Arrays.sort(actual, sProtoComparator);
1400         assertProtoArrayEquals(expected, actual);
1401     }
1402 
assertHasCall( VoiceCallSession[] calls, @Nullable VoiceCallSession expectedCall, int expectedCount)1403     private static void assertHasCall(
1404             VoiceCallSession[] calls, @Nullable VoiceCallSession expectedCall, int expectedCount) {
1405         assertNotNull(calls);
1406         int actualCount = 0;
1407         for (VoiceCallSession call : calls) {
1408             if (call != null && expectedCall != null) {
1409                 if (MessageNano.messageNanoEquals(call, expectedCall)) {
1410                     actualCount++;
1411                 }
1412             }
1413         }
1414         assertEquals(expectedCount, actualCount);
1415     }
1416 
verifyCurrentStateSavedToFileOnce()1417     private void verifyCurrentStateSavedToFileOnce() throws Exception {
1418         InOrder inOrder = inOrder(mTestFileOutputStream);
1419         inOrder.verify(mTestFileOutputStream, times(1))
1420                 .write(eq(PersistAtoms.toByteArray(mPersistAtomsStorage.getAtomsProto())));
1421         inOrder.verify(mTestFileOutputStream, times(1)).close();
1422         inOrder.verifyNoMoreInteractions();
1423     }
1424 }
1425