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