e68262f002b89c6c4801a008ee8e612c85e5aa01
[android/platform/frameworks/opt/telephony.git] / tests / telephonytests / src / com / android / internal / telephony / PhoneSwitcherTest.java
1 /*
2  * Copyright (C) 2006 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.internal.telephony;
18
19 import android.content.Context;
20 import android.net.ConnectivityManager;
21 import android.net.NetworkCapabilities;
22 import android.net.NetworkRequest;
23 import android.net.StringNetworkSpecifier;
24 import android.os.AsyncResult;
25 import android.os.Binder;
26 import android.os.Handler;
27 import android.os.HandlerThread;
28 import android.os.Looper;
29 import android.os.Message;
30 import android.telephony.Rlog;
31 import android.test.AndroidTestCase;
32 import android.test.suitebuilder.annotation.SmallTest;
33
34 import com.android.internal.telephony.mocks.ConnectivityServiceMock;
35 import com.android.internal.telephony.mocks.SubscriptionControllerMock;
36 import com.android.internal.telephony.mocks.TelephonyRegistryMock;
37 import com.android.internal.telephony.test.SimulatedCommands;
38
39 import java.util.concurrent.atomic.AtomicInteger;
40 import java.util.concurrent.atomic.AtomicReference;
41
42 public class PhoneSwitcherTest extends AndroidTestCase {
43     private final static String LOG_TAG = "PhoneSwitcherTest";
44
45     static void failAndStack(String str) {
46         fail(str + "\n" + SubscriptionMonitorTest.stack());
47     }
48
49     static String stack() {
50         StringBuilder sb = new StringBuilder();
51         for(StackTraceElement e : Thread.currentThread().getStackTrace()) {
52             sb.append(e.toString()).append("\n");
53         }
54         return sb.toString();
55     }
56
57     private static class TestHandler extends Handler {
58         public final static int ACTIVE_PHONE_SWITCH = 1;
59         public final static int IN_IDLE = 2;
60
61         HandlerThread handlerThread;
62
63         public TestHandler(Looper looper) {
64             super(looper);
65         }
66
67         public void die() {
68             if(handlerThread != null) {
69                 handlerThread.quit();
70                 handlerThread = null;
71             }
72         }
73
74         public void blockTilIdle() {
75             Object lock = new Object();
76             synchronized (lock) {
77                 Message msg = this.obtainMessage(IN_IDLE, lock);
78                 msg.sendToTarget();
79                 try {
80                     lock.wait();
81                 } catch (InterruptedException e) {}
82             }
83         }
84
85         public static TestHandler makeHandler() {
86             final HandlerThread handlerThread = new HandlerThread("TestHandler");
87             handlerThread.start();
88             final TestHandler result = new TestHandler(handlerThread.getLooper());
89             result.handlerThread = handlerThread;
90             return result;
91         }
92
93         private boolean objectEquals(Object o1, Object o2) {
94             if (o1 == null) return (o2 == null);
95             return o1.equals(o2);
96         }
97
98         private void failAndStack(String str) {
99             SubscriptionMonitorTest.failAndStack(str);
100         }
101
102         @Override
103         public void handleMessage(Message msg) {
104             switch (msg.what) {
105                 case ACTIVE_PHONE_SWITCH: {
106                     AsyncResult ar = (AsyncResult)(msg.obj);
107                     if (objectEquals(ar.userObj, mActivePhoneSwitchObject.get()) == false) {
108                         failAndStack("Active Phone Switch object is incorrect!");
109                     }
110                     int count = mActivePhoneSwitchCount.incrementAndGet();
111                     Rlog.d(LOG_TAG, "ACTIVE_PHONE_SWITCH, inc to " + count);
112                     break;
113                 }
114                 case IN_IDLE: {
115                     Object lock = msg.obj;
116                     synchronized (lock) {
117                         lock.notify();
118                     }
119                     break;
120                 }
121             }
122         }
123
124         private final AtomicInteger mActivePhoneSwitchCount = new AtomicInteger(0);
125         private final AtomicReference<Object> mActivePhoneSwitchObject =
126                 new AtomicReference<Object>();
127
128         public void reset() {
129             mActivePhoneSwitchCount.set(0);
130             mActivePhoneSwitchObject.set(null);
131         }
132
133         public void setActivePhoneSwitchObject(Object o) {
134             mActivePhoneSwitchObject.set(o);
135         }
136
137         public int getActivePhoneSwitchCount() {
138             return mActivePhoneSwitchCount.get();
139         }
140     }
141
142     private void waitABit() {
143         try {
144             Thread.sleep(250);
145         } catch (Exception e) {}
146     }
147
148     private String mTestName = "";
149
150     private void log(String str) {
151         Rlog.d(LOG_TAG + " " + mTestName, str);
152     }
153
154     private NetworkRequest makeSubSpecificDefaultRequest(ConnectivityServiceMock cs, int subId) {
155         NetworkCapabilities netCap = (new NetworkCapabilities()).
156                 addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET).
157                 addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED).
158                 addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
159         netCap.setNetworkSpecifier(new StringNetworkSpecifier(Integer.toString(subId)));
160         return cs.requestNetwork(netCap, null, 0, new Binder(), -1);
161     }
162
163     private NetworkRequest makeSubSpecificMmsRequest(ConnectivityServiceMock cs, int subId) {
164         NetworkCapabilities netCap = (new NetworkCapabilities()).
165                 addCapability(NetworkCapabilities.NET_CAPABILITY_MMS).
166                 addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED).
167                 addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
168         netCap.setNetworkSpecifier(new StringNetworkSpecifier(Integer.toString(subId)));
169         return cs.requestNetwork(netCap, null, 0, new Binder(), -1);
170     }
171
172     private Context makeContext() {
173         final ContextFixture contextFixture = new ContextFixture();
174         String[] networkConfigString = getContext().getResources().getStringArray(
175                 com.android.internal.R.array.networkAttributes);
176         contextFixture.putStringArrayResource(com.android.internal.R.array.networkAttributes,
177                 networkConfigString);
178         return contextFixture.getTestDouble();
179     }
180
181     /**
182      * Test that a single phone case results in our phone being active and the RIL called
183      */
184     @SmallTest
185     public void testRegister() throws Exception {
186         mTestName = "testRegister";
187         final int numPhones = 2;
188         final int maxActivePhones = 1;
189         final HandlerThread handlerThread = new HandlerThread("PhoneSwitcherTestThread");
190         handlerThread.start();
191         final ContextFixture contextFixture = new ContextFixture();
192         String[] networkConfigString = getContext().getResources().getStringArray(
193                 com.android.internal.R.array.networkAttributes);
194         contextFixture.putStringArrayResource(com.android.internal.R.array.networkAttributes,
195                 networkConfigString);
196         final Context contextMock = contextFixture.getTestDouble();
197         final ConnectivityServiceMock connectivityServiceMock =
198                 new ConnectivityServiceMock(contextMock);
199         final ConnectivityManager cm =
200                 new ConnectivityManager(contextMock, connectivityServiceMock);
201         contextFixture.setSystemService(Context.CONNECTIVITY_SERVICE, cm);
202         final ITelephonyRegistry.Stub telRegistryMock = new TelephonyRegistryMock();
203         final SubscriptionControllerMock subControllerMock =
204                 new SubscriptionControllerMock(contextMock, telRegistryMock, numPhones);
205         final SimulatedCommands[] commandsInterfaces = new SimulatedCommands[numPhones];
206         final PhoneMock[] phones = new PhoneMock[numPhones];
207         for (int i = 0; i < numPhones; i++) {
208             commandsInterfaces[i] = new SimulatedCommands();
209         //    phones[i] = new PhoneMock(contextMock, commandsInterfaces[i]);
210         }
211
212         PhoneSwitcher phoneSwitcher = new PhoneSwitcher(maxActivePhones, numPhones,
213                 contextMock, subControllerMock, handlerThread.getLooper(), telRegistryMock,
214                 commandsInterfaces, phones);
215
216         // verify nothing has been done while there are no inputs
217         if (commandsInterfaces[0].isDataAllowed()) fail("data allowed initially");
218         if (phoneSwitcher.isPhoneActive(0))        fail("phone active initially");
219
220         connectivityServiceMock.addDefaultRequest();
221         waitABit();
222
223         if (commandsInterfaces[0].isDataAllowed()) fail("data allowed after request");
224         if (phoneSwitcher.isPhoneActive(0))        fail("phone active after request");
225
226         TestHandler testHandler = TestHandler.makeHandler();
227         Object activePhoneSwitchObject = new Object();
228         testHandler.setActivePhoneSwitchObject(activePhoneSwitchObject);
229
230         testHandler.blockTilIdle();
231
232         // not registered yet - shouldn't inc
233         if (testHandler.getActivePhoneSwitchCount() != 0) {
234             fail("pretest of ActivePhoneSwitchCount");
235         }
236         boolean threw = false;
237         try {
238             // should throw
239             phoneSwitcher.registerForActivePhoneSwitch(2, testHandler,
240                     TestHandler.ACTIVE_PHONE_SWITCH, activePhoneSwitchObject);
241         } catch (IllegalArgumentException e) {
242             threw = true;
243         }
244         if (threw == false) fail("register with bad phoneId didn't throw");
245
246         phoneSwitcher.registerForActivePhoneSwitch(0, testHandler,
247                 TestHandler.ACTIVE_PHONE_SWITCH,
248                 activePhoneSwitchObject);
249         testHandler.blockTilIdle();
250
251         if (testHandler.getActivePhoneSwitchCount() != 1) {
252             fail("post register of ActivePhoneSwitchCount not 1!");
253         }
254
255         subControllerMock.setDefaultDataSubId(0);
256         testHandler.blockTilIdle();
257
258         if (testHandler.getActivePhoneSwitchCount() != 1) {
259             fail("after set of default to 0, ActivePhoneSwitchCount not 1!");
260         }
261         if (commandsInterfaces[0].isDataAllowed()) fail("data allowed");
262
263         subControllerMock.setSlotSubId(0, 0);
264         waitABit();
265
266         if (testHandler.getActivePhoneSwitchCount() != 2) {
267             fail("after mapping of 0 to 0, ActivePhoneSwitchCount not 2!");
268         }
269         if (commandsInterfaces[0].isDataAllowed() == false) fail("data not allowed");
270
271         // now try various things that should cause the active phone to switch:
272         // 1 lose default via default sub change
273         // 2 gain default via default sub change
274         // 3 lose default via sub->phone change
275         // 4 gain default via sub->phone change
276         // 5 lose default network request
277         // 6 gain subscription-specific request
278         // 7 lose via sub->phone change
279         // 8 gain via sub->phone change
280         // 9 lose subscription-specific request
281         // 10 don't switch phones when in emergency mode
282
283         // 1 lose default via default sub change
284         subControllerMock.setDefaultDataSubId(1);
285         waitABit();
286         if (testHandler.getActivePhoneSwitchCount() != 3) {
287             fail("after set of default to 1, ActivePhoneSwitchCount not 3!");
288         }
289         if (commandsInterfaces[0].isDataAllowed()) fail("data allowed");
290
291         subControllerMock.setSlotSubId(1, 1);
292         waitABit();
293         if (testHandler.getActivePhoneSwitchCount() != 3) {
294             fail("after mapping of 1 to 1, ActivePhoneSwitchCount not 3!");
295         }
296         if (commandsInterfaces[0].isDataAllowed()) fail("data allowed");
297         if (commandsInterfaces[1].isDataAllowed() == false) fail("data not allowed");
298
299         // 2 gain default via default sub change
300         subControllerMock.setDefaultDataSubId(0);
301         waitABit();
302         if (testHandler.getActivePhoneSwitchCount() != 4) {
303             fail("after set of default to 0, ActivePhoneSwitchCount not 4!");
304         }
305         if (commandsInterfaces[1].isDataAllowed()) fail("data allowed");
306         if (commandsInterfaces[0].isDataAllowed() == false) fail("data not allowed");
307
308         // 3 lose default via sub->phone change
309         subControllerMock.setSlotSubId(0, 2);
310         waitABit();
311
312         if (testHandler.getActivePhoneSwitchCount() != 5) {
313             fail("after mapping of 0 to 2, ActivePhoneSwitchCount not 5!");
314         }
315         if (commandsInterfaces[0].isDataAllowed()) fail("data allowed");
316         if (commandsInterfaces[1].isDataAllowed()) fail("data allowed");
317
318         // 4 gain default via sub->phone change
319         subControllerMock.setSlotSubId(0, 0);
320         waitABit();
321         if (testHandler.getActivePhoneSwitchCount() != 6) {
322             fail("after mapping of 0 to 0, ActivePhoneSwitchCount not 6!");
323         }
324         if (commandsInterfaces[0].isDataAllowed() == false) fail("data not allowed");
325         if (commandsInterfaces[1].isDataAllowed()) fail("data allowed");
326
327         // 5 lose default network request
328         connectivityServiceMock.removeDefaultRequest();
329         waitABit();
330         if (testHandler.getActivePhoneSwitchCount() != 7) {
331             fail("after loss of network request, ActivePhoneSwitchCount not 7!");
332         }
333         if (commandsInterfaces[0].isDataAllowed()) fail("data allowed");
334         if (commandsInterfaces[1].isDataAllowed()) fail("data allowed");
335
336         // 6 gain subscription-specific request
337         NetworkRequest request = makeSubSpecificDefaultRequest(connectivityServiceMock, 0);
338         waitABit();
339         if (testHandler.getActivePhoneSwitchCount() != 8) {
340             fail("after gain of network request, ActivePhoneSwitchCount not 8!");
341         }
342         if (commandsInterfaces[0].isDataAllowed() == false) fail("data not allowed");
343         if (commandsInterfaces[1].isDataAllowed()) fail("data allowed");
344
345         // 7 lose via sub->phone change
346         subControllerMock.setSlotSubId(0, 1);
347         waitABit();
348         if (testHandler.getActivePhoneSwitchCount() != 9) {
349             fail("after loss of request due to subId map change, ActivePhoneSwitchCount not 9!");
350         }
351         if (commandsInterfaces[0].isDataAllowed()) fail("data allowed");
352         if (commandsInterfaces[1].isDataAllowed()) fail("data allowed");
353
354         // 8 gain via sub->phone change
355         subControllerMock.setSlotSubId(0, 0);
356         waitABit();
357         if (testHandler.getActivePhoneSwitchCount() != 10) {
358             fail("after gain of request due to subId map change, ActivePhoneSwitchCount not 10!");
359         }
360         if (commandsInterfaces[0].isDataAllowed() == false) fail("data not allowed");
361         if (commandsInterfaces[1].isDataAllowed()) fail("data allowed");
362
363         // 9 lose subscription-specific request
364         connectivityServiceMock.releaseNetworkRequest(request);
365         waitABit();
366         if (testHandler.getActivePhoneSwitchCount() != 11) {
367             fail("after release of request, ActivePhoneSwitchCount not 11!");
368         }
369         if (commandsInterfaces[0].isDataAllowed()) fail("data allowed");
370         if (commandsInterfaces[1].isDataAllowed()) fail("data allowed");
371
372         // 10 don't switch phones when in emergency mode
373         // not ready yet - Phone turns out to be hard to stub out
374 //        phones[0].setInEmergencyCall(true);
375 //        connectivityServiceMock.addDefaultRequest();
376 //        waitABit();
377 //        if (testHandler.getActivePhoneSwitchCount() != 11) {
378 //            fail("after release of request, ActivePhoneSwitchCount not 11!");
379 //        }
380 //        if (commandsInterfaces[0].isDataAllowed()) fail("data allowed");
381 //        if (commandsInterfaces[1].isDataAllowed()) fail("data allowed");
382 //
383 //        phones[0].setInEmergencyCall(false);
384 //        connectivityServiceMock.addDefaultRequest();
385 //        waitABit();
386 //        if (testHandler.getActivePhoneSwitchCount() != 12) {
387 //            fail("after release of request, ActivePhoneSwitchCount not 11!");
388 //        }
389 //        if (commandsInterfaces[0].isDataAllowed()) fail("data allowed");
390 //        if (commandsInterfaces[1].isDataAllowed()) fail("data allowed");
391         testHandler.die();
392         handlerThread.quit();
393     }
394
395     /**
396      * Test a multi-sim case with limited active phones:
397      * - lose default via default sub change
398      * - lose default via sub->phone change
399      * - gain default via sub->phone change
400      * - gain default via default sub change
401      * - lose default network request
402      * - gain subscription-specific request
403      * - lose via sub->phone change
404      * - gain via sub->phone change
405      * - lose subscription-specific request
406      * - tear down low priority phone when new request comes in
407      * - tear down low priority phone when sub change causes split
408      * - bring up low priority phone when sub change causes join
409      * - don't switch phones when in emergency mode
410      */
411     @SmallTest
412     public void testPrioritization() throws Exception {
413         mTestName = "testPrioritization";
414         final int numPhones = 2;
415         final int maxActivePhones = 1;
416         final HandlerThread handlerThread = new HandlerThread("PhoneSwitcherTestThread");
417         handlerThread.start();
418         final ContextFixture contextFixture = new ContextFixture();
419         String[] networkConfigString = getContext().getResources().getStringArray(
420                 com.android.internal.R.array.networkAttributes);
421         contextFixture.putStringArrayResource(com.android.internal.R.array.networkAttributes,
422                 networkConfigString);
423         final Context contextMock = contextFixture.getTestDouble();
424         final ConnectivityServiceMock connectivityServiceMock =
425             new ConnectivityServiceMock(contextMock);
426         final ConnectivityManager cm =
427                 new ConnectivityManager(contextMock, connectivityServiceMock);
428         contextFixture.setSystemService(Context.CONNECTIVITY_SERVICE, cm);
429         final ITelephonyRegistry.Stub telRegistryMock = new TelephonyRegistryMock();
430         final SubscriptionControllerMock subControllerMock =
431                 new SubscriptionControllerMock(contextMock, telRegistryMock, numPhones);
432         final SimulatedCommands[] commandsInterfaces = new SimulatedCommands[numPhones];
433         final PhoneMock[] phones = new PhoneMock[numPhones];
434         for (int i = 0; i < numPhones; i++) {
435             commandsInterfaces[i] = new SimulatedCommands();
436         }
437
438         PhoneSwitcher phoneSwitcher = new PhoneSwitcher(maxActivePhones, numPhones,
439                 contextMock, subControllerMock, handlerThread.getLooper(), telRegistryMock,
440                 commandsInterfaces, phones);
441
442         TestHandler testHandler = TestHandler.makeHandler();
443         Object activePhoneSwitchObject = new Object();
444         testHandler.setActivePhoneSwitchObject(activePhoneSwitchObject);
445
446         connectivityServiceMock.addDefaultRequest();
447         subControllerMock.setSlotSubId(0, 0);
448         subControllerMock.setSlotSubId(1, 1);
449         subControllerMock.setDefaultDataSubId(0);
450         waitABit();
451         phoneSwitcher.registerForActivePhoneSwitch(0, testHandler, TestHandler.ACTIVE_PHONE_SWITCH,
452                 activePhoneSwitchObject);
453         waitABit();
454         // verify initial conditions
455         if (testHandler.getActivePhoneSwitchCount() != 1) {
456             fail("Initial conditions not met: ActivePhoneSwitchCount not 1! " +
457                     testHandler.getActivePhoneSwitchCount());
458         }
459         if (commandsInterfaces[0].isDataAllowed() == false) fail("data not allowed");
460         if (commandsInterfaces[1].isDataAllowed()) fail("data allowed");
461
462         // now start a higher priority conneciton on the other sub
463         NetworkRequest request = makeSubSpecificMmsRequest(connectivityServiceMock, 1);
464         waitABit();
465         if (testHandler.getActivePhoneSwitchCount() != 2) {
466             fail("after gain of network request, ActivePhoneSwitchCount not 2!");
467         }
468         if (commandsInterfaces[0].isDataAllowed()) fail("data allowed");
469         if (commandsInterfaces[1].isDataAllowed() == false) fail("data not allowed");
470
471         testHandler.die();
472         handlerThread.quit();
473     }
474
475     /**
476      * Verify we don't send spurious DATA_ALLOWED calls when another NetworkFactory
477      * wins (ie, switch to wifi).
478      */
479     @SmallTest
480     public void testHigherPriorityDefault() throws Exception {
481         mTestName = "testPrioritization";
482         final int numPhones = 2;
483         final int maxActivePhones = 1;
484         final HandlerThread handlerThread = new HandlerThread("PhoneSwitcherTestThread");
485         handlerThread.start();
486         final ContextFixture contextFixture = new ContextFixture();
487         String[] networkConfigString = getContext().getResources().getStringArray(
488                 com.android.internal.R.array.networkAttributes);
489         contextFixture.putStringArrayResource(com.android.internal.R.array.networkAttributes,
490                 networkConfigString);
491         final Context contextMock = contextFixture.getTestDouble();
492         final ConnectivityServiceMock connectivityServiceMock =
493                 new ConnectivityServiceMock(contextMock);
494         final ConnectivityManager cm =
495                 new ConnectivityManager(contextMock, connectivityServiceMock);
496         contextFixture.setSystemService(Context.CONNECTIVITY_SERVICE, cm);
497         final ITelephonyRegistry.Stub telRegistryMock = new TelephonyRegistryMock();
498         final SubscriptionControllerMock subControllerMock =
499                 new SubscriptionControllerMock(contextMock, telRegistryMock, numPhones);
500         final SimulatedCommands[] commandsInterfaces = new SimulatedCommands[numPhones];
501         final PhoneMock[] phones = new PhoneMock[numPhones];
502         for (int i = 0; i < numPhones; i++) {
503             commandsInterfaces[i] = new SimulatedCommands();
504         }
505
506         PhoneSwitcher phoneSwitcher = new PhoneSwitcher(maxActivePhones, numPhones,
507                 contextMock, subControllerMock, handlerThread.getLooper(), telRegistryMock,
508                 commandsInterfaces, phones);
509
510         TestHandler testHandler = TestHandler.makeHandler();
511         Object activePhoneSwitchObject = new Object();
512         testHandler.setActivePhoneSwitchObject(activePhoneSwitchObject);
513
514         connectivityServiceMock.addDefaultRequest();
515         subControllerMock.setSlotSubId(0, 0);
516         subControllerMock.setSlotSubId(1, 1);
517         subControllerMock.setDefaultDataSubId(0);
518         waitABit();
519
520         // Phone 0 should be active
521         if (commandsInterfaces[0].isDataAllowed() == false) fail("data not allowed");
522         if (commandsInterfaces[1].isDataAllowed()) fail("data allowed");
523
524         connectivityServiceMock.setCurrentScoreForRequest(connectivityServiceMock.defaultRequest,
525                 100);
526         waitABit();
527
528         // should be no change
529         if (commandsInterfaces[0].isDataAllowed() == false) fail("data not allowed");
530         if (commandsInterfaces[1].isDataAllowed()) fail("data allowed");
531
532         connectivityServiceMock.setCurrentScoreForRequest(connectivityServiceMock.defaultRequest,
533                 0);
534         waitABit();
535
536         // should be no change
537         if (commandsInterfaces[0].isDataAllowed() == false) fail("data not allowed");
538         if (commandsInterfaces[1].isDataAllowed()) fail("data allowed");
539
540         testHandler.die();
541         handlerThread.quit();
542     }
543
544     /**
545      * Test MSMA testing prioritiziation
546      * - leave multiple on (up to the limit)
547      * - tear down lowest priority phone when new request comes in
548      * - tear down low priority phone when sub change causes split
549      * - bring up low priority phone when sub change causes join
550      * - don't switch phones when in emergency mode
551      */
552
553 }