• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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