1#!/usr/bin/env python3 2# 3# Copyright 2021 - The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17import dataclasses 18import re 19import time 20from typing import List 21 22from acts import asserts 23from acts_contrib.test_utils.tel.tel_defines import SIM_STATE_PIN_REQUIRED 24from acts_contrib.test_utils.tel.tel_defines import SIM_STATE_PUK_REQUIRED 25from acts_contrib.test_utils.tel.tel_test_utils import is_sim_ready 26from acts_contrib.test_utils.tel.tel_test_utils import power_off_sim 27from acts_contrib.test_utils.tel.tel_test_utils import power_on_sim 28 29AT_COMMAND_INSTRUMENTATION = 'com.google.mdstest/com.google.mdstest.instrument.ModemATCommandInstrumentation' 30AT_COMMAND_FAILURE = 'INSTRUMENTATION_RESULT: result=FAILURE' 31LAB_PSIM_ADM_PW = '3131313131313131' 32LAB_ESIM_ADM_PW = '35363738FFFFFFFF' 33LAB_SIM_DEFAULT_PIN1 = '1234' 34LAB_SIM_DEFAULT_PUK1 = '12345678' 35UI_ELEMENT_TEXT_SECURITY_SIM_CARD_LOCK = 'SIM card lock' 36UI_ELEMENT_TEXT_LOCK_SIM_SET = 'Lock SIM card' 37UI_ELEMENT_TEXT_OK = 'OK' 38SHORT_MNC_LENGTH = 2 39 40 41@dataclasses.dataclass 42class SimInfo: 43 sub_id: int 44 slot_index: int 45 imsi: str 46 mcc_mnc: str 47 msin: str 48 display_name: str 49 50 51def get_sim_info(ad) -> List[SimInfo]: 52 """Get Lab SIM subscription information. 53 54 Args: 55 ad: Android device obj. 56 57 Returns: 58 List[SimInfo]: A list of sim information dataclass 59 """ 60 sim_info = [] 61 sub_info_list = ad.droid.subscriptionGetActiveSubInfoList() 62 if not sub_info_list: 63 asserts.skip('No Valid SIM in device') 64 for sub_info in sub_info_list: 65 sub_id = sub_info['subscriptionId'] 66 imsi = get_sim_imsi(ad, sub_id) 67 mcc_mnc = get_sim_mcc_mnc(ad, sub_id) 68 msin = get_sim_msin(imsi, mcc_mnc) 69 sim_info.append( 70 SimInfo( 71 sub_id=sub_id, 72 slot_index=sub_info['simSlotIndex'], 73 imsi=imsi, 74 mcc_mnc=mcc_mnc, 75 msin=msin, 76 display_name=sub_info['displayName'])) 77 ad.log.info(sim_info) 78 return sim_info 79 80 81def get_sim_msin(imsi, mcc_mnc): 82 """Split IMSI to get msin value.""" 83 msin = imsi.split(mcc_mnc)[1] 84 return msin 85 86 87def get_sim_mcc_mnc(ad, sub_id): 88 """Get SIM MCC+MNC value by sub id.""" 89 return ad.droid.telephonyGetSimOperatorForSubscription(sub_id) 90 91 92def get_sim_imsi(ad, sub_id): 93 """Get SIM IMSI value by sub id.""" 94 return ad.droid.telephonyGetSubscriberIdForSubscription(sub_id) 95 96 97def unlock_sim_dsds(ad, 98 dsds=False, 99 pin=LAB_SIM_DEFAULT_PIN1, 100 puk=LAB_SIM_DEFAULT_PUK1) -> bool: 101 """Unlock SIM pin1/puk1 on single or dual sim mode. 102 103 Args: 104 ad: Android device obj. 105 dsds: True is dual sim mode, use adb command to unlock. 106 pin: pin1 code, use LAB_DEFAULT_PIN1 for default value. 107 puk: puk1 code, use LAB_DEFAULT_PUK1 for default value. 108 109 Returns: 110 True if unlock sim success. False otherwise. 111 """ 112 ad.unlock_screen() 113 ad.log.info('[Dual_sim=%s] Unlock SIM', dsds) 114 if not dsds: 115 if is_sim_pin_locked(ad): 116 ad.log.info('Unlock SIM pin') 117 ad.droid.telephonySupplyPin(pin) 118 elif is_sim_puk_locked(ad): 119 ad.log.info('Unlock SIM puk') 120 ad.droid.telephonySupplyPuk(puk, pin) 121 time.sleep(1) 122 return is_sim_ready(ad.log, ad) 123 else: 124 # Checks both pSIM and eSIM states. 125 for slot_index in range(2): 126 if is_sim_pin_locked(ad, slot_index): 127 ad.log.info('[Slot index=%s] Unlock SIM PIN', slot_index) 128 if not unlock_pin_by_mds(ad, slot_index, pin): 129 ad.log.info('[Slot index=%s] AT+CPIN unlock error', slot_index) 130 elif is_sim_puk_locked(ad, slot_index): 131 ad.log.info('[Slot index=%s] Unlock SIM PUK', slot_index) 132 unlock_puk_by_adb(ad, pin, puk) 133 time.sleep(1) 134 if not is_sim_ready(ad.log, ad, slot_index): 135 return False 136 return True 137 138 139def unlock_puk_by_mds(ad, slot_index, pin, puk) -> bool: 140 """Runs AT command to disable SIM PUK1 locked. 141 142 Args: 143 ad: Android device obj. 144 slot_index: sim slot id. 145 pin: pin1 code. 146 puk: puk1 code. 147 148 Returns: 149 True if response 'OK'. False otherwise. 150 """ 151 set_at_command_channel(ad, slot_index) 152 command = r'AT+CPIN=\"' + puk + r'\",\"' + pin + r'\"' 153 cmd = (f'am instrument -w -e request "{command}" ' 154 f'-e response wait {AT_COMMAND_INSTRUMENTATION}') 155 ad.log.info('Unlock sim pin by AT command') 156 output = ad.adb.shell(cmd) 157 if grep(AT_COMMAND_FAILURE, output): 158 asserts.skip('Failed to run MDS test command') 159 if grep('OK', output): 160 return True 161 else: 162 return False 163 164 165def unlock_pin_by_mds(ad, slot_index, pin) -> bool: 166 """Runs AT command to disable SIM PIN1 locked. 167 168 Args: 169 ad: Android device obj. 170 slot_index: sim slot id. 171 pin: pin1 code, use LAB_DEFAULT_PIN1 for default value. 172 173 Returns: 174 True if response 'OK'. False otherwise. 175 """ 176 set_at_command_channel(ad, slot_index) 177 command = r'AT+CPIN=\"' + pin + r'\"' 178 cmd = (f'am instrument -w -e request "{command}" ' 179 f'-e response wait {AT_COMMAND_INSTRUMENTATION}') 180 ad.log.info('Unlock sim pin by AT command') 181 output = ad.adb.shell(cmd) 182 if grep(AT_COMMAND_FAILURE, output): 183 asserts.skip('Failed to run MDS test command') 184 if grep('OK', output): 185 return True 186 else: 187 return False 188 189 190def unlock_puk_by_adb(ad, pin, puk) -> None: 191 """Unlock puk1 by adb keycode. 192 193 Args: 194 ad: Android device obj. 195 pin: pin1 code. 196 puk: puk1 code. 197 198 """ 199 for key_code in puk: 200 ad.send_keycode(key_code) 201 time.sleep(1) 202 ad.send_keycode('ENTER') 203 time.sleep(1) 204 # PIN required 2 times 205 for _ in range(2): 206 for key_code in pin: 207 ad.send_keycode(key_code) 208 time.sleep(1) 209 ad.send_keycode('ENTER') 210 time.sleep(1) 211 212 213def lock_puk_by_mds(ad, slot_index) -> bool: 214 """Inputs wrong PIN1 code 3 times to make PUK1 locked. 215 216 Args: 217 ad: Android device obj. 218 slot_index: Sim slot id. 219 220 Returns: 221 True if SIM puk1 locked. False otherwise. 222 """ 223 ad.unlock_screen() 224 wrong_pin = '1111' 225 for count in range(3): 226 if not unlock_pin_by_mds(ad, slot_index, wrong_pin): 227 ad.log.info('Error input pin:%d', count+1) 228 time.sleep(1) 229 ad.reboot() 230 return is_sim_puk_locked(ad, slot_index) 231 232 233def is_sim_puk_locked(ad, slot_index=None) -> bool: 234 """Checks whether SIM puk1 is locked on single or dual sim mode. 235 236 Args: 237 ad: Android device obj. 238 slot_index: Check the SIM status for slot_index. 239 This is optional. If this is None, check default SIM. 240 241 Returns: 242 True if SIM puk1 locked. False otherwise. 243 """ 244 if slot_index is None: 245 status = ad.droid.telephonyGetSimState() 246 else: 247 status = ad.droid.telephonyGetSimStateForSlotId(slot_index) 248 if status != SIM_STATE_PUK_REQUIRED: 249 ad.log.info('Sim state is %s', status) 250 return False 251 return True 252 253 254def is_sim_pin_locked(ad, slot_index=None) -> bool: 255 """Checks whether SIM pin is locked on single or dual sim mode. 256 257 Args: 258 ad: Android device obj. 259 slot_index: Check the SIM status for slot_index. This is optional. If this 260 is None, check default SIM. 261 262 Returns: 263 True if SIM pin1 locked. False otherwise. 264 """ 265 if slot_index is None: 266 status = ad.droid.telephonyGetSimState() 267 else: 268 status = ad.droid.telephonyGetSimStateForSlotId(slot_index) 269 if status != SIM_STATE_PIN_REQUIRED: 270 ad.log.info('Sim state is %s', status) 271 return False 272 return True 273 274 275def set_at_command_channel(ad, slot_index: int) -> bool: 276 """Runs AT command to set AT command channel by MDS tool(pSIM=1,eSIM=2). 277 278 Args: 279 ad: Android device obj. 280 slot_index: Sim slot id. 281 282 Returns: 283 True if response 'OK'. False otherwise. 284 """ 285 channel = slot_index + 1 286 command = f'AT+CSUS={channel}' 287 cmd = (f'am instrument -w -e request "{command}" ' 288 f'-e response wait {AT_COMMAND_INSTRUMENTATION}') 289 ad.log.info('Set AT command channel') 290 output = ad.adb.shell(cmd) 291 if grep(AT_COMMAND_FAILURE, output): 292 asserts.skip('Failed to run MDS test command') 293 if grep('OK', output): 294 return True 295 else: 296 return False 297 298 299def sim_enable_pin_by_mds(ad, pin) -> bool: 300 """Runs AT command to enable SIM PIN1 locked by MDS tool. 301 302 Args: 303 ad: Android device obj. 304 pin: PIN1 code. 305 306 Returns: 307 True if response 'OK'. False otherwise. 308 """ 309 command = r'AT+CLCK=\"SC\",1,\"' + pin + r'\"' 310 cmd = (f'am instrument -w -e request "{command}" ' 311 f'-e response wait {AT_COMMAND_INSTRUMENTATION}') 312 ad.log.info('Enable sim pin by AT command') 313 output = ad.adb.shell(cmd) 314 if grep(AT_COMMAND_FAILURE, output): 315 asserts.skip('Failed to run MDS test command') 316 if grep('OK', output): 317 return True 318 else: 319 return False 320 321 322def sim_disable_pin_by_mds(ad, pin) -> bool: 323 """Runs AT command to disable SIM PIN1 locked by MDS tool. 324 325 Args: 326 ad: Android device obj. 327 pin: PIN1 code. 328 329 Returns: 330 True if response 'OK'. False otherwise. 331 """ 332 command = r'AT+CLCK=\"SC\",0,\"' + pin + r'\"' 333 cmd = (f'am instrument -w -e request "{command}" ' 334 f'-e response wait {AT_COMMAND_INSTRUMENTATION}') 335 ad.log.info('Disable sim pin by AT command') 336 output = ad.adb.shell(cmd) 337 if grep(AT_COMMAND_FAILURE, output): 338 asserts.skip('Failed to run MDS test command') 339 if grep('OK', output): 340 return True 341 else: 342 return False 343 344 345def set_sim_lock(ad, enable, slot_index, pin=LAB_SIM_DEFAULT_PIN1) -> bool: 346 """Enable/disable SIM card lock. 347 348 Args: 349 ad: Android device obj. 350 enable: True is to enable sim lock. False is to disable. 351 slot_index: Sim slot id. 352 pin: Pin1 code. 353 354 Returns: 355 True if enable/disable SIM lock successfully.False otherwise. 356 """ 357 if enable: 358 ad.log.info('[Slot:%d]Enable SIM pin1 locked by mds', slot_index) 359 if not set_at_command_channel(ad, slot_index): 360 ad.log.info('[Slot:%d] set AT command on MDS tool not OK', slot_index) 361 if sim_enable_pin_by_mds(ad, pin): 362 ad.reboot() 363 return is_sim_pin_locked(ad, slot_index) 364 else: 365 ad.log.info('[Slot:%d]Disable SIM pin1 locked by mds', slot_index) 366 if not set_at_command_channel(ad, slot_index): 367 ad.log.info('[Slot:%d] set AT command on MDS tool not OK', slot_index) 368 if sim_disable_pin_by_mds(ad, pin): 369 ad.reboot() 370 return is_sim_ready(ad.log, ad, slot_index) 371 372 373def activate_sim(ad, 374 slot_index=None, 375 dsds=False, 376 pin=LAB_SIM_DEFAULT_PIN1, 377 puk=LAB_SIM_DEFAULT_PUK1) -> bool: 378 """Activate sim state with slot id. Check sim lock state after activating. 379 380 Args: 381 ad: Android_device obj. 382 slot_index: Sim slot id. 383 dsds: True is dual sim mode, False is single mode. 384 pin: pin1 code, use LAB_DEFAULT_PIN1 for default value. 385 puk: puk1 code, use LAB_DEFAULT_PUK1 for default value. 386 Returns: 387 True if activate SIM lock successfully.False otherwise. 388 """ 389 ad.log.info('Disable SIM slot') 390 if not power_off_sim(ad, slot_index): 391 return False 392 time.sleep(2) 393 ad.log.info('Enable SIM slot') 394 if not power_on_sim(ad, slot_index): 395 return False 396 unlock_sim_dsds(ad, dsds, pin, puk) 397 return True 398 399 400def grep(regex, output): 401 """Returns the line in an output stream that matches a given regex pattern.""" 402 lines = output.strip().splitlines() 403 results = [] 404 for line in lines: 405 if re.search(regex, line): 406 results.append(line.strip()) 407 return results 408 409 410def modify_sim_imsi(ad, 411 new_imsi, 412 sim_info, 413 sim_adm=LAB_PSIM_ADM_PW): 414 """Uses ADB Content Provider Command to Read/Update EF (go/pmw-see-adb). 415 416 Args: 417 ad: Android_device obj. 418 new_imsi: New IMSI string to be set. 419 sim_info: SimInfo dataclass log. 420 sim_adm: SIM slot adm password. 421 """ 422 cmd = (f"content update --uri content://com.google.android.wsdsimeditor.EF/EFIMSI " 423 f"--bind data:s:'{new_imsi}' --bind format:s:'raw' " 424 f"--bind adm:s:'{sim_adm}' --where slot={sim_info.slot_index}") 425 ad.log.info('Update IMSI cmd = %s', cmd) 426 ad.adb.shell(cmd) 427 time.sleep(5) 428 modified_imsi = get_sim_imsi(ad, sim_info.sub_id) 429 asserts.assert_equal(new_imsi, modified_imsi) 430