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 androidx.test.InstrumentationRegistry.getContext;
20 
21 import static org.junit.Assert.assertEquals;
22 import static org.junit.Assert.assertNotNull;
23 import static org.junit.Assert.assertTrue;
24 import static org.junit.Assert.fail;
25 import static org.junit.Assume.assumeTrue;
26 
27 import android.annotation.Nullable;
28 import android.content.ComponentName;
29 import android.content.Context;
30 import android.content.Intent;
31 import android.content.ServiceConnection;
32 import android.net.Uri;
33 import android.os.Bundle;
34 import android.os.Handler;
35 import android.os.HandlerThread;
36 import android.os.IBinder;
37 import android.os.RemoteException;
38 import android.platform.test.flag.junit.CheckFlagsRule;
39 import android.platform.test.flag.junit.DeviceFlagsValueProvider;
40 import android.telephony.MbmsDownloadSession;
41 import android.telephony.cts.embmstestapp.CtsDownloadService;
42 import android.telephony.cts.embmstestapp.ICtsDownloadMiddlewareControl;
43 import android.telephony.mbms.DownloadRequest;
44 import android.telephony.mbms.FileServiceInfo;
45 import android.telephony.mbms.MbmsDownloadSessionCallback;
46 import android.util.Log;
47 
48 import com.android.internal.os.SomeArgs;
49 import com.android.internal.telephony.flags.Flags;
50 
51 import org.junit.After;
52 import org.junit.Before;
53 import org.junit.Rule;
54 
55 import java.io.File;
56 import java.util.List;
57 import java.util.concurrent.BlockingQueue;
58 import java.util.concurrent.CountDownLatch;
59 import java.util.concurrent.Executor;
60 import java.util.concurrent.LinkedBlockingQueue;
61 import java.util.concurrent.TimeUnit;
62 import java.util.stream.Collectors;
63 
64 public class MbmsDownloadTestBase {
65     @Rule
66     public final CheckFlagsRule mCheckFlagsRule =
67             DeviceFlagsValueProvider.createCheckFlagsRule();
68 
69     protected static final int ASYNC_TIMEOUT = 10000;
70 
71     protected static class TestCallback extends MbmsDownloadSessionCallback {
72         private final BlockingQueue<SomeArgs> mErrorCalls = new LinkedBlockingQueue<>();
73         private final BlockingQueue<SomeArgs> mFileServicesUpdatedCalls =
74                 new LinkedBlockingQueue<>();
75         private final BlockingQueue<SomeArgs> mMiddlewareReadyCalls = new LinkedBlockingQueue<>();
76         private int mNumErrorCalls = 0;
77 
78         @Override
onError(int errorCode, @Nullable String message)79         public void onError(int errorCode, @Nullable String message) {
80             mNumErrorCalls += 1;
81             SomeArgs args = SomeArgs.obtain();
82             args.arg1 = errorCode;
83             args.arg2 = message;
84             mErrorCalls.add(args);
85             Log.i(MbmsDownloadTestBase.class.getSimpleName(),
86                     "Got error: " + errorCode + ": " + message);
87         }
88 
89         @Override
onFileServicesUpdated(List<FileServiceInfo> services)90         public void onFileServicesUpdated(List<FileServiceInfo> services) {
91             SomeArgs args = SomeArgs.obtain();
92             args.arg1 = services;
93             mFileServicesUpdatedCalls.add(args);
94         }
95 
96         @Override
onMiddlewareReady()97         public void onMiddlewareReady() {
98             mMiddlewareReadyCalls.add(SomeArgs.obtain());
99         }
100 
waitOnError()101         public SomeArgs waitOnError() {
102             try {
103                 return mErrorCalls.poll(ASYNC_TIMEOUT, TimeUnit.MILLISECONDS);
104             } catch (InterruptedException e) {
105                 return null;
106             }
107         }
108 
waitOnMiddlewareReady()109         public boolean waitOnMiddlewareReady() {
110             try {
111                 return mMiddlewareReadyCalls.poll(ASYNC_TIMEOUT, TimeUnit.MILLISECONDS) != null;
112             } catch (InterruptedException e) {
113                 return false;
114             }
115         }
116 
waitOnFileServicesUpdated()117         public SomeArgs waitOnFileServicesUpdated() {
118             try {
119                 return mFileServicesUpdatedCalls.poll(ASYNC_TIMEOUT, TimeUnit.MILLISECONDS);
120             } catch (InterruptedException e) {
121                 return null;
122             }
123         }
124 
getNumErrorCalls()125         public int getNumErrorCalls() {
126             return mNumErrorCalls;
127         }
128     }
129 
130     DownloadRequest.Builder downloadRequestTemplate;
131     Uri destinationDirectoryUri;
132 
133     Context mContext;
134     HandlerThread mHandlerThread;
135     Handler mHandler;
136     Executor mCallbackExecutor;
137     ICtsDownloadMiddlewareControl mMiddlewareControl;
138     MbmsDownloadSession mDownloadSession;
139     TestCallback mCallback = new TestCallback();
140 
141     @Before
setUp()142     public void setUp() throws Exception {
143         if (Flags.enforceTelephonyFeatureMappingForPublicApis()) {
144             assumeTrue(MbmsUtil.hasMbmsFeature());
145         }
146 
147         mContext = getContext();
148         mHandlerThread = new HandlerThread("EmbmsCtsTestWorker");
149         mHandlerThread.start();
150         mHandler = new Handler(mHandlerThread.getLooper());
151         mCallbackExecutor = mHandler::post;
152         mCallback = new TestCallback();
153 
154         File destinationDirectory = new File(mContext.getFilesDir(), "downloads");
155         destinationDirectory.mkdirs();
156         destinationDirectoryUri = Uri.fromFile(destinationDirectory);
157         downloadRequestTemplate = new DownloadRequest.Builder(
158                 CtsDownloadService.SOURCE_URI_1, destinationDirectoryUri)
159                 .setServiceInfo(CtsDownloadService.FILE_SERVICE_INFO);
160         getControlBinder();
161         setupDownloadSession();
162     }
163 
164     @After
tearDown()165     public void tearDown() throws Exception {
166         if (Flags.enforceTelephonyFeatureMappingForPublicApis()) {
167             if (!MbmsUtil.hasMbmsFeature()) {
168                 return;
169             }
170         }
171 
172         mHandlerThread.quit();
173         mDownloadSession.close();
174         mMiddlewareControl.reset();
175     }
176 
setupDownloadSession()177     private void setupDownloadSession() throws Exception {
178         mDownloadSession = MbmsDownloadSession.create(
179                 mContext, mCallbackExecutor, mCallback);
180         assertNotNull(mDownloadSession);
181         assertTrue(mCallback.waitOnMiddlewareReady());
182         assertEquals(0, mCallback.getNumErrorCalls());
183         Bundle initializeCall =  mMiddlewareControl.getDownloadSessionCalls().get(0);
184         assertEquals(CtsDownloadService.METHOD_INITIALIZE,
185                 initializeCall.getString(CtsDownloadService.METHOD_NAME));
186     }
187 
getControlBinder()188     private void getControlBinder() throws InterruptedException {
189         Intent bindIntent = new Intent(CtsDownloadService.CONTROL_INTERFACE_ACTION);
190         bindIntent.setComponent(CtsDownloadService.CONTROL_INTERFACE_COMPONENT);
191         final CountDownLatch bindLatch = new CountDownLatch(1);
192 
193         boolean success = mContext.bindService(bindIntent, new ServiceConnection() {
194             @Override
195             public void onServiceConnected(ComponentName name, IBinder service) {
196                 mMiddlewareControl = ICtsDownloadMiddlewareControl.Stub.asInterface(service);
197                 bindLatch.countDown();
198             }
199 
200             @Override
201             public void onServiceDisconnected(ComponentName name) {
202                 mMiddlewareControl = null;
203             }
204         }, Context.BIND_AUTO_CREATE);
205         if (!success) {
206             fail("Failed to get control interface -- bind error");
207         }
208         bindLatch.await(ASYNC_TIMEOUT, TimeUnit.MILLISECONDS);
209     }
210 
getMiddlewareCalls(String methodName)211     protected List<Bundle> getMiddlewareCalls(String methodName) throws RemoteException {
212         return (mMiddlewareControl.getDownloadSessionCalls()).stream()
213                 .filter((elem) -> elem.getString(CtsDownloadService.METHOD_NAME).equals(methodName))
214                 .collect(Collectors.toList());
215     }
216 
recursiveDelete(File f)217     protected static void recursiveDelete(File f) {
218         if (f != null) {
219             if (f.isDirectory()) {
220                 for (File f1 : f.listFiles()) {
221                     recursiveDelete(f1);
222                 }
223             }
224             f.delete();
225         }
226     }
227 }