1 /*
2  * Copyright (C) 2017 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 android.telephony.embms.cts;
18 
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertNotNull;
21 import static org.junit.Assert.assertTrue;
22 import static org.junit.Assert.fail;
23 
24 import android.content.BroadcastReceiver;
25 import android.content.ContentResolver;
26 import android.content.Context;
27 import android.content.Intent;
28 import android.content.IntentFilter;
29 import android.net.Uri;
30 import android.os.Bundle;
31 import android.os.Handler;
32 import android.telephony.MbmsDownloadSession;
33 import android.telephony.cts.embmstestapp.CtsDownloadService;
34 import android.telephony.mbms.DownloadRequest;
35 import android.telephony.mbms.MbmsDownloadReceiver;
36 import android.telephony.mbms.UriPathPair;
37 import android.telephony.mbms.vendor.VendorUtils;
38 
39 import java.io.File;
40 import java.util.ArrayList;
41 import java.util.List;
42 import java.util.Objects;
43 import java.util.concurrent.BlockingQueue;
44 import java.util.concurrent.LinkedBlockingQueue;
45 import java.util.concurrent.TimeUnit;
46 import java.util.stream.Collectors;
47 import org.junit.After;
48 import org.junit.Before;
49 import org.junit.Test;
50 
51 public class MbmsDownloadReceiverTest extends MbmsDownloadTestBase {
52     private static final String CTS_BROADCAST_PERMISSION =
53             "android.telephony.embms.cts.permission.TEST_BROADCAST";
54     private static final String TEST_SERVICE_ID = "service_id";
55 
56     public static final String APP_INTENT_ACTION =
57             "android.telephony.embms.cts.ACTION_TEST_DOWNLOAD_COMPLETE";
58 
59     public static class AppIntentCapture {
60         private final BlockingQueue<Intent> mReceivedIntent = new LinkedBlockingQueue<>();
61         private final BroadcastReceiver mAppIntentReceiver = new BroadcastReceiver() {
62             @Override
63             public void onReceive(Context context, Intent intent) {
64                 mReceivedIntent.add(intent);
65             }
66         };
67         private Context mContext;
68 
AppIntentCapture(Context context, Handler handler)69         public AppIntentCapture(Context context, Handler handler) {
70             mContext = context;
71             IntentFilter filter = new IntentFilter(APP_INTENT_ACTION);
72             mContext.registerReceiver(mAppIntentReceiver, filter, null, handler,
73                     Context.RECEIVER_EXPORTED);
74         }
75 
getIntent()76         public Intent getIntent() {
77             return getIntent(true);
78         }
79 
getIntent(boolean unregister)80         public Intent getIntent(boolean unregister) {
81             try {
82                 Intent result = mReceivedIntent.poll(ASYNC_TIMEOUT, TimeUnit.MILLISECONDS);
83                 if (unregister) {
84                     mContext.unregisterReceiver(mAppIntentReceiver);
85                 }
86                 return result;
87             } catch (InterruptedException e) {
88                 fail("test was interrupted");
89                 return null;
90             }
91         }
92 
getIntents(int numExpected)93         public List<Intent> getIntents(int numExpected) {
94             ArrayList<Intent> result = new ArrayList<>(numExpected);
95             for (int i = 0; i < numExpected; i++) {
96                 result.add(getIntent(false));
97             }
98             mContext.unregisterReceiver(mAppIntentReceiver);
99             return result;
100         }
101     }
102 
103     private MbmsDownloadReceiver mReceiver;
104     private File tempFileRootDir;
105     private String tempFileRootDirPath;
106     private DownloadRequest testDownloadRequest;
107 
108     @Before
setUp()109     public void setUp() throws Exception {
110         super.setUp();
111         testDownloadRequest = downloadRequestTemplate
112                 .setAppIntent(new Intent(APP_INTENT_ACTION))
113                 .build();
114         mReceiver = new MbmsDownloadReceiver();
115         IntentFilter filter = new IntentFilter();
116         filter.addAction(VendorUtils.ACTION_DOWNLOAD_RESULT_INTERNAL);
117         filter.addAction(VendorUtils.ACTION_CLEANUP);
118         filter.addAction(VendorUtils.ACTION_FILE_DESCRIPTOR_REQUEST);
119         mContext.registerReceiver(mReceiver, filter, Context.RECEIVER_EXPORTED);
120         tempFileRootDir = new File(mContext.getFilesDir(), "CtsTestDir");
121         tempFileRootDir.mkdir();
122         tempFileRootDirPath = tempFileRootDir.getCanonicalPath();
123         try {
124             mDownloadSession.setTempFileRootDirectory(tempFileRootDir);
125         } catch (IllegalStateException e) {
126             tearDown();
127             throw e;
128         }
129     }
130 
131     @After
tearDown()132     public void tearDown() throws Exception {
133         recursiveDelete(tempFileRootDir);
134         tempFileRootDir = null;
135         super.tearDown();
136     }
137 
138     @Test
testMalformedIntents()139     public void testMalformedIntents() throws Exception {
140         Intent downloadCompleteIntent = new Intent(VendorUtils.ACTION_DOWNLOAD_RESULT_INTERNAL);
141         sendBroadcastAndValidate(downloadCompleteIntent,
142                 MbmsDownloadReceiver.RESULT_MALFORMED_INTENT);
143 
144         Intent fdRequestIntent = new Intent(VendorUtils.ACTION_FILE_DESCRIPTOR_REQUEST);
145         sendBroadcastAndValidate(fdRequestIntent,
146                 MbmsDownloadReceiver.RESULT_MALFORMED_INTENT);
147 
148         Intent cleanupIntent = new Intent(VendorUtils.ACTION_CLEANUP);
149         sendBroadcastAndValidate(cleanupIntent,
150                 MbmsDownloadReceiver.RESULT_MALFORMED_INTENT);
151     }
152 
153     @Test
testBadTempFileDirectory()154     public void testBadTempFileDirectory() throws Exception {
155         Intent cleanupIntent = new Intent(VendorUtils.ACTION_CLEANUP);
156         populateIntentWithCommonFields(cleanupIntent);
157         cleanupIntent.putParcelableArrayListExtra(VendorUtils.EXTRA_TEMP_FILES_IN_USE,
158                 new ArrayList<>(0));
159         cleanupIntent.putExtra(VendorUtils.EXTRA_TEMP_FILE_ROOT, "this is not a directory path");
160         sendBroadcastAndValidate(cleanupIntent,
161                 MbmsDownloadReceiver.RESULT_BAD_TEMP_FILE_ROOT);
162     }
163 
164     @Test
testDownloadFailureIntent()165     public void testDownloadFailureIntent() throws Exception {
166         Intent intentForReceiverTest = new Intent(VendorUtils.ACTION_DOWNLOAD_RESULT_INTERNAL);
167         populateIntentWithCommonFields(intentForReceiverTest);
168         intentForReceiverTest.putExtra(MbmsDownloadSession.EXTRA_MBMS_DOWNLOAD_RESULT,
169                 MbmsDownloadSession.RESULT_CANCELLED);
170         intentForReceiverTest.putExtra(MbmsDownloadSession.EXTRA_MBMS_DOWNLOAD_REQUEST,
171                 testDownloadRequest);
172 
173         AppIntentCapture intentCaptor = new AppIntentCapture(mContext, mHandler);
174 
175         sendBroadcastAndValidate(intentForReceiverTest, MbmsDownloadReceiver.RESULT_OK);
176         Intent receivedIntent = intentCaptor.getIntent();
177 
178         assertEquals(MbmsDownloadSession.RESULT_CANCELLED,
179                 receivedIntent.getIntExtra(MbmsDownloadSession.EXTRA_MBMS_DOWNLOAD_RESULT, -1));
180 
181         assertEquals(testDownloadRequest,
182                 receivedIntent.getParcelableExtra(MbmsDownloadSession.EXTRA_MBMS_DOWNLOAD_REQUEST));
183     }
184 
185     @Test
testBadDownloadToken()186     public void testBadDownloadToken() {
187         // Set up a perfectly valid download completion intent, and expect it to fail because the
188         // download token hasn't been written.
189         Intent intentForReceiverTest = new Intent(VendorUtils.ACTION_DOWNLOAD_RESULT_INTERNAL);
190         populateIntentWithCommonFields(intentForReceiverTest);
191         intentForReceiverTest.putExtra(MbmsDownloadSession.EXTRA_MBMS_DOWNLOAD_RESULT,
192                 MbmsDownloadSession.RESULT_SUCCESSFUL);
193         intentForReceiverTest.putExtra(MbmsDownloadSession.EXTRA_MBMS_DOWNLOAD_REQUEST,
194                 testDownloadRequest);
195         intentForReceiverTest.putExtra(MbmsDownloadSession.EXTRA_MBMS_FILE_INFO,
196                 CtsDownloadService.FILE_INFO_1);
197         intentForReceiverTest.putExtra(VendorUtils.EXTRA_FINAL_URI,
198                 Uri.fromFile(new File(new File(tempFileRootDir, TEST_SERVICE_ID), "file1")));
199 
200         sendBroadcastAndValidate(intentForReceiverTest,
201                 MbmsDownloadReceiver.RESULT_MALFORMED_INTENT);
202     }
203 
204     @Test
testRequestNoFileDescriptors()205     public void testRequestNoFileDescriptors() throws Exception {
206         Intent fdRequestIntent = new Intent(VendorUtils.ACTION_FILE_DESCRIPTOR_REQUEST);
207         populateIntentWithCommonFields(fdRequestIntent);
208 
209         Bundle b = sendBroadcastAndValidate(fdRequestIntent, MbmsDownloadReceiver.RESULT_OK);
210         assertTrue(b == null || b.isEmpty());
211     }
212 
213     @Test
testRequestNewFileDescriptors()214     public void testRequestNewFileDescriptors() throws Exception {
215         Intent fdRequestIntent = new Intent(VendorUtils.ACTION_FILE_DESCRIPTOR_REQUEST);
216         populateIntentWithCommonFields(fdRequestIntent);
217         fdRequestIntent.putExtra(VendorUtils.EXTRA_FD_COUNT, 5);
218 
219         Bundle result = sendBroadcastAndValidate(fdRequestIntent, MbmsDownloadReceiver.RESULT_OK);
220         List<UriPathPair> freeUris = result.getParcelableArrayList(VendorUtils.EXTRA_FREE_URI_LIST);
221         assertNotNull(freeUris);
222         assertEquals(5, freeUris.size());
223         for (UriPathPair pathPair : freeUris) {
224             assertEquals(ContentResolver.SCHEME_CONTENT, pathPair.getContentUri().getScheme());
225             assertEquals(ContentResolver.SCHEME_FILE, pathPair.getFilePathUri().getScheme());
226         }
227     }
228 
229     @Test
testRequestRefreshedFileDescriptors()230     public void testRequestRefreshedFileDescriptors() throws Exception {
231         // Set up a few temp files that we can request again
232         Intent fdRequestIntent = new Intent(VendorUtils.ACTION_FILE_DESCRIPTOR_REQUEST);
233         populateIntentWithCommonFields(fdRequestIntent);
234         fdRequestIntent.putExtra(VendorUtils.EXTRA_FD_COUNT, 2);
235 
236         Bundle result = sendBroadcastAndValidate(fdRequestIntent, MbmsDownloadReceiver.RESULT_OK);
237         List<UriPathPair> freeUris = result.getParcelableArrayList(VendorUtils.EXTRA_FREE_URI_LIST);
238 
239         Intent fdRefreshIntent = new Intent(VendorUtils.ACTION_FILE_DESCRIPTOR_REQUEST);
240         populateIntentWithCommonFields(fdRefreshIntent);
241         fdRefreshIntent.putParcelableArrayListExtra(VendorUtils.EXTRA_PAUSED_LIST,
242                 new ArrayList<>(freeUris.stream().map(UriPathPair::getFilePathUri)
243                         .collect(Collectors.toList())));
244         Bundle result2 = sendBroadcastAndValidate(fdRefreshIntent, MbmsDownloadReceiver.RESULT_OK);
245         List<UriPathPair> refreshUris =
246                 result2.getParcelableArrayList(VendorUtils.EXTRA_PAUSED_URI_LIST);
247         assertEquals(freeUris.size(), refreshUris.size());
248         for (UriPathPair pathPair : refreshUris) {
249             assertTrue(freeUris.stream()
250                     .anyMatch((originalPair) ->
251                             originalPair.getFilePathUri().equals(pathPair.getFilePathUri())));
252         }
253     }
254 
sendBroadcastAndValidate(Intent intent, int expectedCode)255     private Bundle sendBroadcastAndValidate(Intent intent, int expectedCode) {
256         BlockingQueue<Bundle> receivedExtras = new LinkedBlockingQueue<>();
257         BlockingQueue<Integer> receivedCode = new LinkedBlockingQueue<>();
258         mContext.sendOrderedBroadcast(intent, CTS_BROADCAST_PERMISSION,
259                 new BroadcastReceiver() {
260                     @Override
261                     public void onReceive(Context context, Intent intent) {
262                         receivedExtras.add(getResultExtras(true));
263                         receivedCode.add(getResultCode());
264                     }
265                 }, mHandler, -1, null, null);
266 
267         try {
268             assertEquals(expectedCode,
269                     (int) receivedCode.poll(ASYNC_TIMEOUT, TimeUnit.MILLISECONDS));
270             return receivedExtras.poll(ASYNC_TIMEOUT, TimeUnit.MILLISECONDS);
271         } catch (InterruptedException e) {
272             fail("Test interrupted");
273             return null;
274         }
275     }
276 
bundleEquals(Bundle a, Bundle b)277     private boolean bundleEquals(Bundle a, Bundle b) {
278         if (a == null && b == null) {
279             return true;
280         }
281         if (a == null || b == null) {
282             return false;
283         }
284         for (String aKey : a.keySet()) {
285             if (!Objects.equals(a.get(aKey), b.get(aKey))) {
286                 return false;
287             }
288         }
289 
290         for (String bKey : b.keySet()) {
291             if (!Objects.equals(b.get(bKey), a.get(bKey))) {
292                 return false;
293             }
294         }
295 
296         return true;
297     }
298 
populateIntentWithCommonFields(Intent intent)299     private void populateIntentWithCommonFields(Intent intent) {
300         intent.putExtra(VendorUtils.EXTRA_SERVICE_ID, TEST_SERVICE_ID);
301         intent.putExtra(VendorUtils.EXTRA_TEMP_FILE_ROOT, tempFileRootDirPath);
302     }
303 
304 }
305