#!/usr/bin/env python3.4 # # Copyright 2017 - Google # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """ Test Script for Telephony Pre Check In Sanity """ import re import time from acts import signals from acts.utils import get_current_epoch_time from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest from acts_contrib.test_utils.tel.tel_bootloader_utils import reset_device_password from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phone_default_state from acts_contrib.test_utils.tel.tel_test_utils import abort_all_tests from acts_contrib.test_utils.tel.tel_test_utils import get_operator_name from acts_contrib.test_utils.tel.tel_test_utils import get_service_state_by_adb from acts_contrib.test_utils.tel.tel_test_utils import is_sim_lock_enabled from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode_by_adb from acts_contrib.test_utils.tel.tel_test_utils import unlock_sim from acts_contrib.test_utils.tel.tel_test_utils import verify_internet_connection from acts_contrib.test_utils.tel.tel_data_utils import wait_for_cell_data_connection from acts_contrib.test_utils.tel.tel_voice_utils import call_setup_teardown from acts_contrib.test_utils.tel.tel_voice_utils import dumpsys_last_call_info from acts_contrib.test_utils.tel.tel_voice_utils import dumpsys_last_call_number from acts_contrib.test_utils.tel.tel_voice_utils import dumpsys_new_call_info from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call_by_adb from acts_contrib.test_utils.tel.tel_voice_utils import initiate_call from acts_contrib.test_utils.tel.tel_voice_utils import initiate_emergency_dialer_call_by_adb from acts_contrib.test_utils.tel.tel_voice_utils import last_call_drop_reason CARRIER_OVERRIDE_CMD = ( "am broadcast -a com.google.android.carrier.action.LOCAL_OVERRIDE -n " "com.google.android.carrier/.ConfigOverridingReceiver --ez") IMS_FIRST = "carrier_use_ims_first_for_emergency_bool" ALLOW_NON_EMERGENCY_CALL = "allow_non_emergency_calls_in_ecm_bool" BLOCK_DURATION_CMD = "duration_blocking_disabled_after_emergency_int" BLOCK_DURATION = 300 class TelLiveEmergencyBase(TelephonyBaseTest): def setup_class(self): TelephonyBaseTest.setup_class(self) self.number_of_devices = 1 fake_number = self.user_params.get("fake_emergency_number", "411") self.fake_emergency_number = fake_number.strip("+").replace("-", "") self.my_devices = self.android_devices[:] for ad in self.android_devices: if not is_sim_lock_enabled(ad): self.setup_dut(ad) return True self.log.error("No device meets SIM READY or LOADED requirement") raise signals.TestAbortClass("No device meets SIM requirement") def setup_dut(self, ad): self.dut = ad output = self.dut.adb.shell("dumpsys carrier_config") self.default_settings = {} for setting in (IMS_FIRST, ALLOW_NON_EMERGENCY_CALL, BLOCK_DURATION_CMD): values = re.findall(r"%s = (\S+)" % setting, output) if values: self.default_settings[setting] = values[-1] else: self.default_settings[setting] = "" self.dut.adb.shell(" ".join( [CARRIER_OVERRIDE_CMD, BLOCK_DURATION_CMD, "%s" % BLOCK_DURATION])) self.dut_operator = get_operator_name(self.log, ad) if self.dut_operator == "tmo": self.fake_emergency_number = "611" elif self.dut_operator == "vzw": self.fake_emergency_number = "922" elif self.dut_operator == "spt": self.fake_emergency_number = "526" if len(self.my_devices) > 1: self.android_devices.remove(ad) self.android_devices.insert(0, ad) def teardown_class(self): self.android_devices = self.my_devices TelephonyBaseTest.teardown_class(self) def setup_test(self): if not unlock_sim(self.dut): abort_all_tests(self.dut.log, "unable to unlock SIM") self.expected_call_result = True def teardown_test(self): self.dut.ensure_screen_on() self.dut.exit_setup_wizard() reset_device_password(self.dut, None) output = self.dut.adb.shell("dumpsys carrier_config") for setting, state in self.default_settings.items(): values = re.findall(r"%s = (\S+)" % setting, output) if values and values[-1] != state: self.dut.adb.shell(" ".join( [CARRIER_OVERRIDE_CMD, setting, state])) ensure_phone_default_state(self.log, self.dut) def change_emergency_number_list(self): test_number = "%s:%s" % (self.fake_emergency_number, self.fake_emergency_number) output = self.dut.adb.getprop("ril.test.emergencynumber") if output != test_number: cmd = "setprop ril.test.emergencynumber %s" % test_number self.dut.log.info(cmd) self.dut.adb.shell(cmd) for _ in range(5): existing = self.dut.adb.getprop("ril.ecclist") self.dut.log.info("Existing ril.ecclist is: %s", existing) if self.fake_emergency_number in existing: return True emergency_numbers = "%s,%s" % (existing, self.fake_emergency_number) cmd = "setprop ril.ecclist %s" % emergency_numbers self.dut.log.info(cmd) self.dut.adb.shell(cmd) # After some system events, ril.ecclist might change # wait sometime for it to settle time.sleep(10) if self.fake_emergency_number in existing: return True return False def change_qcril_emergency_source_mcc_table(self): # This will add the fake number into emergency number list for a mcc # in qcril. Please note, the fake number will be send as an emergency # number by modem and reach the real 911 by this qcril_database_path = self.dut.adb.shell("find /data -iname qcril.db") if not qcril_database_path: return mcc = self.dut.droid.telephonyGetNetworkOperator() mcc = mcc[:3] self.dut.log.info("Add %s mcc %s in qcril_emergency_source_mcc_table") self.dut.adb.shell( "sqlite3 %s \"INSERT INTO qcril_emergency_source_mcc_table VALUES('%s','%s','','')\"" % (qcril_database_path, mcc, self.fake_emergency_number)) def fake_emergency_call_test(self, by_emergency_dialer=True, attemps=3): self.dut.log.info("ServiceState is in %s", get_service_state_by_adb(self.log, self.dut)) if by_emergency_dialer: dialing_func = initiate_emergency_dialer_call_by_adb callee = self.fake_emergency_number else: dialing_func = initiate_call # Initiate_call method has to have "+" in front # otherwise the number will be in dialer without dial out # with sl4a fascade. Need further investigation callee = "+%s" % self.fake_emergency_number for i in range(attemps): begin_time = get_current_epoch_time() result = True if not self.change_emergency_number_list(): self.dut.log.error("Unable to add number to ril.ecclist") return False time.sleep(1) last_call_number = dumpsys_last_call_number(self.dut) call_result = dialing_func(self.log, self.dut, callee) time.sleep(3) hangup_call_by_adb(self.dut) if not call_result: last_call_drop_reason(self.dut, begin_time) self.dut.send_keycode("BACK") self.dut.send_keycode("BACK") if not dumpsys_new_call_info(self.dut, last_call_number): result = False if call_result == self.expected_call_result: self.dut.log.info("Call to %s returns %s as expected", callee, self.expected_call_result) else: self.dut.log.info("Call to %s returns %s", callee, not self.expected_call_result) result = False if result: return True ecclist = self.dut.adb.getprop("ril.ecclist") self.dut.log.info("ril.ecclist = %s", ecclist) if self.fake_emergency_number in ecclist: if i == attemps - 1: self.dut.log.error("%s is in ril-ecclist, but call failed", self.fake_emergency_number) else: self.dut.log.warning( "%s is in ril-ecclist, but call failed, try again", self.fake_emergency_number) else: if i == attemps - 1: self.dut.log.error("Fail to write %s to ril-ecclist", self.fake_emergency_number) else: self.dut.log.info("%s is not in ril-ecclist", self.fake_emergency_number) self.dut.log.info("fake_emergency_call_test result is %s", result) return result def set_ims_first(self, state): output = self.dut.adb.shell( "dumpsys carrier_config | grep %s | tail -1" % IMS_FIRST) self.dut.log.info(output) if state in output: return cmd = " ".join([CARRIER_OVERRIDE_CMD, IMS_FIRST, state]) self.dut.log.info(cmd) self.dut.adb.shell(cmd) self.dut.log.info( self.dut.adb.shell( "dumpsys carrier_config | grep %s | tail -1" % IMS_FIRST)) def set_allow_non_emergency_call(self, state): output = self.dut.adb.shell( "dumpsys carrier_config | grep %s | tail -1" % ALLOW_NON_EMERGENCY_CALL) self.dut.log.info(output) if state in output: return cmd = " ".join([CARRIER_OVERRIDE_CMD, ALLOW_NON_EMERGENCY_CALL, state]) self.dut.log.info(cmd) self.dut.adb.shell(cmd) self.dut.log.info( self.dut.adb.shell("dumpsys carrier_config | grep %s | tail -1" % ALLOW_NON_EMERGENCY_CALL)) def check_emergency_call_back_mode(self, by_emergency_dialer=True, non_emergency_call_allowed=True, attemps=3): state = "true" if non_emergency_call_allowed else "false" self.set_allow_non_emergency_call(state) result = True for _ in range(attemps): if not self.change_emergency_number_list(): self.dut.log.error("Unable to add number to ril.ecclist") return False last_call_number = dumpsys_last_call_number(self.dut) self.dut.log.info("Hung up fake emergency call in ringing") if by_emergency_dialer: initiate_emergency_dialer_call_by_adb( self.log, self.dut, self.fake_emergency_number, timeout=0) else: callee = "+%s" % self.fake_emergency_number self.dut.droid.telecomCallNumber(callee) time.sleep(3) hangup_call_by_adb(self.dut) ecclist = self.dut.adb.getprop("ril.ecclist") self.dut.log.info("ril.ecclist = %s", ecclist) if self.fake_emergency_number in ecclist: break call_info = dumpsys_new_call_info(self.dut, last_call_number) if not call_info: return False call_tech = call_info.get("callTechnologies", "") if "CDMA" in call_tech: expected_ecbm = True expected_data = False expected_call = non_emergency_call_allowed elif "GSM" in call_tech: expected_ecbm = True expected_data = True expected_call = True else: expected_ecbm = False expected_data = True expected_call = True last_call_number = dumpsys_last_call_number(self.dut) begin_time = get_current_epoch_time() self.dut.ensure_screen_on() self.dut.exit_setup_wizard() reset_device_password(self.dut, None) call_check = call_setup_teardown( self.log, self.dut, self.android_devices[1], ad_hangup=self.dut) if call_check != expected_call: self.dut.log.error("Regular phone call is %s, expecting %s", call_check, expected_call) result = False call_info = dumpsys_new_call_info(self.dut, last_call_number) if not call_info: self.dut.log.error("New call is not in dumpsys telecom") return False if expected_ecbm: if "ecbm" in call_info["callProperties"]: self.dut.log.info("New call is in ecbm.") else: self.dut.log.error( "New call is not in emergency call back mode.") result = False else: if "ecbm" in call_info["callProperties"]: self.dut.log.error("New call is in emergency call back mode") result = False if not expected_data: if self.dut.droid.telephonyGetDataConnectionState(): self.dut.log.info( "Data connection is off as expected in ECB mode") self.dut.log.info("Wait for getting out of ecbm") if not wait_for_cell_data_connection(self.log, self.dut, True, 400): self.dut.log.error( "Data connection didn't come back after 5 minutes") result = False #if not self.dut.droid.telephonyGetDataConnectionState(): # self.dut.log.error( # "Data connection is not coming back") # result = False elif not verify_internet_connection(self.log, self.dut): self.dut.log.error( "Internet connection check failed after getting out of ECB" ) result = False else: self.dut.log.error("Data connection is not off in ECB mode") if not verify_internet_connection(self.log, self.dut, False): self.dut.log.error("Internet connection is not off") result = False else: if self.dut.droid.telephonyGetDataConnectionState(): self.dut.log.info("Data connection is on as expected") if not verify_internet_connection(self.log, self.dut): self.dut.log.error("Internet connection check failed") result = False else: self.dut.log.error("Data connection is off, expecting on") result = False if expected_call: return result elapsed_time = (get_current_epoch_time() - begin_time) / 1000 if elapsed_time < BLOCK_DURATION: time.sleep(BLOCK_DURATION - elapsed_time + 10) if not call_setup_teardown( self.log, self.dut, self.android_devices[1], ad_hangup=self.dut): self.dut.log.error("Regular phone call failed after out of ecbm") result = False return result def check_normal_call(self): result = True if "wfc" not in self.test_name: toggle_airplane_mode_by_adb(self.log, self.dut, False) self.dut.ensure_screen_on() self.dut.exit_setup_wizard() reset_device_password(self.dut, None) begin_time = get_current_epoch_time() if not call_setup_teardown( self.log, self.android_devices[1], self.dut, ad_hangup=self.android_devices[1]): self.dut.log.error("Regular MT phone call fails") self.dut.log.info("call_info = %s", dumpsys_last_call_info( self.dut)) result = False if not call_setup_teardown( self.log, self.dut, self.android_devices[1], ad_hangup=self.dut): self.dut.log.error("Regular MO phone call fails") self.dut.log.info("call_info = %s", dumpsys_last_call_info( self.dut)) result = False return result