1 /*
2  * Copyright (C) 2019 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.ims.cts;
18 
19 import android.app.Service;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.os.Binder;
23 import android.os.IBinder;
24 import android.telephony.ims.ImsService;
25 import android.telephony.ims.feature.MmTelFeature;
26 import android.telephony.ims.feature.RcsFeature;
27 import android.telephony.ims.stub.ImsConfigImplBase;
28 import android.telephony.ims.stub.ImsFeatureConfiguration;
29 import android.telephony.ims.stub.ImsRegistrationImplBase;
30 import android.telephony.ims.stub.SipTransportImplBase;
31 import android.util.Log;
32 
33 
34 import androidx.annotation.Nullable;
35 
36 import java.util.concurrent.CountDownLatch;
37 import java.util.concurrent.TimeUnit;
38 
39 /**
40  * A Test ImsService that will verify ImsService functionality.
41  */
42 public class TestImsService extends Service {
43 
44     private static final String TAG = "GtsImsTestImsService";
45 
46     private static final TestImsRegistration sImsRegistrationImplBase =
47             new TestImsRegistration();
48 
49     private TestRcsFeature mTestRcsFeature;
50     private TestMmTelFeature mTestMmTelFeature;
51     private TestImsConfig mTestImsConfig;
52     private TestSipTransport mTestSipTransport;
53     private ImsService mTestImsService;
54     private boolean mIsEnabled = false;
55     private boolean mSetNullRcsBinding = false;
56     private boolean mIsSipTransportImplemented = false;
57     private long mCapabilities = 0;
58     private ImsFeatureConfiguration mFeatureConfig;
59     private final Object mLock = new Object();
60 
61     public static final int LATCH_FEATURES_READY = 0;
62     public static final int LATCH_ENABLE_IMS = 1;
63     public static final int LATCH_DISABLE_IMS = 2;
64     public static final int LATCH_CREATE_MMTEL = 3;
65     public static final int LATCH_CREATE_RCS = 4;
66     public static final int LATCH_REMOVE_MMTEL = 5;
67     public static final int LATCH_REMOVE_RCS = 6;
68     public static final int LATCH_MMTEL_READY = 7;
69     public static final int LATCH_RCS_READY = 8;
70     public static final int LATCH_MMTEL_CAP_SET = 9;
71     public static final int LATCH_RCS_CAP_SET = 10;
72     public static final int LATCH_UCE_LISTENER_SET = 11;
73     public static final int LATCH_UCE_REQUEST_PUBLISH = 12;
74     private static final int LATCH_MAX = 13;
75     protected static final CountDownLatch[] sLatches = new CountDownLatch[LATCH_MAX];
76     static {
77         for (int i = 0; i < LATCH_MAX; i++) {
78             sLatches[i] = new CountDownLatch(1);
79         }
80     }
81 
82     interface RemovedListener {
onRemoved()83         void onRemoved();
84     }
85     interface ReadyListener {
onReady()86         void onReady();
87     }
88     interface CapabilitiesSetListener {
onSet()89         void onSet();
90     }
91     interface RcsCapabilityExchangeEventListener {
onSet()92         void onSet();
93     }
94     interface DeviceCapPublishListener {
onPublish()95         void onPublish();
96     }
97 
98     // This is defined here instead TestImsService extending ImsService directly because the GTS
99     // tests were failing to run on pre-P devices. Not sure why, but TestImsService is loaded
100     // even if it isn't used.
101     private class ImsServiceUT extends ImsService {
102 
ImsServiceUT(Context context)103         ImsServiceUT(Context context) {
104             // As explained above, ImsServiceUT is created in order to get around classloader
105             // restrictions. Attach the base context from the wrapper ImsService.
106             if (getBaseContext() == null) {
107                 attachBaseContext(context);
108             }
109             mTestImsConfig = new TestImsConfig();
110             // For testing, just run on binder thread until required otherwise.
111             mTestSipTransport = new TestSipTransport(Runnable::run);
112         }
113 
114         @Override
querySupportedImsFeatures()115         public ImsFeatureConfiguration querySupportedImsFeatures() {
116             return getFeatureConfig();
117         }
118 
119         @Override
getImsServiceCapabilities()120         public long getImsServiceCapabilities() {
121             return mCapabilities;
122         }
123 
124         @Override
readyForFeatureCreation()125         public void readyForFeatureCreation() {
126             synchronized (mLock) {
127                 countDownLatch(LATCH_FEATURES_READY);
128             }
129         }
130 
131         @Override
enableIms(int slotId)132         public void enableIms(int slotId) {
133             synchronized (mLock) {
134                 countDownLatch(LATCH_ENABLE_IMS);
135                 setIsEnabled(true);
136             }
137         }
138 
139         @Override
disableIms(int slotId)140         public void disableIms(int slotId) {
141             synchronized (mLock) {
142                 countDownLatch(LATCH_DISABLE_IMS);
143                 setIsEnabled(false);
144             }
145         }
146 
147         @Override
createRcsFeature(int slotId)148         public RcsFeature createRcsFeature(int slotId) {
149             synchronized (mLock) {
150                 countDownLatch(LATCH_CREATE_RCS);
151                 mTestRcsFeature = new TestRcsFeature(getBaseContext(),
152                         //onReady
153                         () -> {
154                             synchronized (mLock) {
155                                 countDownLatch(LATCH_RCS_READY);
156                             }
157                         },
158                         //onRemoved
159                         () -> {
160                             synchronized (mLock) {
161                                 countDownLatch(LATCH_REMOVE_RCS);
162                                 mTestRcsFeature = null;
163                             }
164                         },
165                         //onCapabilitiesSet
166                         () -> {
167                             synchronized (mLock) {
168                                 countDownLatch(LATCH_RCS_CAP_SET);
169                             }
170                         },
171                         () -> {
172                             synchronized (mLock) {
173                                 countDownLatch(LATCH_UCE_LISTENER_SET);
174                         }
175                         });
176 
177                 // Setup UCE request listener
178                 mTestRcsFeature.setDeviceCapPublishListener(() -> {
179                     synchronized (mLock) {
180                         countDownLatch(LATCH_UCE_REQUEST_PUBLISH);
181                     }
182                 });
183 
184                 if (mSetNullRcsBinding) {
185                     return null;
186                 }
187                 return mTestRcsFeature;
188             }
189         }
190 
191         @Override
getConfig(int slotId)192         public ImsConfigImplBase getConfig(int slotId) {
193             return mTestImsConfig;
194         }
195 
196         @Override
createMmTelFeature(int slotId)197         public MmTelFeature createMmTelFeature(int slotId) {
198             synchronized (mLock) {
199                 countDownLatch(LATCH_CREATE_MMTEL);
200                 mTestMmTelFeature = new TestMmTelFeature(
201                         //onReady
202                         () -> {
203                             synchronized (mLock) {
204                                 countDownLatch(LATCH_MMTEL_READY);
205                             }
206                         },
207                         //onRemoved
208                         () -> {
209                             synchronized (mLock) {
210                                 countDownLatch(LATCH_REMOVE_MMTEL);
211                                 mTestMmTelFeature = null;
212                             }
213                         },
214                         //onCapabilitiesSet
215                         () -> {
216                             synchronized (mLock) {
217                                 countDownLatch(LATCH_MMTEL_CAP_SET);
218                             }
219                         }
220                         );
221                 return mTestMmTelFeature;
222             }
223         }
224 
225         @Override
getRegistration(int slotId)226         public ImsRegistrationImplBase getRegistration(int slotId) {
227             return sImsRegistrationImplBase;
228         }
229 
230         @Nullable
231         @Override
getSipTransport(int slotId)232         public SipTransportImplBase getSipTransport(int slotId) {
233             if (mIsSipTransportImplemented) {
234                 return mTestSipTransport;
235             } else {
236                 return null;
237             }
238         }
239     }
240 
241     private final LocalBinder mBinder = new LocalBinder();
242     // For local access of this Service.
243     class LocalBinder extends Binder {
getService()244         TestImsService getService() {
245             return TestImsService.this;
246         }
247     }
248 
getImsService()249     protected ImsService getImsService() {
250         synchronized (mLock) {
251             if (mTestImsService != null) {
252                 return mTestImsService;
253             }
254             mTestImsService = new ImsServiceUT(this);
255             return mTestImsService;
256         }
257     }
258 
259     @Override
onBind(Intent intent)260     public IBinder onBind(Intent intent) {
261         if ("android.telephony.ims.ImsService".equals(intent.getAction())) {
262             if (ImsUtils.VDBG) {
263                 Log.d(TAG, "onBind-Remote");
264             }
265             return getImsService().onBind(intent);
266         }
267         if (ImsUtils.VDBG) {
268             Log.i(TAG, "onBind-Local");
269         }
270         return mBinder;
271     }
272 
resetState()273     public void resetState() {
274         synchronized (mLock) {
275             mTestMmTelFeature = null;
276             mTestRcsFeature = null;
277             mIsEnabled = false;
278             mSetNullRcsBinding = false;
279             mIsSipTransportImplemented = false;
280             mCapabilities = 0;
281             for (int i = 0; i < LATCH_MAX; i++) {
282                 sLatches[i] = new CountDownLatch(1);
283             }
284         }
285     }
286 
287     // Sets the feature configuration. Make sure to call this before initiating Bind to this
288     // ImsService.
setFeatureConfig(ImsFeatureConfiguration f)289     public void setFeatureConfig(ImsFeatureConfiguration f) {
290         synchronized (mLock) {
291             mFeatureConfig = f;
292         }
293     }
294 
getFeatureConfig()295     public ImsFeatureConfiguration getFeatureConfig() {
296         synchronized (mLock) {
297             return mFeatureConfig;
298         }
299     }
300 
isEnabled()301     public boolean isEnabled() {
302         synchronized (mLock) {
303             return mIsEnabled;
304         }
305     }
306 
setNullRcsBinding()307     public void setNullRcsBinding() {
308         synchronized (mLock) {
309             mSetNullRcsBinding = true;
310         }
311     }
312 
setIsEnabled(boolean isEnabled)313     public void setIsEnabled(boolean isEnabled) {
314         synchronized (mLock) {
315             mIsEnabled = isEnabled;
316         }
317     }
318 
addCapabilities(long capabilities)319     public void addCapabilities(long capabilities) {
320         synchronized (mLock) {
321             mCapabilities |= capabilities;
322         }
323     }
324 
setSipTransportImplemented()325     public void setSipTransportImplemented() {
326         synchronized (mLock) {
327             mIsSipTransportImplemented = true;
328         }
329     }
330 
waitForLatchCountdown(int latchIndex)331     public boolean waitForLatchCountdown(int latchIndex) {
332         boolean complete = false;
333         try {
334             CountDownLatch latch;
335             synchronized (mLock) {
336                 latch = sLatches[latchIndex];
337             }
338             complete = latch.await(ImsUtils.TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
339         } catch (InterruptedException e) {
340             // complete == false
341         }
342         synchronized (mLock) {
343             sLatches[latchIndex] = new CountDownLatch(1);
344         }
345         return complete;
346     }
347 
waitForLatchCountdown(int latchIndex, long waitMs)348     public boolean waitForLatchCountdown(int latchIndex, long waitMs) {
349         boolean complete = false;
350         try {
351             CountDownLatch latch;
352             synchronized (mLock) {
353                 latch = sLatches[latchIndex];
354             }
355             complete = latch.await(waitMs, TimeUnit.MILLISECONDS);
356         } catch (InterruptedException e) {
357             // complete == false
358         }
359         synchronized (mLock) {
360             sLatches[latchIndex] = new CountDownLatch(1);
361         }
362         return complete;
363     }
364 
countDownLatch(int latchIndex)365     public void countDownLatch(int latchIndex) {
366         synchronized (mLock) {
367             sLatches[latchIndex].countDown();
368         }
369     }
370 
getMmTelFeature()371     public TestMmTelFeature getMmTelFeature() {
372         synchronized (mLock) {
373             return mTestMmTelFeature;
374         }
375     }
376 
getRcsFeature()377     public TestRcsFeature getRcsFeature() {
378         synchronized (mLock) {
379             return mTestRcsFeature;
380         }
381     }
382 
getSipTransport()383     public TestSipTransport getSipTransport() {
384         synchronized (mLock) {
385             return mTestSipTransport;
386         }
387     }
388 
getImsRegistration()389     public TestImsRegistration getImsRegistration() {
390         synchronized (mLock) {
391             return sImsRegistrationImplBase;
392         }
393     }
394 
getConfig()395     public ImsConfigImplBase getConfig() {
396         return mTestImsConfig;
397     }
398 }
399