1 /*
2  * Copyright (C) 2022 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.adservices.download;
18 
19 import static com.android.adservices.download.EnrollmentDataDownloadManager.DownloadStatus.SUCCESS;
20 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
21 
22 import static com.google.common.truth.Truth.assertThat;
23 
24 import static org.mockito.ArgumentMatchers.any;
25 import static org.mockito.Mockito.when;
26 
27 import static java.util.concurrent.TimeUnit.SECONDS;
28 
29 import android.content.Context;
30 import android.database.DatabaseUtils;
31 import android.net.wifi.WifiManager;
32 import android.os.SystemClock;
33 
34 import androidx.annotation.NonNull;
35 
36 import com.android.adservices.common.AdServicesExtendedMockitoTestCase;
37 import com.android.adservices.data.DbTestUtil;
38 import com.android.adservices.data.encryptionkey.EncryptionKeyDao;
39 import com.android.adservices.data.encryptionkey.EncryptionKeyTables;
40 import com.android.adservices.data.enrollment.EnrollmentDao;
41 import com.android.adservices.data.enrollment.EnrollmentTables;
42 import com.android.adservices.data.shared.SharedDbHelper;
43 import com.android.adservices.service.FakeFlagsFactory;
44 import com.android.adservices.service.Flags;
45 import com.android.adservices.service.FlagsFactory;
46 import com.android.adservices.service.consent.AdServicesApiConsent;
47 import com.android.adservices.service.consent.AdServicesApiType;
48 import com.android.adservices.service.consent.ConsentManager;
49 import com.android.adservices.service.topics.classifier.CommonClassifierHelper;
50 import com.android.adservices.service.ui.data.UxStatesManager;
51 import com.android.adservices.service.ui.ux.collection.PrivacySandboxUxCollection;
52 import com.android.adservices.shared.testing.annotations.RequiresSdkLevelAtLeastS;
53 import com.android.adservices.shared.util.Clock;
54 import com.android.compatibility.common.util.ShellUtils;
55 import com.android.modules.utils.testing.ExtendedMockitoRule.SpyStatic;
56 
57 import com.google.android.libraries.mobiledatadownload.AddFileGroupRequest;
58 import com.google.android.libraries.mobiledatadownload.DownloadFileGroupRequest;
59 import com.google.android.libraries.mobiledatadownload.FileGroupPopulator;
60 import com.google.android.libraries.mobiledatadownload.GetFileGroupRequest;
61 import com.google.android.libraries.mobiledatadownload.Logger;
62 import com.google.android.libraries.mobiledatadownload.MobileDataDownload;
63 import com.google.android.libraries.mobiledatadownload.MobileDataDownloadBuilder;
64 import com.google.android.libraries.mobiledatadownload.TaskScheduler;
65 import com.google.android.libraries.mobiledatadownload.TimeSource;
66 import com.google.android.libraries.mobiledatadownload.downloader.FileDownloader;
67 import com.google.android.libraries.mobiledatadownload.file.SynchronousFileStorage;
68 import com.google.android.libraries.mobiledatadownload.monitor.NetworkUsageMonitor;
69 import com.google.common.base.Optional;
70 import com.google.common.collect.ImmutableList;
71 import com.google.mobiledatadownload.ClientConfigProto;
72 import com.google.mobiledatadownload.ClientConfigProto.ClientFileGroup;
73 import com.google.mobiledatadownload.DownloadConfigProto.DataFile;
74 import com.google.mobiledatadownload.DownloadConfigProto.DataFileGroup;
75 import com.google.mobiledatadownload.DownloadConfigProto.DownloadConditions;
76 import com.google.mobiledatadownload.DownloadConfigProto.DownloadConditions.DeviceNetworkPolicy;
77 
78 import org.junit.After;
79 import org.junit.Assume;
80 import org.junit.Before;
81 import org.junit.Test;
82 import org.mockito.Mock;
83 
84 import java.util.concurrent.ExecutionException;
85 import java.util.concurrent.TimeoutException;
86 import java.util.stream.Collectors;
87 
88 /** Unit tests for {@link MobileDataDownloadFactory} */
89 @RequiresSdkLevelAtLeastS
90 @SpyStatic(MddLogger.class)
91 @SpyStatic(FlagsFactory.class)
92 @SpyStatic(MobileDataDownloadFactory.class)
93 @SpyStatic(UxStatesManager.class)
94 @SpyStatic(EnrollmentDao.class)
95 @SpyStatic(EncryptionKeyDao.class)
96 @SpyStatic(ConsentManager.class)
97 @SpyStatic(CommonClassifierHelper.class)
98 public final class MobileDataDownloadTest extends AdServicesExtendedMockitoTestCase {
99     private static final int MAX_HANDLE_TASK_WAIT_TIME_SECS = 300;
100 
101     // Two files are from cts_test_1 folder.
102     // https://source.corp.google.com/piper///depot/google3/wireless/android/adservices/mdd/topics_classifier/cts_test_1/
103     private static final String FILE_GROUP_NAME_1 = "test-group-1";
104     private static final String FILE_ID_1 = "classifier_assets_metadata.json";
105     private static final String FILE_ID_2 = "stopwords.txt";
106     private static final String FILE_CHECKSUM_1 = "52633ae715ead32ec6c8ae721ad34ea301336a8e";
107     private static final String FILE_URL_1 =
108             "https://dl.google.com/mdi-serving/rubidium-adservices-topics-classifier/1489"
109                     + "/52633ae715ead32ec6c8ae721ad34ea301336a8e";
110     private static final int FILE_SIZE_1 = 1026;
111 
112     private static final String FILE_CHECKSUM_2 = "042dc4512fa3d391c5170cf3aa61e6a638f84342";
113     private static final String FILE_URL_2 =
114             "https://dl.google.com/mdi-serving/rubidium-adservices-topics-classifier/1489"
115                     + "/042dc4512fa3d391c5170cf3aa61e6a638f84342";
116     private static final int FILE_SIZE_2 = 1;
117 
118     // TODO(b/263521464): Use the production topics classifier manifest URL.
119     private static final String TEST_MDD_TOPICS_CLASSIFIER_MANIFEST_FILE_URL =
120             "https://www.gstatic.com/mdi-serving/rubidium-adservices-topics-classifier/922"
121                     + "/217081737fd739c74dd3ca5c407813d818526577";
122     private static final String MDD_TOPICS_CLASSIFIER_MANIFEST_FILE_URL =
123             "https://www.gstatic.com/mdi-serving/rubidium-adservices-topics-classifier/1986"
124                     + "/9e98784bcdb26a3eb2ab3f65ee811f43177c761f";
125     private static final String PRODUCTION_ENROLLMENT_MANIFEST_FILE_URL =
126             "https://www.gstatic.com/mdi-serving/rubidium-adservices-adtech-enrollment/4503"
127                     + "/fecd522d3dcfbe1b3b1f1054947be8528be43e97";
128     private static final String PRODUCTION_ENCRYPTION_KEYS_MANIFEST_FILE_URL =
129             "https://www.gstatic.com/mdi-serving/rubidium-adservices-encryption-keys/4543"
130                     + "/e9d118728752e6a6bfb5d7d8d1520807591f0717";
131 
132     // Prod Test Bed enrollment manifest URL
133     private static final String PTB_ENROLLMENT_MANIFEST_FILE_URL =
134             "https://www.gstatic.com/mdi-serving/rubidium-adservices-adtech-enrollment/3548"
135                     + "/206afe932d6db2a87cad70421454a0c258297d77";
136     private static final String OEM_ENROLLMENT_MANIFEST_FILE_URL =
137             "https://www.gstatic.com/mdi-serving/rubidium-adservices-adtech-enrollment/1760"
138                     + "/1460e6aea598fe7a153100d6e2749f45313ef905";
139     private static final String UI_OTA_STRINGS_MANIFEST_FILE_URL =
140             "https://www.gstatic.com/mdi-serving/rubidium-adservices-ui-ota-strings/1360"
141                     + "/d428721d225582922a7fe9d5ad6db7b09cb03209";
142 
143     private static final String UI_OTA_RESOURCES_MANIFEST_FILE_URL =
144             "https://www.gstatic.com/mdi-serving/rubidium-adservices-ui-ota-strings/3150"
145                     + "/672c83fa4aad630a360dc3b7ce43d94ab75852cd";
146 
147     private static final int PRODUCTION_ENROLLMENT_ENTRIES = 78;
148 
149     /** Old PTB URL with a small number of enrollment records. */
150     private static final String PTB_OLD_ENROLLMENT_FILE_URL =
151             "https://www.gstatic.com/mdi-serving/rubidium-adservices-adtech-enrollment/3156/9d9d99be0c6dc71fc329f5c02a0fac48d3b06e73";
152 
153     private static final int PTB_ENROLLMENT_ENTRIES = 6;
154 
155     private static final int PTB_OLD_ENROLLMENT_ENTRIES = 4;
156     private static final int OEM_ENROLLMENT_ENTRIES = 114;
157 
158     private static final int PRODUCTION_FILEGROUP_VERSION = 0;
159     private static final int PTB_FILEGROUP_VERSION = 0;
160     private static final int OEM_FILEGROUP_VERSION = 0;
161 
162     public static final String TEST_TOPIC_FILE_GROUP_NAME = "topics-classifier-model";
163     public static final String ENCRYPTION_KEYS_FILE_GROUP_NAME = "encryption-keys";
164     public static final String ENROLLMENT_FILE_GROUP_NAME = "adtech_enrollment_data";
165     public static final String ENROLLMENT_PROTO_FILE_GROUP_NAME = "adtech_enrollment_proto_data";
166     public static final String UI_OTA_STRINGS_FILE_GROUP_NAME = "ui-ota-strings";
167     private SynchronousFileStorage mFileStorage;
168     private FileDownloader mFileDownloader;
169     private SharedDbHelper mDbHelper;
170     private MobileDataDownload mMdd;
171     private WifiManager mWifiManager;
172 
173     @Mock Flags mMockFlags;
174     @Mock ConsentManager mConsentManager;
175     @Mock UxStatesManager mUxStatesManager;
176     @Mock Clock mMockClock;
177 
178     @Before
setUp()179     public void setUp() throws Exception {
180         mWifiManager = mContext.getSystemService(WifiManager.class);
181         // The MDD integration tests require wifi connection. If the running device is not
182         // connected to the Wifi, tests should be skipped.
183         Assume.assumeTrue("Device must have wifi connection", mWifiManager.isWifiEnabled());
184 
185         mockMddFlags();
186 
187         mFileStorage = MobileDataDownloadFactory.getFileStorage();
188         mFileDownloader = MobileDataDownloadFactory.getFileDownloader(mMockFlags, mFileStorage);
189 
190         mDbHelper = DbTestUtil.getSharedDbHelperForTest();
191 
192         doReturn(AdServicesApiConsent.GIVEN).when(mConsentManager).getConsent();
193         // Mock static method ConsentManager.getInstance() to return test ConsentManager
194         doReturn(mConsentManager).when(() -> ConsentManager.getInstance());
195         doReturn(mUxStatesManager).when(() -> UxStatesManager.getInstance());
196         overridingMddLoggingLevel("VERBOSE");
197     }
198 
199     @After
teardown()200     public void teardown() throws ExecutionException, InterruptedException {
201         if (mMdd != null) {
202             mMdd.clear().get();
203         }
204         overridingMddLoggingLevel("INFO");
205     }
206 
207     @Test
testCreateMddManagerSuccessfully()208     public void testCreateMddManagerSuccessfully() throws ExecutionException, InterruptedException {
209         mMdd =
210                 getMddForTesting(
211                         mContext,
212                         FakeFlagsFactory.getFlagsForTest(),
213                         // Pass in an empty list of FileGroupPopulator. Add ad hoc DataFileGroup
214                         // to MDD manually below.
215                         ImmutableList.of());
216 
217         DataFileGroup dataFileGroup =
218                 createDataFileGroup(
219                         FILE_GROUP_NAME_1,
220                         mContext.getPackageName(),
221                         5 /* versionNumber */,
222                         new String[] {FILE_ID_1, FILE_ID_2},
223                         new int[] {FILE_SIZE_1, FILE_SIZE_2},
224                         new String[] {FILE_CHECKSUM_1, FILE_CHECKSUM_2},
225                         new String[] {FILE_URL_1, FILE_URL_2},
226                         DeviceNetworkPolicy.DOWNLOAD_ONLY_ON_WIFI);
227         // Add the DataFileGroup to MDD
228         assertThat(
229                         mMdd.addFileGroup(
230                                         AddFileGroupRequest.newBuilder()
231                                                 .setDataFileGroup(dataFileGroup)
232                                                 .build())
233                                 .get())
234                 .isTrue();
235 
236         // Trigger the download immediately.
237         ClientFileGroup clientFileGroup =
238                 mMdd.downloadFileGroup(
239                                 DownloadFileGroupRequest.newBuilder()
240                                         .setGroupName(FILE_GROUP_NAME_1)
241                                         .build())
242                         .get();
243 
244         // Verify the downloaded DataFileGroup.
245         assertThat(clientFileGroup.getGroupName()).isEqualTo(FILE_GROUP_NAME_1);
246         assertThat(clientFileGroup.getOwnerPackage()).isEqualTo(mContext.getPackageName());
247         assertThat(clientFileGroup.getVersionNumber()).isEqualTo(5);
248         assertThat(clientFileGroup.getFileCount()).isEqualTo(2);
249         assertThat(clientFileGroup.hasAccount()).isFalse();
250     }
251 
252     @Test
testTopicsManifestFileGroupPopulator_ManifestConfigOverrider_NoFileGroup()253     public void testTopicsManifestFileGroupPopulator_ManifestConfigOverrider_NoFileGroup()
254             throws ExecutionException, InterruptedException, TimeoutException {
255         createMddForTopics(MDD_TOPICS_CLASSIFIER_MANIFEST_FILE_URL);
256         // The server side test model build_id = 1986, which equals to bundled model build_id =
257         // 1986. ManifestConfigOverrider will not add the DataFileGroup in the
258         // TopicsManifestFileGroupPopulator and will not download either.
259         assertThat(
260                         mMdd.getFileGroup(
261                                         GetFileGroupRequest.newBuilder()
262                                                 .setGroupName(TEST_TOPIC_FILE_GROUP_NAME)
263                                                 .build())
264                                 .get())
265                 .isNull();
266     }
267 
268     /**
269      * This method tests topics manifest files. It downloads test classifier model and verifies
270      * files downloaded successfully.
271      */
272     @Test
testTopicsManifestFileGroupPopulator()273     public void testTopicsManifestFileGroupPopulator()
274             throws ExecutionException, InterruptedException, TimeoutException {
275         // Set the bundled build_id to 1 so the server side build_id will be bigger. This will
276         // trigger MDD download.
277         doReturn(1L).when(() -> CommonClassifierHelper.getBundledModelBuildId(any(), any()));
278 
279         createMddForTopics(MDD_TOPICS_CLASSIFIER_MANIFEST_FILE_URL);
280 
281         ClientFileGroup clientFileGroup =
282                 mMdd.getFileGroup(
283                                 GetFileGroupRequest.newBuilder()
284                                         .setGroupName(TEST_TOPIC_FILE_GROUP_NAME)
285                                         .build())
286                         .get();
287 
288         // Verify topics file group.
289         assertThat(clientFileGroup.getGroupName()).isEqualTo(TEST_TOPIC_FILE_GROUP_NAME);
290         assertThat(clientFileGroup.getOwnerPackage()).isEqualTo(mContext.getPackageName());
291         assertThat(clientFileGroup.getVersionNumber())
292                 .isEqualTo(/* Test filegroup version number */ 0);
293         assertThat(clientFileGroup.getFileCount()).isEqualTo(6);
294         assertThat(clientFileGroup.getStatus()).isEqualTo(ClientFileGroup.Status.DOWNLOADED);
295         assertThat(clientFileGroup.getBuildId()).isEqualTo(/* BuildID generated by Ingress */ 1986);
296     }
297 
298     /**
299      * This method tests MDD production encryption keys data, verifies files downloaded successfully
300      * and data saved into DB correctly.
301      */
302     @Test
testEncryptionKeysDataDownload_production_featureEnabled()303     public void testEncryptionKeysDataDownload_production_featureEnabled() throws Exception {
304         doReturn(true).when(mMockFlags).getEnableMddEncryptionKeys();
305         // All keys have greater expiration time than this timestamp. (Sep 2, 1996)
306         when(mMockClock.currentTimeMillis()).thenReturn(841622400000L);
307         createMddForEncryptionKeys(PRODUCTION_ENCRYPTION_KEYS_MANIFEST_FILE_URL);
308 
309         ClientFileGroup clientFileGroup =
310                 mMdd.getFileGroup(
311                                 GetFileGroupRequest.newBuilder()
312                                         .setGroupName(ENCRYPTION_KEYS_FILE_GROUP_NAME)
313                                         .build())
314                         .get();
315 
316         assertThat(clientFileGroup).isNotNull();
317         verifyEncryptionKeysFileGroup(clientFileGroup, /* NumberOfKeysOnTestUrl */ 2);
318     }
319 
320     /** Test disabling the feature flag does not create the manifest for download. */
321     @Test
testEncryptionKeysDataDownload_production_featureDisabled()322     public void testEncryptionKeysDataDownload_production_featureDisabled() throws Exception {
323         doReturn(false).when(mMockFlags).getEnableMddEncryptionKeys();
324         createMddForEncryptionKeys(PRODUCTION_ENCRYPTION_KEYS_MANIFEST_FILE_URL);
325 
326         ClientFileGroup clientFileGroup =
327                 mMdd.getFileGroup(
328                                 GetFileGroupRequest.newBuilder()
329                                         .setGroupName(ENCRYPTION_KEYS_FILE_GROUP_NAME)
330                                         .build())
331                         .get();
332 
333         assertThat(clientFileGroup).isNull();
334     }
335 
336     /**
337      * This method tests MDD production enrollment data, verifies files downloaded successfully and
338      * data saved into DB correctly.
339      */
340     @Test
testEnrollmentDataDownload_Production()341     public void testEnrollmentDataDownload_Production()
342             throws ExecutionException, InterruptedException, TimeoutException {
343         when(mMockFlags.getEncryptionKeyNewEnrollmentFetchKillSwitch()).thenReturn(true);
344         createMddForEnrollment(PRODUCTION_ENROLLMENT_MANIFEST_FILE_URL, /* getProto= */ false);
345 
346         ClientFileGroup clientFileGroup =
347                 mMdd.getFileGroup(
348                                 GetFileGroupRequest.newBuilder()
349                                         .setGroupName(ENROLLMENT_FILE_GROUP_NAME)
350                                         .build())
351                         .get();
352 
353         verifyMeasurementFileGroup(
354                 clientFileGroup, PRODUCTION_FILEGROUP_VERSION, PRODUCTION_ENROLLMENT_ENTRIES);
355     }
356 
357     /**
358      * This method tests OEM enrollment data, verifies files downloaded successfully and data saved
359      * into DB correctly.
360      */
361     @Test
testEnrollmentDataDownload_OEM()362     public void testEnrollmentDataDownload_OEM()
363             throws ExecutionException, InterruptedException, TimeoutException {
364         when(mMockFlags.getEncryptionKeyNewEnrollmentFetchKillSwitch()).thenReturn(true);
365         createMddForEnrollment(OEM_ENROLLMENT_MANIFEST_FILE_URL, /* getProto= */ false);
366 
367         ClientFileGroup clientFileGroup =
368                 mMdd.getFileGroup(
369                                 GetFileGroupRequest.newBuilder()
370                                         .setGroupName(ENROLLMENT_FILE_GROUP_NAME)
371                                         .build())
372                         .get();
373 
374         verifyMeasurementFileGroup(clientFileGroup, OEM_FILEGROUP_VERSION, OEM_ENROLLMENT_ENTRIES);
375     }
376 
377     /**
378      * This method tests Prod Test Bed enrollment data, verifies files downloaded successfully and
379      * data saved into DB correctly, additionally checks record deletion when flag is enabled.
380      */
381     @Test
testEnrollmentDataDownload_PTB()382     public void testEnrollmentDataDownload_PTB()
383             throws ExecutionException, InterruptedException, TimeoutException {
384         when(mMockFlags.getEncryptionKeyNewEnrollmentFetchKillSwitch()).thenReturn(true);
385         when(mMockFlags.getEnrollmentMddRecordDeletionEnabled()).thenReturn(true);
386         createMddForEnrollment(PTB_ENROLLMENT_MANIFEST_FILE_URL, /* getProto= */ false);
387 
388         ClientFileGroup clientFileGroup =
389                 mMdd.getFileGroup(
390                                 GetFileGroupRequest.newBuilder()
391                                         .setGroupName(ENROLLMENT_FILE_GROUP_NAME)
392                                         .build())
393                         .get();
394 
395         verifyMeasurementFileGroup(
396                 clientFileGroup,
397                 PTB_FILEGROUP_VERSION,
398                 PTB_ENROLLMENT_ENTRIES,
399                 /* clearExistingData= */ true,
400                 /* clearDownloadedData= */ false);
401         createMddForEnrollment(PTB_OLD_ENROLLMENT_FILE_URL, /* getProto= */ false);
402         verifyMeasurementFileGroup(
403                 clientFileGroup,
404                 PTB_FILEGROUP_VERSION,
405                 PTB_OLD_ENROLLMENT_ENTRIES,
406                 /* clearExistingData= */ false,
407                 /* clearDownloadedData= */ true);
408     }
409 
410     // TODO (b/340891475): Add tests for Enrollment production proto files
411 
412     /** This method verifies that the file group does not exist when an empty url is provided. */
413     @Test
testEnrollmentProtoDataDownload_emptyUrl()414     public void testEnrollmentProtoDataDownload_emptyUrl() throws Exception {
415         when(mMockFlags.getEncryptionKeyNewEnrollmentFetchKillSwitch()).thenReturn(true);
416         createMddForEnrollment("", /* getProto= */ true);
417 
418         ClientFileGroup clientFileGroup =
419                 mMdd.getFileGroup(
420                                 GetFileGroupRequest.newBuilder()
421                                         .setGroupName(ENROLLMENT_PROTO_FILE_GROUP_NAME)
422                                         .build())
423                         .get();
424 
425         assertThat(clientFileGroup).isNull();
426     }
427 
428     /**
429      * This method tests enrollment data, verifies that the file group doesn't exist if the consent
430      * is revoked.
431      */
432     @Test
testEnrollmentDataDownloadFailOnConsentRevoked_gaUxEnabled()433     public void testEnrollmentDataDownloadFailOnConsentRevoked_gaUxEnabled()
434             throws ExecutionException, InterruptedException, TimeoutException {
435         doReturn(true).when(mMockFlags).getGaUxFeatureEnabled();
436         when(mConsentManager.getConsent(AdServicesApiType.MEASUREMENTS))
437                 .thenReturn(AdServicesApiConsent.REVOKED);
438 
439         createMddForEnrollment(PRODUCTION_ENROLLMENT_MANIFEST_FILE_URL, /* getProto= */ false);
440 
441         ClientFileGroup clientFileGroup =
442                 mMdd.getFileGroup(
443                                 GetFileGroupRequest.newBuilder()
444                                         .setGroupName(ENROLLMENT_FILE_GROUP_NAME)
445                                         .build())
446                         .get();
447 
448         assertThat(clientFileGroup).isNull();
449     }
450 
451     /**
452      * This method tests enrollment data, verifies that the file group exists if the consent is
453      * given.
454      */
455     @Test
testEnrollmentDataDownloadOnConsentGiven_gaUxEnabled()456     public void testEnrollmentDataDownloadOnConsentGiven_gaUxEnabled()
457             throws ExecutionException, InterruptedException, TimeoutException {
458         doReturn(true).when(mMockFlags).getGaUxFeatureEnabled();
459         when(mConsentManager.getConsent(AdServicesApiType.MEASUREMENTS))
460                 .thenReturn(AdServicesApiConsent.GIVEN);
461 
462         createMddForEnrollment(PRODUCTION_ENROLLMENT_MANIFEST_FILE_URL, /* getProto= */ false);
463 
464         ClientFileGroup clientFileGroup =
465                 mMdd.getFileGroup(
466                                 GetFileGroupRequest.newBuilder()
467                                         .setGroupName(ENROLLMENT_FILE_GROUP_NAME)
468                                         .build())
469                         .get();
470 
471         assertThat(clientFileGroup).isNotNull();
472     }
473 
474     /**
475      * This method tests topics data, verifies that the file group doesn't exist if the consent is
476      * revoked.
477      */
478     @Test
testMddTopicsFailsOnConsentRevoked_gaUxEnabled()479     public void testMddTopicsFailsOnConsentRevoked_gaUxEnabled()
480             throws ExecutionException, InterruptedException, TimeoutException {
481         doReturn(true).when(mMockFlags).getGaUxFeatureEnabled();
482         when(mConsentManager.getConsent(AdServicesApiType.TOPICS))
483                 .thenReturn(AdServicesApiConsent.REVOKED);
484 
485         createMddForTopics(TEST_MDD_TOPICS_CLASSIFIER_MANIFEST_FILE_URL);
486 
487         ClientFileGroup clientFileGroup =
488                 mMdd.getFileGroup(
489                                 GetFileGroupRequest.newBuilder()
490                                         .setGroupName(TEST_TOPIC_FILE_GROUP_NAME)
491                                         .build())
492                         .get();
493 
494         assertThat(clientFileGroup).isNull();
495     }
496 
497     /**
498      * This method tests topics data, verifies that the file group exists if the consent is given.
499      */
500     @Test
testMddTopicsOnConsentGiven_gaUxEnabled()501     public void testMddTopicsOnConsentGiven_gaUxEnabled()
502             throws ExecutionException, InterruptedException, TimeoutException {
503         doReturn(1L).when(() -> CommonClassifierHelper.getBundledModelBuildId(any(), any()));
504 
505         doReturn(true).when(mMockFlags).getGaUxFeatureEnabled();
506         when(mConsentManager.getConsent(AdServicesApiType.TOPICS))
507                 .thenReturn(AdServicesApiConsent.GIVEN);
508 
509         createMddForTopics(TEST_MDD_TOPICS_CLASSIFIER_MANIFEST_FILE_URL);
510 
511         ClientFileGroup clientFileGroup =
512                 mMdd.getFileGroup(
513                                 GetFileGroupRequest.newBuilder()
514                                         .setGroupName(TEST_TOPIC_FILE_GROUP_NAME)
515                                         .build())
516                         .get();
517 
518         assertThat(clientFileGroup).isNotNull();
519     }
520 
521     /**
522      * This method tests OTA data, verifies that the file group exists if the consent is given to at
523      * least one of the APIs.
524      */
525     @Test
testOtaOnTopicsConsentGiven_gaUxEnabled()526     public void testOtaOnTopicsConsentGiven_gaUxEnabled()
527             throws ExecutionException, InterruptedException, TimeoutException {
528         doReturn(true).when(mMockFlags).getGaUxFeatureEnabled();
529         when(mConsentManager.getConsent(AdServicesApiType.TOPICS))
530                 .thenReturn(AdServicesApiConsent.GIVEN);
531 
532         doReturn(UI_OTA_STRINGS_MANIFEST_FILE_URL)
533                 .when(mMockFlags)
534                 .getUiOtaStringsManifestFileUrl();
535         doReturn(UI_OTA_RESOURCES_MANIFEST_FILE_URL)
536                 .when(mMockFlags)
537                 .getUiOtaResourcesManifestFileUrl();
538         createMddForUiOTA();
539 
540         ClientFileGroup clientFileGroup =
541                 mMdd.getFileGroup(
542                                 GetFileGroupRequest.newBuilder()
543                                         .setGroupName(UI_OTA_STRINGS_FILE_GROUP_NAME)
544                                         .build())
545                         .get();
546 
547         assertThat(clientFileGroup).isNotNull();
548     }
549 
550     /**
551      * This method tests OTA data, verifies that the file group doesn't exist if the consent is
552      * revoked for all the APIs.
553      */
554     @Test
testOtaFailsOnAggregatedConsentRevoked_gaUxEnabled()555     public void testOtaFailsOnAggregatedConsentRevoked_gaUxEnabled()
556             throws ExecutionException, InterruptedException, TimeoutException {
557         doReturn(true).when(mMockFlags).getGaUxFeatureEnabled();
558         when(mConsentManager.getConsent(AdServicesApiType.TOPICS))
559                 .thenReturn(AdServicesApiConsent.REVOKED);
560         when(mConsentManager.getConsent(AdServicesApiType.MEASUREMENTS))
561                 .thenReturn(AdServicesApiConsent.REVOKED);
562         when(mConsentManager.getConsent(AdServicesApiType.FLEDGE))
563                 .thenReturn(AdServicesApiConsent.REVOKED);
564 
565         createMddForTopics(TEST_MDD_TOPICS_CLASSIFIER_MANIFEST_FILE_URL);
566 
567         ClientFileGroup clientFileGroup =
568                 mMdd.getFileGroup(
569                                 GetFileGroupRequest.newBuilder()
570                                         .setGroupName(UI_OTA_STRINGS_FILE_GROUP_NAME)
571                                         .build())
572                         .get();
573 
574         assertThat(clientFileGroup).isNull();
575     }
576 
577     // Topics MFGP should be disabled for U18 UX.
578     @Test
topicsDownloadTest_U18UxEnabled()579     public void topicsDownloadTest_U18UxEnabled()
580             throws ExecutionException, InterruptedException, TimeoutException {
581         doReturn(PrivacySandboxUxCollection.U18_UX).when(mUxStatesManager).getUx();
582 
583         createMddForTopics(TEST_MDD_TOPICS_CLASSIFIER_MANIFEST_FILE_URL);
584 
585         ClientFileGroup clientFileGroup =
586                 mMdd.getFileGroup(
587                                 GetFileGroupRequest.newBuilder()
588                                         .setGroupName(TEST_TOPIC_FILE_GROUP_NAME)
589                                         .build())
590                         .get();
591 
592         assertThat(clientFileGroup).isNull();
593     }
594 
595     @Test
testMddLoggerFeatureFlagIsOff()596     public void testMddLoggerFeatureFlagIsOff() {
597         // The feature flag is off. MddLogger should be disabled.
598         doReturn(false).when(mMockFlags).getMddLoggerEnabled();
599         Optional<Logger> mddLogger = MobileDataDownloadFactory.getMddLogger(mMockFlags);
600         assertThat(mddLogger).isAbsent();
601     }
602 
603     @Test
testMddLoggerFeatureFlagIsOn()604     public void testMddLoggerFeatureFlagIsOn() {
605         // The feature flag is on. MddLogger should be enabled.
606         doReturn(true).when(mMockFlags).getMddLoggerEnabled();
607         Optional<Logger> mddLogger = MobileDataDownloadFactory.getMddLogger(mMockFlags);
608         assertThat(mddLogger).isPresent();
609     }
610 
611     /**
612      * This method tests UI OTA Strings manifest files. It downloads test UI Strings file and
613      * verifies files downloaded successfully.
614      */
615     @Test
testUiOtaStringsManifestFileGroupPopulator()616     public void testUiOtaStringsManifestFileGroupPopulator()
617             throws ExecutionException, InterruptedException, TimeoutException {
618         doReturn(false).when(mMockFlags).getUiOtaResourcesFeatureEnabled();
619         doReturn(UI_OTA_STRINGS_MANIFEST_FILE_URL)
620                 .when(mMockFlags)
621                 .getUiOtaStringsManifestFileUrl();
622         createMddForUiOTA();
623 
624         ClientFileGroup clientFileGroup =
625                 mMdd.getFileGroup(
626                                 GetFileGroupRequest.newBuilder()
627                                         .setGroupName(UI_OTA_STRINGS_FILE_GROUP_NAME)
628                                         .build())
629                         .get();
630 
631         // Verify UI file group.
632         assertThat(clientFileGroup.getGroupName()).isEqualTo(UI_OTA_STRINGS_FILE_GROUP_NAME);
633         assertThat(clientFileGroup.getOwnerPackage()).isEqualTo(mContext.getPackageName());
634         assertThat(clientFileGroup.getFileCount()).isEqualTo(1);
635         assertThat(clientFileGroup.getStatus()).isEqualTo(ClientFileGroup.Status.DOWNLOADED);
636         assertThat(clientFileGroup.getBuildId()).isEqualTo(/* BuildID generated by Ingress */ 1360);
637     }
638 
639     /**
640      * This method tests UI OTA resources manifest files. It downloads test UI apk file and verifies
641      * files downloaded successfully.
642      */
643     @Test
testUiOtaResourcesManifestFileGroupPopulator()644     public void testUiOtaResourcesManifestFileGroupPopulator()
645             throws ExecutionException, InterruptedException, TimeoutException {
646         doReturn(true).when(mMockFlags).getUiOtaResourcesFeatureEnabled();
647         doReturn(UI_OTA_RESOURCES_MANIFEST_FILE_URL)
648                 .when(mMockFlags)
649                 .getUiOtaResourcesManifestFileUrl();
650         createMddForUiOTA();
651 
652         ClientFileGroup clientFileGroup =
653                 mMdd.getFileGroup(
654                                 GetFileGroupRequest.newBuilder()
655                                         .setGroupName(UI_OTA_STRINGS_FILE_GROUP_NAME)
656                                         .build())
657                         .get();
658 
659         // Verify UI file group.
660         assertThat(clientFileGroup.getGroupName()).isEqualTo(UI_OTA_STRINGS_FILE_GROUP_NAME);
661         assertThat(clientFileGroup.getOwnerPackage()).isEqualTo(mContext.getPackageName());
662         assertThat(clientFileGroup.getFileCount()).isEqualTo(1);
663         assertThat(clientFileGroup.getStatus()).isEqualTo(ClientFileGroup.Status.DOWNLOADED);
664         assertThat(clientFileGroup.getBuildId()).isEqualTo(/* BuildID generated by Ingress */ 3150);
665     }
666 
667     // A helper function to create a DataFilegroup.
createDataFileGroup( String groupName, String ownerPackage, int versionNumber, String[] fileId, int[] byteSize, String[] checksum, String[] url, DeviceNetworkPolicy deviceNetworkPolicy)668     private static DataFileGroup createDataFileGroup(
669             String groupName,
670             String ownerPackage,
671             int versionNumber,
672             String[] fileId,
673             int[] byteSize,
674             String[] checksum,
675             String[] url,
676             DeviceNetworkPolicy deviceNetworkPolicy) {
677         if (fileId.length != byteSize.length
678                 || fileId.length != checksum.length
679                 || fileId.length != url.length) {
680             throw new IllegalArgumentException();
681         }
682 
683         DataFileGroup.Builder dataFileGroupBuilder =
684                 DataFileGroup.newBuilder()
685                         .setGroupName(groupName)
686                         .setOwnerPackage(ownerPackage)
687                         .setFileGroupVersionNumber(versionNumber)
688                         .setDownloadConditions(
689                                 DownloadConditions.newBuilder()
690                                         .setDeviceNetworkPolicy(deviceNetworkPolicy));
691 
692         for (int i = 0; i < fileId.length; ++i) {
693             DataFile file =
694                     DataFile.newBuilder()
695                             .setFileId(fileId[i])
696                             .setByteSize(byteSize[i])
697                             .setChecksum(checksum[i])
698                             .setUrlToDownload(url[i])
699                             .build();
700             dataFileGroupBuilder.addFile(file);
701         }
702 
703         return dataFileGroupBuilder.build();
704     }
705 
706     /**
707      * Returns a MobileDataDownload instance for testing.
708      *
709      * @param context the context
710      * @param flags the flags
711      * @param fileGroupPopulators a list of FileGroupPopulator that will be added to the MDD
712      * @return a MobileDataDownload instance.
713      */
714     @NonNull
getMddForTesting( @onNull Context context, @NonNull Flags flags, @NonNull ImmutableList<FileGroupPopulator> fileGroupPopulators)715     private static MobileDataDownload getMddForTesting(
716             @NonNull Context context,
717             @NonNull Flags flags,
718             @NonNull ImmutableList<FileGroupPopulator> fileGroupPopulators) {
719         context = context.getApplicationContext();
720         SynchronousFileStorage fileStorage = MobileDataDownloadFactory.getFileStorage();
721         FileDownloader fileDownloader =
722                 MobileDataDownloadFactory.getFileDownloader(flags, fileStorage);
723         NetworkUsageMonitor networkUsageMonitor =
724                 new NetworkUsageMonitor(
725                         context,
726                         new TimeSource() {
727                             @Override
728                             public long currentTimeMillis() {
729                                 return System.currentTimeMillis();
730                             }
731 
732                             @Override
733                             public long elapsedRealtimeNanos() {
734                                 return SystemClock.elapsedRealtimeNanos();
735                             }
736                         });
737 
738         return MobileDataDownloadBuilder.newBuilder()
739                 .setContext(context)
740                 .setControlExecutor(MobileDataDownloadFactory.getControlExecutor())
741                 .setNetworkUsageMonitor(networkUsageMonitor)
742                 .setFileStorage(fileStorage)
743                 .setFileDownloaderSupplier(() -> fileDownloader)
744                 .addFileGroupPopulators(fileGroupPopulators)
745                 .setLoggerOptional(MobileDataDownloadFactory.getMddLogger(flags))
746                 // Use default MDD flags so that it does not need to access DeviceConfig
747                 // which is inaccessible from Unit Tests.
748                 .setFlagsOptional(
749                         Optional.of(new com.google.android.libraries.mobiledatadownload.Flags() {}))
750                 .build();
751     }
752 
753     // Returns MobileDataDownload using passed in encryption keys manifest url.
754     @NonNull
createMddForEncryptionKeys(String encryptionManifestFileUrl)755     private void createMddForEncryptionKeys(String encryptionManifestFileUrl)
756             throws ExecutionException, InterruptedException, TimeoutException {
757         doReturn(encryptionManifestFileUrl).when(mMockFlags).getMddEncryptionKeysManifestFileUrl();
758 
759         FileGroupPopulator fileGroupPopulator =
760                 MobileDataDownloadFactory.getEncryptionKeysManifestPopulator(
761                         mContext, mMockFlags, mFileStorage, mFileDownloader);
762 
763         mMdd =
764                 getMddForTesting(
765                         mContext,
766                         mMockFlags,
767                         // List of FileGroupPopulator that contains Measurement FileGroupPopulator
768                         // only.
769                         ImmutableList.of(fileGroupPopulator));
770 
771         // Calling handleTask directly to trigger the MDD's background download on wifi. This should
772         // be done in tests only.
773         mMdd.handleTask(TaskScheduler.WIFI_CHARGING_PERIODIC_TASK)
774                 .get(MAX_HANDLE_TASK_WAIT_TIME_SECS, SECONDS);
775     }
776 
777     // Returns MobileDataDownload using passed in enrollment manifest url.
778     @NonNull
createMddForEnrollment(String enrollmentManifestFileUrl, boolean getProto)779     private void createMddForEnrollment(String enrollmentManifestFileUrl, boolean getProto)
780             throws ExecutionException, InterruptedException, TimeoutException {
781         if (getProto) {
782             doReturn(enrollmentManifestFileUrl).when(mMockFlags).getMddEnrollmentManifestFileUrl();
783         } else {
784             doReturn(enrollmentManifestFileUrl).when(mMockFlags).getMeasurementManifestFileUrl();
785         }
786 
787         FileGroupPopulator fileGroupPopulator =
788                 MobileDataDownloadFactory.getMeasurementManifestPopulator(
789                         mMockFlags, mFileStorage, mFileDownloader, getProto);
790 
791         mMdd =
792                 getMddForTesting(
793                         mContext,
794                         mMockFlags,
795                         // List of FileGroupPopulator that contains Measurement FileGroupPopulator
796                         // only.
797                         ImmutableList.of(fileGroupPopulator));
798 
799         // Calling handleTask directly to trigger the MDD's background download on wifi. This should
800         // be done in tests only.
801         mMdd.handleTask(TaskScheduler.WIFI_CHARGING_PERIODIC_TASK)
802                 .get(MAX_HANDLE_TASK_WAIT_TIME_SECS, SECONDS);
803     }
804 
805     // Returns MobileDataDownload using passed in topics manifest url.
806     @NonNull
createMddForTopics(String topicsManifestFileUrl)807     private void createMddForTopics(String topicsManifestFileUrl)
808             throws ExecutionException, InterruptedException, TimeoutException {
809         doReturn(topicsManifestFileUrl).when(mMockFlags).getMddTopicsClassifierManifestFileUrl();
810 
811         FileGroupPopulator fileGroupPopulator =
812                 MobileDataDownloadFactory.getTopicsManifestPopulator(
813                         mMockFlags, mFileStorage, mFileDownloader);
814 
815         mMdd =
816                 getMddForTesting(
817                         mContext,
818                         mMockFlags,
819                         // List of FileGroupPopulator that contains Topics FileGroupPopulator only.
820                         ImmutableList.of(fileGroupPopulator));
821 
822         // Calling handleTask directly to trigger the MDD's background download on wifi. This should
823         // be done in tests only.
824         mMdd.handleTask(TaskScheduler.WIFI_CHARGING_PERIODIC_TASK)
825                 .get(MAX_HANDLE_TASK_WAIT_TIME_SECS, SECONDS);
826     }
827 
828     // Returns MobileDataDownload using passed in UI OTA manifest url.
829     @NonNull
createMddForUiOTA()830     private void createMddForUiOTA()
831             throws ExecutionException, InterruptedException, TimeoutException {
832         FileGroupPopulator fileGroupPopulator =
833                 MobileDataDownloadFactory.getUiOtaResourcesManifestPopulator(
834                         mMockFlags, mFileStorage, mFileDownloader);
835 
836         mMdd =
837                 getMddForTesting(
838                         mContext,
839                         mMockFlags,
840                         // List of FileGroupPopulator that contains UI OTA String FileGroupPopulator
841                         // only.
842                         ImmutableList.of(fileGroupPopulator));
843 
844         // Calling handleTask directly to trigger the MDD's background download on wifi. This should
845         // be done in tests only.
846         mMdd.handleTask(TaskScheduler.WIFI_CHARGING_PERIODIC_TASK)
847                 .get(MAX_HANDLE_TASK_WAIT_TIME_SECS, SECONDS);
848     }
849 
getNumEntriesInEncryptionKeysTable()850     private long getNumEntriesInEncryptionKeysTable() {
851         return DatabaseUtils.queryNumEntries(
852                 mDbHelper.getReadableDatabase(),
853                 EncryptionKeyTables.EncryptionKeyContract.TABLE,
854                 null);
855     }
856 
getNumEntriesInEnrollmentTable()857     private long getNumEntriesInEnrollmentTable() {
858         return DatabaseUtils.queryNumEntries(
859                 mDbHelper.getReadableDatabase(),
860                 EnrollmentTables.EnrollmentDataContract.TABLE,
861                 null);
862     }
863 
verifyEncryptionKeysFileGroup( ClientFileGroup clientFileGroup, int numberOfExpectedKeys)864     private void verifyEncryptionKeysFileGroup(
865             ClientFileGroup clientFileGroup, int numberOfExpectedKeys)
866             throws InterruptedException, ExecutionException {
867         expect.that(clientFileGroup.getGroupName()).isEqualTo(ENCRYPTION_KEYS_FILE_GROUP_NAME);
868         expect.that(clientFileGroup.getOwnerPackage()).isEqualTo(mContext.getPackageName());
869         // Number of enrollment ids with provided encryption keys.
870         expect.that(clientFileGroup.getFileCount()).isEqualTo(numberOfExpectedKeys);
871         expect.that(
872                         clientFileGroup.getFileList().stream()
873                                 .map(ClientConfigProto.ClientFile::getFileId)
874                                 .collect(Collectors.toList()))
875                 .containsExactly("E4.json", "ptb.json");
876         expect.that(clientFileGroup.getStatus()).isEqualTo(ClientFileGroup.Status.DOWNLOADED);
877 
878         doReturn(mMdd).when(() -> MobileDataDownloadFactory.getMdd(any(Flags.class)));
879 
880         EncryptionKeyDao encryptionKeyDao = new EncryptionKeyDao(mDbHelper);
881         EncryptionDataDownloadManager encryptionDataDownloadManager =
882                 new EncryptionDataDownloadManager(mMockFlags, encryptionKeyDao, mMockClock);
883 
884         // Verify encryption keys data file read from MDD and insert the data into the encryption
885         // keys database.
886         expect.that(encryptionDataDownloadManager.readAndInsertEncryptionDataFromMdd().get())
887                 .isEqualTo(EncryptionDataDownloadManager.DownloadStatus.SUCCESS);
888         expect.that(getNumEntriesInEncryptionKeysTable()).isEqualTo(numberOfExpectedKeys);
889     }
890 
verifyEnrollmentMddDownloadStatus( ClientFileGroup clientFileGroup, int fileGroupVersion)891     private void verifyEnrollmentMddDownloadStatus(
892             ClientFileGroup clientFileGroup, int fileGroupVersion) {
893         assertThat(clientFileGroup.getGroupName()).isEqualTo(ENROLLMENT_FILE_GROUP_NAME);
894         assertThat(clientFileGroup.getOwnerPackage()).isEqualTo(mContext.getPackageName());
895         assertThat(clientFileGroup.getFileCount()).isEqualTo(1);
896         assertThat(clientFileGroup.getStatus()).isEqualTo(ClientFileGroup.Status.DOWNLOADED);
897         assertThat(clientFileGroup.getVersionNumber()).isEqualTo(fileGroupVersion);
898     }
899 
setupEnrollmentDaoForTest()900     private EnrollmentDao setupEnrollmentDaoForTest() {
901         EnrollmentDao enrollmentDao = new EnrollmentDao(mContext, mDbHelper, mMockFlags);
902         doReturn(enrollmentDao).when(() -> EnrollmentDao.getInstance());
903         return enrollmentDao;
904     }
905 
setupEnrollmentDownloadManagerForTest()906     private EnrollmentDataDownloadManager setupEnrollmentDownloadManagerForTest() {
907         EnrollmentDataDownloadManager enrollmentDataDownloadManager =
908                 new EnrollmentDataDownloadManager(mContext, mMockFlags);
909 
910         EncryptionKeyDao encryptionKeyDao = new EncryptionKeyDao(mDbHelper);
911         doReturn(encryptionKeyDao).when(EncryptionKeyDao::getInstance);
912         return enrollmentDataDownloadManager;
913     }
914 
verifyMeasurementFileGroup( ClientFileGroup clientFileGroup, int fileGroupVersion, int enrollmentEntries)915     private void verifyMeasurementFileGroup(
916             ClientFileGroup clientFileGroup, int fileGroupVersion, int enrollmentEntries)
917             throws InterruptedException, ExecutionException {
918         verifyMeasurementFileGroup(
919                 clientFileGroup,
920                 fileGroupVersion,
921                 enrollmentEntries,
922                 /* clearExistingData= */ true,
923                 /* clearDownloadedData= */ true);
924     }
925 
verifyMeasurementFileGroup( ClientFileGroup clientFileGroup, int fileGroupVersion, int enrollmentEntries, boolean clearExistingData, boolean clearDownloadedData)926     private void verifyMeasurementFileGroup(
927             ClientFileGroup clientFileGroup,
928             int fileGroupVersion,
929             int enrollmentEntries,
930             boolean clearExistingData,
931             boolean clearDownloadedData)
932             throws InterruptedException, ExecutionException {
933         verifyEnrollmentMddDownloadStatus(clientFileGroup, fileGroupVersion);
934 
935         doReturn(mMdd).when(() -> MobileDataDownloadFactory.getMdd(any(Flags.class)));
936 
937         EnrollmentDao enrollmentDao = setupEnrollmentDaoForTest();
938         if (clearExistingData) {
939             assertThat(enrollmentDao.deleteAll()).isTrue();
940             // Verify no enrollment data after table cleared.
941             assertThat(getNumEntriesInEnrollmentTable()).isEqualTo(0);
942         }
943 
944         EnrollmentDataDownloadManager enrollmentDataDownloadManager =
945                 setupEnrollmentDownloadManagerForTest();
946         // Verify enrollment data file read from MDD and insert the data into the enrollment
947         // database.
948         assertThat(enrollmentDataDownloadManager.readAndInsertEnrollmentDataFromMdd().get())
949                 .isEqualTo(SUCCESS);
950         assertThat(getNumEntriesInEnrollmentTable()).isEqualTo(enrollmentEntries);
951         if (clearDownloadedData) {
952             assertThat(enrollmentDao.deleteAll()).isTrue();
953         }
954     }
955 
mockMddFlags()956     private void mockMddFlags() {
957         mocker.mockGetFlags(mMockFlags);
958 
959         doReturn(2).when(mMockFlags).getDownloaderMaxDownloadThreads();
960         doReturn(false).when(mMockFlags).getEncryptionKeyNewEnrollmentFetchKillSwitch();
961         doReturn(Flags.ENCRYPTION_KEY_NETWORK_CONNECT_TIMEOUT_MS)
962                 .when(mMockFlags)
963                 .getEncryptionKeyNetworkConnectTimeoutMs();
964         doReturn(Flags.ENCRYPTION_KEY_NETWORK_READ_TIMEOUT_MS)
965                 .when(mMockFlags)
966                 .getEncryptionKeyNetworkReadTimeoutMs();
967     }
968 
overridingMddLoggingLevel(String loggingLevel)969     private static void overridingMddLoggingLevel(String loggingLevel) {
970         ShellUtils.runShellCommand("setprop log.tag.MDD %s", loggingLevel);
971     }
972 }
973