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 package com.android.ons; 17 18 import static org.junit.Assert.assertThrows; 19 import static org.mockito.Mockito.any; 20 import static org.mockito.Mockito.doReturn; 21 import static org.mockito.Mockito.never; 22 import static org.mockito.Mockito.times; 23 import static org.mockito.Mockito.verify; 24 import static org.mockito.Mockito.when; 25 26 import android.compat.testing.PlatformCompatChangeRule; 27 import android.content.BroadcastReceiver; 28 import android.content.Context; 29 import android.content.Intent; 30 import android.content.pm.PackageManager; 31 import android.os.Build; 32 import android.os.Looper; 33 import android.os.RemoteException; 34 import android.os.UserManager; 35 import android.platform.test.flag.junit.SetFlagsRule; 36 import android.telephony.AvailableNetworkInfo; 37 import android.telephony.CarrierConfigManager; 38 import android.telephony.SubscriptionInfo; 39 import android.telephony.SubscriptionManager; 40 import android.telephony.TelephonyFrameworkInitializer; 41 import android.telephony.TelephonyManager; 42 import android.util.Log; 43 44 import androidx.test.runner.AndroidJUnit4; 45 46 import com.android.internal.telephony.IOns; 47 import com.android.internal.telephony.ISetOpportunisticDataCallback; 48 import com.android.internal.telephony.IUpdateAvailableNetworksCallback; 49 50 import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges; 51 52 import org.junit.After; 53 import org.junit.Before; 54 import org.junit.Rule; 55 import org.junit.Test; 56 import org.junit.rules.TestRule; 57 import org.junit.runner.RunWith; 58 import org.mockito.ArgumentCaptor; 59 import org.mockito.Mock; 60 61 import java.lang.reflect.Field; 62 import java.util.ArrayList; 63 import java.util.HashMap; 64 import java.util.List; 65 66 @RunWith(AndroidJUnit4.class) 67 public class OpportunisticNetworkServiceTest extends ONSBaseTest { 68 // SetFlagsRule will be used for Telephony feature flag 69 @Rule 70 public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); 71 @Rule 72 public TestRule compatChangeRule = new PlatformCompatChangeRule(); 73 74 private static final String TAG = "ONSTest"; 75 private String pkgForDebug; 76 private String pkgForFeature; 77 private int mResult; 78 private IOns iOpportunisticNetworkService; 79 private Looper mLooper; 80 private OpportunisticNetworkService mOpportunisticNetworkService; 81 private static final String CARRIER_APP_CONFIG_NAME = "carrierApp"; 82 private static final String SYSTEM_APP_CONFIG_NAME = "systemApp"; 83 84 @Mock 85 private HashMap<String, ONSConfigInput> mockONSConfigInputHashMap; 86 @Mock 87 private ONSProfileSelector mockProfileSelector; 88 @Mock 89 private CarrierConfigManager mCarrierConfigManager; 90 @Mock 91 private ONSProfileActivator mONSProfileActivator; 92 @Mock 93 private UserManager mUserManager; 94 @Mock 95 private Context mMockContext; 96 @Mock 97 private PackageManager mPackageManager; 98 99 @Before setUp()100 public void setUp() throws Exception { 101 super.setUp("ONSTest"); 102 pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>"; 103 pkgForFeature = mContext != null ? mContext.getAttributionTag() : null; 104 Intent intent = new Intent(mContext, OpportunisticNetworkService.class); 105 new Thread(new Runnable() { 106 @Override 107 public void run() { 108 Looper.prepare(); 109 mOpportunisticNetworkService = new OpportunisticNetworkService(); 110 mOpportunisticNetworkService.initialize(mContext); 111 mOpportunisticNetworkService.mSubscriptionManager = mSubscriptionManager; 112 mOpportunisticNetworkService.mPackageManager = mPackageManager; 113 for (int retry = 2; retry > 0; retry--) { 114 115 iOpportunisticNetworkService = (IOns) mOpportunisticNetworkService.onBind(null); 116 117 if (iOpportunisticNetworkService != null) { 118 break; 119 } 120 121 try { 122 Thread.sleep(100); 123 } catch (Exception e) { 124 Log.e(TAG, e.toString()); 125 } 126 } 127 mLooper = Looper.myLooper(); 128 setReady(true); 129 Looper.loop(); 130 } 131 }).start(); 132 waitUntilReady(300); 133 134 // In order not to affect the existing implementation, define a telephony feature 135 when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY_DATA)) 136 .thenReturn(true); 137 when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)) 138 .thenReturn(true); 139 } 140 141 @After tearDown()142 public void tearDown() throws Exception { 143 super.tearDown(); 144 mOpportunisticNetworkService.onDestroy(); 145 if (mLooper != null) { 146 mLooper.quit(); 147 mLooper.getThread().join(); 148 } 149 } 150 151 @Test testCheckEnable()152 public void testCheckEnable() { 153 boolean isEnable = true; 154 try { 155 iOpportunisticNetworkService.setEnable(false, pkgForDebug); 156 isEnable = iOpportunisticNetworkService.isEnabled(pkgForDebug); 157 } catch (RemoteException ex) { 158 Log.e(TAG, "RemoteException", ex); 159 } 160 assertEquals(false, isEnable); 161 } 162 163 @Test testHandleSimStateChange()164 public void testHandleSimStateChange() { 165 mResult = -1; 166 ArrayList<String> mccMncs = new ArrayList<>(); 167 mccMncs.add("310210"); 168 AvailableNetworkInfo availableNetworkInfo = new AvailableNetworkInfo(1, 1, mccMncs, 169 new ArrayList<Integer>()); 170 List<AvailableNetworkInfo> availableNetworkInfos = 171 new ArrayList<AvailableNetworkInfo>(); 172 availableNetworkInfos.add(availableNetworkInfo); 173 IUpdateAvailableNetworksCallback mCallback = new IUpdateAvailableNetworksCallback.Stub() { 174 @Override 175 public void onComplete(int result) { 176 mResult = result; 177 Log.d(TAG, "result: " + result); 178 } 179 }; 180 ONSConfigInput onsConfigInput = new ONSConfigInput(availableNetworkInfos, mCallback, 181 availableNetworkInfos.get(0).getSubId(), 1); 182 List<SubscriptionInfo> subscriptionInfos = new ArrayList<SubscriptionInfo>(); 183 184 // Case 1: There is no Carrier app using ONS. 185 doReturn(null).when(mockONSConfigInputHashMap).get(CARRIER_APP_CONFIG_NAME); 186 mOpportunisticNetworkService.mIsEnabled = true; 187 mOpportunisticNetworkService.mONSConfigInputHashMap = mockONSConfigInputHashMap; 188 mOpportunisticNetworkService.handleSimStateChange(); 189 waitForMs(500); 190 verify(mockONSConfigInputHashMap, never()).get(SYSTEM_APP_CONFIG_NAME); 191 192 // Case 2: There is a Carrier app using ONS and no System app input. 193 doReturn(subscriptionInfos).when(mSubscriptionManager).getActiveSubscriptionInfoList(false); 194 doReturn(onsConfigInput).when(mockONSConfigInputHashMap).get(CARRIER_APP_CONFIG_NAME); 195 doReturn(null).when(mockONSConfigInputHashMap).get(SYSTEM_APP_CONFIG_NAME); 196 mOpportunisticNetworkService.mIsEnabled = true; 197 mOpportunisticNetworkService.mONSConfigInputHashMap = mockONSConfigInputHashMap; 198 mOpportunisticNetworkService.handleSimStateChange(); 199 waitForMs(50); 200 verify(mockONSConfigInputHashMap,times(1)).get(SYSTEM_APP_CONFIG_NAME); 201 } 202 203 @Test testSystemPreferredDataWhileCarrierAppIsActive()204 public void testSystemPreferredDataWhileCarrierAppIsActive() { 205 mResult = -1; 206 ArrayList<String> mccMncs = new ArrayList<>(); 207 mccMncs.add("310210"); 208 AvailableNetworkInfo availableNetworkInfo = new AvailableNetworkInfo(1, 1, mccMncs, 209 new ArrayList<Integer>()); 210 List<AvailableNetworkInfo> availableNetworkInfos = 211 new ArrayList<AvailableNetworkInfo>(); 212 availableNetworkInfos.add(availableNetworkInfo); 213 IUpdateAvailableNetworksCallback mCallback = new IUpdateAvailableNetworksCallback.Stub() { 214 @Override 215 public void onComplete(int result) { 216 mResult = result; 217 Log.d(TAG, "result: " + result); 218 } 219 }; 220 ONSConfigInput onsConfigInput = new ONSConfigInput(availableNetworkInfos, mCallback, 221 availableNetworkInfos.get(0).getSubId(), 1); 222 List<SubscriptionInfo> subscriptionInfos = new ArrayList<SubscriptionInfo>(); 223 224 doReturn(subscriptionInfos).when(mSubscriptionManager).getActiveSubscriptionInfoList(false); 225 doReturn(onsConfigInput).when(mockONSConfigInputHashMap).get(CARRIER_APP_CONFIG_NAME); 226 mOpportunisticNetworkService.mIsEnabled = true; 227 mOpportunisticNetworkService.mONSConfigInputHashMap = mockONSConfigInputHashMap; 228 229 mResult = -1; 230 ISetOpportunisticDataCallback callbackStub = new ISetOpportunisticDataCallback.Stub() { 231 @Override 232 public void onComplete(int result) { 233 Log.d(TAG, "callbackStub, mResult end:" + result); 234 mResult = result; 235 } 236 }; 237 238 try { 239 IOns onsBinder = (IOns)mOpportunisticNetworkService.onBind(null); 240 onsBinder.setPreferredDataSubscriptionId( 241 SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, false, callbackStub, 242 pkgForDebug); 243 } catch (RemoteException ex) { 244 Log.e(TAG, "RemoteException", ex); 245 } 246 waitForMs(50); 247 assertEquals(TelephonyManager.SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED, mResult); 248 } 249 250 @Test testSetPreferredDataSubscriptionId()251 public void testSetPreferredDataSubscriptionId() { 252 mResult = -1; 253 ISetOpportunisticDataCallback callbackStub = new ISetOpportunisticDataCallback.Stub() { 254 @Override 255 public void onComplete(int result) { 256 Log.d(TAG, "callbackStub, mResult end:" + result); 257 mResult = result; 258 } 259 }; 260 261 try { 262 assertNotNull(iOpportunisticNetworkService); 263 iOpportunisticNetworkService.setPreferredDataSubscriptionId(5, false, callbackStub, 264 pkgForDebug); 265 } catch (RemoteException ex) { 266 Log.e(TAG, "RemoteException", ex); 267 } 268 assertEquals( 269 TelephonyManager.SET_OPPORTUNISTIC_SUB_NO_OPPORTUNISTIC_SUB_AVAILABLE, mResult); 270 } 271 272 @Test testGetPreferredDataSubscriptionId()273 public void testGetPreferredDataSubscriptionId() { 274 assertNotNull(iOpportunisticNetworkService); 275 mResult = -1; 276 try { 277 mResult = iOpportunisticNetworkService.getPreferredDataSubscriptionId(pkgForDebug, 278 pkgForFeature); 279 Log.d(TAG, "testGetPreferredDataSubscriptionId: " + mResult); 280 } catch (RemoteException ex) { 281 Log.e(TAG, "RemoteException", ex); 282 } 283 } 284 285 @Test testUpdateAvailableNetworksWithInvalidArguments()286 public void testUpdateAvailableNetworksWithInvalidArguments() { 287 mResult = -1; 288 IUpdateAvailableNetworksCallback mCallback = new IUpdateAvailableNetworksCallback.Stub() { 289 @Override 290 public void onComplete(int result) { 291 Log.d(TAG, "mResult end:" + result); 292 mResult = result; 293 } 294 }; 295 296 ArrayList<String> mccMncs = new ArrayList<>(); 297 mccMncs.add("310210"); 298 AvailableNetworkInfo availableNetworkInfo = new AvailableNetworkInfo(1, 1, mccMncs, 299 new ArrayList<Integer>()); 300 List<AvailableNetworkInfo> availableNetworkInfos = new ArrayList<>(); 301 availableNetworkInfos.add(availableNetworkInfo); 302 303 try { 304 iOpportunisticNetworkService.updateAvailableNetworks(availableNetworkInfos, mCallback, 305 pkgForDebug); 306 } catch (RemoteException ex) { 307 Log.e(TAG, "RemoteException", ex); 308 } 309 assertEquals( 310 TelephonyManager.UPDATE_AVAILABLE_NETWORKS_NO_OPPORTUNISTIC_SUB_AVAILABLE, mResult); 311 } 312 313 @Test testUpdateAvailableNetworksWithSuccess()314 public void testUpdateAvailableNetworksWithSuccess() { 315 mResult = -1; 316 IUpdateAvailableNetworksCallback mCallback = new IUpdateAvailableNetworksCallback.Stub() { 317 @Override 318 public void onComplete(int result) { 319 Log.d(TAG, "mResult end:" + result); 320 mResult = result; 321 } 322 }; 323 List<AvailableNetworkInfo> availableNetworkInfos = new ArrayList<>(); 324 try { 325 iOpportunisticNetworkService.setEnable(false, pkgForDebug); 326 iOpportunisticNetworkService.updateAvailableNetworks(availableNetworkInfos, mCallback, 327 pkgForDebug); 328 } catch (RemoteException ex) { 329 Log.e(TAG, "RemoteException", ex); 330 } 331 assertEquals(TelephonyManager.UPDATE_AVAILABLE_NETWORKS_SUCCESS, mResult); 332 } 333 334 @Test testPriorityRuleOfActivatingAvailableNetworks()335 public void testPriorityRuleOfActivatingAvailableNetworks() { 336 ArrayList<String> mccMncs = new ArrayList<>(); 337 mccMncs.add("310210"); 338 AvailableNetworkInfo availableNetworkInfo = new AvailableNetworkInfo(1, 1, mccMncs, 339 new ArrayList<Integer>()); 340 List<AvailableNetworkInfo> availableNetworkInfos = 341 new ArrayList<AvailableNetworkInfo>(); 342 availableNetworkInfos.add(availableNetworkInfo); 343 mResult = -1; 344 IUpdateAvailableNetworksCallback mCallback = new IUpdateAvailableNetworksCallback.Stub() { 345 @Override 346 public void onComplete(int result) { 347 mResult = result; 348 Log.d(TAG, "result: " + result); 349 } 350 }; 351 ONSConfigInput onsConfigInput = new ONSConfigInput(availableNetworkInfos, mCallback, 352 availableNetworkInfos.get(0).getSubId(), 1); 353 doReturn(onsConfigInput).when(mockONSConfigInputHashMap).get(CARRIER_APP_CONFIG_NAME); 354 doReturn(true).when(mockProfileSelector).hasOpportunisticSub(any()); 355 doReturn(false).when(mockProfileSelector).containStandaloneOppSubs(any()); 356 mOpportunisticNetworkService.mIsEnabled = true; 357 mOpportunisticNetworkService.mONSConfigInputHashMap = mockONSConfigInputHashMap; 358 mOpportunisticNetworkService.mProfileSelector = mockProfileSelector; 359 360 // Assume carrier app has updated available networks at first. 361 // Then system app updated available networks which is not standalone. 362 try { 363 IOns onsBinder = (IOns) mOpportunisticNetworkService.onBind(null); 364 onsBinder.updateAvailableNetworks(availableNetworkInfos, mCallback, pkgForDebug); 365 } catch (RemoteException ex) { 366 Log.e(TAG, "RemoteException", ex); 367 } 368 verify(mockProfileSelector, never()).startProfileSelection(any(), any()); 369 370 // System app updated available networks which contain standalone network. 371 doReturn(true).when(mockProfileSelector).containStandaloneOppSubs(any()); 372 try { 373 IOns onsBinder = (IOns) mOpportunisticNetworkService.onBind(null); 374 onsBinder.updateAvailableNetworks(availableNetworkInfos, mCallback, pkgForDebug); 375 } catch (RemoteException ex) { 376 Log.e(TAG, "RemoteException", ex); 377 } 378 verify(mockProfileSelector, times(1)).startProfileSelection(any(), any()); 379 380 // System app updated available networks which equal to null. 381 // Case1: start carrier app request, if there is a carrier app request. 382 availableNetworkInfos.clear(); 383 try { 384 IOns onsBinder = (IOns) mOpportunisticNetworkService.onBind(null); 385 onsBinder.updateAvailableNetworks(availableNetworkInfos, mCallback, pkgForDebug); 386 } catch (RemoteException ex) { 387 Log.e(TAG, "RemoteException", ex); 388 } 389 verify(mockProfileSelector, times(2)).startProfileSelection(any(), any()); 390 391 // System app updated available networks which equal to null. 392 // Case2: stop profile selection, if there is no any carrier app request. 393 doReturn(null).when(mockONSConfigInputHashMap).get(CARRIER_APP_CONFIG_NAME); 394 try { 395 IOns onsBinder = (IOns) mOpportunisticNetworkService.onBind(null); 396 onsBinder.updateAvailableNetworks(availableNetworkInfos, mCallback, pkgForDebug); 397 } catch (RemoteException ex) { 398 Log.e(TAG, "RemoteException", ex); 399 } 400 verify(mockProfileSelector, times(1)).stopProfileSelection(any()); 401 } 402 403 @Test testCarrierConfigChangedUnlocked()404 public void testCarrierConfigChangedUnlocked() { 405 mOpportunisticNetworkService.mUserManager = mUserManager; 406 mOpportunisticNetworkService.mONSProfileActivator = mONSProfileActivator; 407 mOpportunisticNetworkService.mCarrierConfigManager = mCarrierConfigManager; 408 mOpportunisticNetworkService.registerCarrierConfigChangListener(); 409 mOpportunisticNetworkService.mContext = mMockContext; 410 411 CarrierConfigManager.CarrierConfigChangeListener CarrierConfigChangeListener; 412 413 final ArgumentCaptor<CarrierConfigManager.CarrierConfigChangeListener> listenerCaptor = 414 ArgumentCaptor.forClass(CarrierConfigManager.CarrierConfigChangeListener.class); 415 416 verify(mCarrierConfigManager).registerCarrierConfigChangeListener(any(), 417 listenerCaptor.capture()); 418 CarrierConfigChangeListener = listenerCaptor.getAllValues().get(0); 419 420 // CarrierConfigChange in lock state 421 when(mUserManager.isUserUnlocked()).thenReturn(false); 422 CarrierConfigChangeListener.onCarrierConfigChanged(0, 0, 0, 0); 423 verify(mONSProfileActivator, never()).handleCarrierConfigChange(); 424 425 // handle CarrierConfigChange when state is changed from lock to unlock 426 final ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor = 427 ArgumentCaptor.forClass(BroadcastReceiver.class); 428 429 verify(mMockContext).registerReceiver(broadcastReceiverCaptor.capture(), any()); 430 broadcastReceiverCaptor.getValue().onReceive(mMockContext, 431 new Intent(Intent.ACTION_USER_UNLOCKED)); 432 verify(mONSProfileActivator, times(1)).handleCarrierConfigChange(); 433 434 // CarrierConfigChange in Unlock state 435 when(mUserManager.isUserUnlocked()).thenReturn(true); 436 CarrierConfigChangeListener.onCarrierConfigChanged(0, 0, 0, 0); 437 verify(mONSProfileActivator, times(2)).handleCarrierConfigChange(); 438 } 439 440 @Test 441 @EnableCompatChanges({TelephonyManager.ENABLE_FEATURE_MAPPING}) testTelephonyFeatureAndCompatChanges()442 public void testTelephonyFeatureAndCompatChanges() throws Exception { 443 ArrayList<String> mccMncs = new ArrayList<>(); 444 mccMncs.add("310210"); 445 AvailableNetworkInfo availableNetworkInfo = new AvailableNetworkInfo(1, 1, mccMncs, 446 new ArrayList<Integer>()); 447 List<AvailableNetworkInfo> availableNetworkInfos = new ArrayList<>(); 448 availableNetworkInfos.add(availableNetworkInfo); 449 450 // Enabled FeatureFlags and ENABLE_FEATURE_MAPPING, telephony features are defined 451 try { 452 // FEATURE_TELEPHONY_DATA 453 iOpportunisticNetworkService.setPreferredDataSubscriptionId( 454 SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, false, null, pkgForDebug); 455 iOpportunisticNetworkService.getPreferredDataSubscriptionId(pkgForDebug, pkgForFeature); 456 457 // FEATURE_TELEPHONY_RADIO_ACCESS 458 iOpportunisticNetworkService.setEnable(false, pkgForDebug); 459 iOpportunisticNetworkService.isEnabled(pkgForDebug); 460 iOpportunisticNetworkService.updateAvailableNetworks(availableNetworkInfos, null, 461 pkgForDebug); 462 } catch (Exception e) { 463 fail("Not expect exception " + e.getMessage()); 464 } 465 466 // Replace field to set SDK version of vendor partition to Android V 467 int vendorApiLevel = Build.VERSION_CODES.VANILLA_ICE_CREAM; 468 replaceInstance(OpportunisticNetworkService.class, "mVendorApiLevel", 469 mOpportunisticNetworkService, vendorApiLevel); 470 471 // FEATURE_TELEPHONY_DATA is not defined, expect UnsupportedOperationException. 472 when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY_DATA)) 473 .thenReturn(false); 474 475 assertThrows(UnsupportedOperationException.class, 476 () -> iOpportunisticNetworkService.setPreferredDataSubscriptionId( 477 SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, false, null, pkgForDebug)); 478 assertThrows(UnsupportedOperationException.class, 479 () -> iOpportunisticNetworkService.getPreferredDataSubscriptionId( 480 pkgForDebug, pkgForFeature)); 481 482 // FEATURE_TELEPHONY_DATA is not defined, expect UnsupportedOperationException. 483 when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)) 484 .thenReturn(false); 485 assertThrows(UnsupportedOperationException.class, 486 () -> iOpportunisticNetworkService.setEnable(false, pkgForDebug)); 487 assertThrows(UnsupportedOperationException.class, 488 () -> iOpportunisticNetworkService.isEnabled(pkgForDebug)); 489 assertThrows(UnsupportedOperationException.class, 490 () -> iOpportunisticNetworkService.updateAvailableNetworks( 491 availableNetworkInfos, null, pkgForDebug)); 492 } 493 replaceInstance(final Class c, final String instanceName, final Object obj, final Object newValue)494 private void replaceInstance(final Class c, final String instanceName, final Object obj, 495 final Object newValue) throws Exception { 496 Field field = c.getDeclaredField(instanceName); 497 field.setAccessible(true); 498 field.set(obj, newValue); 499 } 500 getIOns()501 private IOns getIOns() { 502 return IOns.Stub.asInterface( 503 TelephonyFrameworkInitializer 504 .getTelephonyServiceManager() 505 .getOpportunisticNetworkServiceRegisterer() 506 .get()); 507 } 508 waitForMs(long ms)509 public static void waitForMs(long ms) { 510 try { 511 Thread.sleep(ms); 512 } catch (InterruptedException e) { 513 Log.d(TAG, "InterruptedException while waiting: " + e); 514 } 515 } 516 } 517