• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.ondevicepersonalization.services.download;
18 
19 import static org.junit.Assert.assertArrayEquals;
20 import static org.junit.Assert.assertEquals;
21 import static org.junit.Assert.assertTrue;
22 import static org.junit.Assert.fail;
23 import static org.mockito.Mockito.spy;
24 import static org.mockito.Mockito.when;
25 
26 import android.adservices.ondevicepersonalization.DownloadCompletedOutputParcel;
27 import android.content.ComponentName;
28 import android.content.Context;
29 import android.database.Cursor;
30 
31 import androidx.test.core.app.ApplicationProvider;
32 
33 import com.android.compatibility.common.util.ShellUtils;
34 import com.android.dx.mockito.inline.extended.ExtendedMockito;
35 import com.android.modules.utils.build.SdkLevel;
36 import com.android.modules.utils.testing.ExtendedMockitoRule;
37 import com.android.odp.module.common.PackageUtils;
38 import com.android.ondevicepersonalization.services.Flags;
39 import com.android.ondevicepersonalization.services.FlagsFactory;
40 import com.android.ondevicepersonalization.services.PhFlagsTestUtil;
41 import com.android.ondevicepersonalization.services.data.OnDevicePersonalizationDbHelper;
42 import com.android.ondevicepersonalization.services.data.vendor.OnDevicePersonalizationVendorDataDao;
43 import com.android.ondevicepersonalization.services.data.vendor.VendorData;
44 import com.android.ondevicepersonalization.services.data.vendor.VendorDataContract;
45 import com.android.ondevicepersonalization.services.download.mdd.MobileDataDownloadFactory;
46 import com.android.ondevicepersonalization.services.download.mdd.OnDevicePersonalizationFileGroupPopulator;
47 
48 import com.google.android.libraries.mobiledatadownload.DownloadFileGroupRequest;
49 import com.google.android.libraries.mobiledatadownload.MobileDataDownload;
50 import com.google.android.libraries.mobiledatadownload.RemoveFileGroupsByFilterRequest;
51 import com.google.android.libraries.mobiledatadownload.file.SynchronousFileStorage;
52 import com.google.common.util.concurrent.FutureCallback;
53 import com.google.common.util.concurrent.ListeningExecutorService;
54 import com.google.common.util.concurrent.MoreExecutors;
55 import com.google.common.util.concurrent.SettableFuture;
56 
57 import org.junit.After;
58 import org.junit.Before;
59 import org.junit.Rule;
60 import org.junit.Test;
61 import org.junit.runner.RunWith;
62 import org.junit.runners.Parameterized;
63 import org.mockito.Spy;
64 import org.mockito.quality.Strictness;
65 
66 import java.util.ArrayList;
67 import java.util.Arrays;
68 import java.util.Base64;
69 import java.util.Collection;
70 import java.util.List;
71 import java.util.concurrent.CountDownLatch;
72 
73 @RunWith(Parameterized.class)
74 public class OnDevicePersonalizationDataProcessingAsyncCallableTests {
75     private final Context mContext = ApplicationProvider.getApplicationContext();
76     private OnDevicePersonalizationFileGroupPopulator mPopulator;
77     private MobileDataDownload mMdd;
78     private String mPackageName;
79     private SynchronousFileStorage mFileStorage;
80     private final VendorData mContent1 = new VendorData.Builder()
81             .setKey("key1")
82             .setData("dGVzdGRhdGEx".getBytes())
83             .build();
84 
85     private final VendorData mContent2 = new VendorData.Builder()
86             .setKey("key2")
87             .setData("dGVzdGRhdGEy".getBytes())
88             .build();
89 
90     private final VendorData mContentExtra = new VendorData.Builder()
91             .setKey("keyExtra")
92             .setData("extra".getBytes())
93             .build();
94 
95     private ComponentName mService;
96     private FutureCallback mTestCallback;
97     private boolean mCallbackSuccess;
98     private boolean mCallbackFailure;
99     private CountDownLatch mLatch;
100     @Parameterized.Parameter(0)
101     public boolean mIsSipFeatureEnabled;
102 
103     @Parameterized.Parameters
data()104     public static Collection<Object[]> data() {
105         return Arrays.asList(
106                 new Object[][] {
107                         {true}, {false}
108                 }
109         );
110     }
111 
112     @Spy
113     private Flags mSpyFlags = spy(FlagsFactory.getFlags());
114 
115     @Rule
116     public final ExtendedMockitoRule mExtendedMockitoRule = new ExtendedMockitoRule.Builder(this)
117             .mockStatic(FlagsFactory.class)
118             .setStrictness(Strictness.LENIENT)
119             .build();
120 
121     @Before
setup()122     public void setup() throws Exception {
123         mPackageName = mContext.getPackageName();
124         mService = ComponentName.createRelative(
125                 mPackageName, "com.test.TestPersonalizationService");
126         mFileStorage = MobileDataDownloadFactory.getFileStorage(mContext);
127         // Use direct executor to keep all work sequential for the tests
128         ListeningExecutorService executorService = MoreExecutors.newDirectExecutorService();
129         mMdd = MobileDataDownloadFactory.getMdd(mContext, executorService, executorService);
130         mPopulator = new OnDevicePersonalizationFileGroupPopulator(mContext);
131         RemoveFileGroupsByFilterRequest request =
132                 RemoveFileGroupsByFilterRequest.newBuilder().build();
133         MobileDataDownloadFactory.getMdd(mContext).removeFileGroupsByFilter(request).get();
134 
135         // Initialize the DB as a test instance
136         OnDevicePersonalizationVendorDataDao.getInstanceForTest(mContext, mService,
137                 PackageUtils.getCertDigest(mContext, mPackageName));
138 
139         PhFlagsTestUtil.setUpDeviceConfigPermissions();
140         ExtendedMockito.doReturn(mSpyFlags).when(FlagsFactory::getFlags);
141         when(mSpyFlags.isSharedIsolatedProcessFeatureEnabled())
142                 .thenReturn(SdkLevel.isAtLeastU() && mIsSipFeatureEnabled);
143         ShellUtils.runShellCommand("settings put global hidden_api_policy 1");
144 
145         mLatch = new CountDownLatch(1);
146         mTestCallback = new FutureCallback<DownloadCompletedOutputParcel>() {
147             @Override
148             public void onSuccess(DownloadCompletedOutputParcel result) {
149                 mCallbackSuccess = true;
150                 mLatch.countDown();
151             }
152 
153             @Override
154             public void onFailure(Throwable t) {
155                 mCallbackFailure = true;
156                 mLatch.countDown();
157             }
158         };
159     }
160 
161     @Test
testRun()162     public void testRun() throws Exception {
163         OnDevicePersonalizationVendorDataDao dao =
164                 OnDevicePersonalizationVendorDataDao.getInstanceForTest(mContext, mService,
165                         PackageUtils.getCertDigest(mContext, mPackageName));
166         var originalIsolatedServiceAllowList =
167                 FlagsFactory.getFlags().getIsolatedServiceAllowList();
168         PhFlagsTestUtil.setIsolatedServiceAllowList(
169                 "com.android.ondevicepersonalization.servicetests");
170         mPopulator.refreshFileGroups(mMdd).get();
171         PhFlagsTestUtil.setIsolatedServiceAllowList(originalIsolatedServiceAllowList);
172         String fileGroupName = OnDevicePersonalizationFileGroupPopulator.createPackageFileGroupName(
173                 mPackageName, mContext);
174         // Trigger the download immediately.
175         mMdd.downloadFileGroup(
176                 DownloadFileGroupRequest.newBuilder().setGroupName(fileGroupName).build()).get();
177 
178         List<VendorData> existingData = new ArrayList<>();
179         existingData.add(mContentExtra);
180         List<String> retain = new ArrayList<>();
181         retain.add("keyExtra");
182         assertTrue(dao.batchUpdateOrInsertVendorDataTransaction(existingData, retain,
183                 100));
184 
185         OnDevicePersonalizationDataProcessingAsyncCallable callable =
186                 new OnDevicePersonalizationDataProcessingAsyncCallable(
187                         mPackageName, mContext, new TestInjector());
188 
189         callable.call();
190         mLatch.await();
191 
192         Cursor cursor = dao.readAllVendorData();
193         List<VendorData> vendorDataList = new ArrayList<>();
194         while (cursor.moveToNext()) {
195             String key = cursor.getString(
196                     cursor.getColumnIndexOrThrow(VendorDataContract.VendorDataEntry.KEY));
197 
198             byte[] data = cursor.getBlob(
199                     cursor.getColumnIndexOrThrow(VendorDataContract.VendorDataEntry.DATA));
200 
201             vendorDataList.add(new VendorData.Builder()
202                     .setKey(key)
203                     .setData(data)
204                     .build());
205         }
206         cursor.close();
207         assertEquals(3, vendorDataList.size());
208         for (VendorData data : vendorDataList) {
209             if (data.getKey().equals(mContent1.getKey())) {
210                 compareDataContent(mContent1, data, false);
211             } else if (data.getKey().equals(mContent2.getKey())) {
212                 compareDataContent(mContent2, data, true);
213             } else if (data.getKey().equals(mContentExtra.getKey())) {
214                 compareDataContent(mContentExtra, data, false);
215             } else {
216                 fail("Vendor data from DB contains unexpected key");
217             }
218         }
219     }
220 
221     @Test
testRunOldDataDownloaded()222     public void testRunOldDataDownloaded() throws Exception {
223         OnDevicePersonalizationVendorDataDao dao =
224                 OnDevicePersonalizationVendorDataDao.getInstanceForTest(mContext, mService,
225                         PackageUtils.getCertDigest(mContext, mPackageName));
226         var originalIsolatedServiceAllowList =
227                 FlagsFactory.getFlags().getIsolatedServiceAllowList();
228         PhFlagsTestUtil.setIsolatedServiceAllowList(
229                 "com.android.ondevicepersonalization.servicetests");
230         mPopulator.refreshFileGroups(mMdd).get();
231         PhFlagsTestUtil.setIsolatedServiceAllowList(originalIsolatedServiceAllowList);
232         String fileGroupName = OnDevicePersonalizationFileGroupPopulator.createPackageFileGroupName(
233                 mPackageName, mContext);
234         // Trigger the download immediately.
235         mMdd.downloadFileGroup(
236                 DownloadFileGroupRequest.newBuilder().setGroupName(fileGroupName).build()).get();
237 
238         List<VendorData> existingData = new ArrayList<>();
239         existingData.add(mContentExtra);
240         List<String> retain = new ArrayList<>();
241         retain.add("keyExtra");
242         assertTrue(dao.batchUpdateOrInsertVendorDataTransaction(existingData, retain,
243                 System.currentTimeMillis()));
244 
245         OnDevicePersonalizationDataProcessingAsyncCallable callable =
246                 new OnDevicePersonalizationDataProcessingAsyncCallable(
247                         mPackageName, mContext, new TestInjector());
248 
249         callable.call();
250         mLatch.await();
251 
252         Cursor cursor = dao.readAllVendorData();
253         List<VendorData> vendorDataList = new ArrayList<>();
254         while (cursor.moveToNext()) {
255             String key = cursor.getString(
256                     cursor.getColumnIndexOrThrow(VendorDataContract.VendorDataEntry.KEY));
257 
258             byte[] data = cursor.getBlob(
259                     cursor.getColumnIndexOrThrow(VendorDataContract.VendorDataEntry.DATA));
260 
261             vendorDataList.add(new VendorData.Builder()
262                     .setKey(key)
263                     .setData(data)
264                     .build());
265         }
266         cursor.close();
267         assertEquals(1, vendorDataList.size());
268         for (VendorData data : vendorDataList) {
269             if (data.getKey().equals(mContentExtra.getKey())) {
270                 compareDataContent(mContentExtra, data, false);
271             } else {
272                 fail("Vendor data from DB contains unexpected key");
273             }
274         }
275     }
276 
277     class TestInjector extends OnDevicePersonalizationDataProcessingAsyncCallable.Injector {
278         @Override
getFutureCallback( SettableFuture<Boolean> settableFuture)279         FutureCallback<DownloadCompletedOutputParcel> getFutureCallback(
280                 SettableFuture<Boolean> settableFuture) {
281             return mTestCallback;
282         }
283     }
284 
compareDataContent(VendorData expectedData, VendorData actualData, boolean base64)285     private void compareDataContent(VendorData expectedData, VendorData actualData,
286             boolean base64) {
287         assertEquals(expectedData.getKey(), actualData.getKey());
288         if (base64) {
289             assertArrayEquals(Base64.getDecoder().decode(expectedData.getData()),
290                     actualData.getData());
291         } else {
292             assertArrayEquals(expectedData.getData(), actualData.getData());
293         }
294     }
295 
296     @After
cleanup()297     public void cleanup() {
298         OnDevicePersonalizationDbHelper dbHelper =
299                 OnDevicePersonalizationDbHelper.getInstanceForTest(mContext);
300         dbHelper.getWritableDatabase().close();
301         dbHelper.getReadableDatabase().close();
302         dbHelper.close();
303     }
304 }
305