1 /* 2 * Copyright (C) 2011 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 17 package android.telephony.cts; 18 19 import android.app.Instrumentation; 20 import android.os.ParcelFileDescriptor; 21 import android.telecom.TelecomManager; 22 import android.telephony.TelephonyManager; 23 24 import java.io.BufferedReader; 25 import java.io.FileInputStream; 26 import java.io.InputStream; 27 import java.io.InputStreamReader; 28 import java.lang.reflect.Field; 29 import java.nio.charset.StandardCharsets; 30 import java.util.function.BooleanSupplier; 31 32 public class TelephonyUtils { 33 34 /** 35 * See {@link TelecomManager#ENABLE_GET_CALL_STATE_PERMISSION_PROTECTION} 36 */ 37 public static final String ENABLE_GET_CALL_STATE_PERMISSION_PROTECTION_STRING = 38 "ENABLE_GET_CALL_STATE_PERMISSION_PROTECTION"; 39 40 private static final String COMMAND_ADD_TEST_EMERGENCY_NUMBER = 41 "cmd phone emergency-number-test-mode -a "; 42 43 private static final String COMMAND_REMOVE_TEST_EMERGENCY_NUMBER = 44 "cmd phone emergency-number-test-mode -r "; 45 46 private static final String COMMAND_END_BLOCK_SUPPRESSION = "cmd phone end-block-suppression"; 47 48 private static final String COMMAND_FLUSH_TELEPHONY_METRICS = 49 "/system/bin/dumpsys activity service TelephonyDebugService --metricsproto"; 50 51 private static final String COMMAND_AM_COMPAT = "am compat "; 52 53 public static final String CTS_APP_PACKAGE = "android.telephony.cts"; 54 public static final String CTS_APP_PACKAGE2 = "android.telephony2.cts"; 55 56 private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 57 'A', 'B', 'C', 'D', 'E', 'F' }; 58 addTestEmergencyNumber(Instrumentation instr, String testNumber)59 public static void addTestEmergencyNumber(Instrumentation instr, String testNumber) 60 throws Exception { 61 executeShellCommand(instr, COMMAND_ADD_TEST_EMERGENCY_NUMBER + testNumber); 62 } 63 removeTestEmergencyNumber(Instrumentation instr, String testNumber)64 public static void removeTestEmergencyNumber(Instrumentation instr, String testNumber) 65 throws Exception { 66 executeShellCommand(instr, COMMAND_REMOVE_TEST_EMERGENCY_NUMBER + testNumber); 67 } 68 endBlockSuppression(Instrumentation instr)69 public static void endBlockSuppression(Instrumentation instr) throws Exception { 70 executeShellCommand(instr, COMMAND_END_BLOCK_SUPPRESSION); 71 } 72 flushTelephonyMetrics(Instrumentation instr)73 public static void flushTelephonyMetrics(Instrumentation instr) throws Exception { 74 executeShellCommand(instr, COMMAND_FLUSH_TELEPHONY_METRICS); 75 } 76 enableCompatCommand(Instrumentation instr, String pkgName, String commandName)77 public static void enableCompatCommand(Instrumentation instr, String pkgName, 78 String commandName) throws Exception { 79 executeShellCommand(instr, COMMAND_AM_COMPAT + "enable --no-kill " + commandName + " " 80 + pkgName); 81 } 82 disableCompatCommand(Instrumentation instr, String pkgName, String commandName)83 public static void disableCompatCommand(Instrumentation instr, String pkgName, 84 String commandName) throws Exception { 85 executeShellCommand(instr, COMMAND_AM_COMPAT + "disable --no-kill " + commandName + " " 86 + pkgName); 87 } 88 resetCompatCommand(Instrumentation instr, String pkgName, String commandName)89 public static void resetCompatCommand(Instrumentation instr, String pkgName, 90 String commandName) throws Exception { 91 executeShellCommand(instr, COMMAND_AM_COMPAT + "reset --no-kill " + commandName + " " 92 + pkgName); 93 } 94 isSkt(TelephonyManager telephonyManager)95 public static boolean isSkt(TelephonyManager telephonyManager) { 96 return isOperator(telephonyManager, "45005"); 97 } 98 isKt(TelephonyManager telephonyManager)99 public static boolean isKt(TelephonyManager telephonyManager) { 100 return isOperator(telephonyManager, "45002") 101 || isOperator(telephonyManager, "45004") 102 || isOperator(telephonyManager, "45008"); 103 } 104 isOperator(TelephonyManager telephonyManager, String operator)105 private static boolean isOperator(TelephonyManager telephonyManager, String operator) { 106 String simOperator = telephonyManager.getSimOperator(); 107 return simOperator != null && simOperator.equals(operator); 108 } 109 parseErrorCodeToString(int errorCode, Class<?> containingClass, String prefix)110 public static String parseErrorCodeToString(int errorCode, 111 Class<?> containingClass, String prefix) { 112 for (Field field : containingClass.getDeclaredFields()) { 113 if (field.getName().startsWith(prefix)) { 114 if (field.getType() == Integer.TYPE) { 115 field.setAccessible(true); 116 try { 117 if (field.getInt(null) == errorCode) { 118 return field.getName(); 119 } 120 } catch (IllegalAccessException e) { 121 continue; 122 } 123 } 124 } 125 } 126 return String.format("??%d??", errorCode); 127 } 128 129 /** 130 * Executes the given shell command and returns the output in a string. Note that even 131 * if we don't care about the output, we have to read the stream completely to make the 132 * command execute. 133 */ executeShellCommand(Instrumentation instrumentation, String command)134 public static String executeShellCommand(Instrumentation instrumentation, 135 String command) throws Exception { 136 final ParcelFileDescriptor pfd = 137 instrumentation.getUiAutomation().executeShellCommand(command); 138 BufferedReader br = null; 139 try (InputStream in = new FileInputStream(pfd.getFileDescriptor())) { 140 br = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8)); 141 String str = null; 142 StringBuilder out = new StringBuilder(); 143 while ((str = br.readLine()) != null) { 144 out.append(str); 145 } 146 return out.toString(); 147 } finally { 148 if (br != null) { 149 closeQuietly(br); 150 } 151 closeQuietly(pfd); 152 } 153 } 154 closeQuietly(AutoCloseable closeable)155 private static void closeQuietly(AutoCloseable closeable) { 156 if (closeable != null) { 157 try { 158 closeable.close(); 159 } catch (RuntimeException rethrown) { 160 throw rethrown; 161 } catch (Exception ignored) { 162 } 163 } 164 } 165 pollUntilTrue(BooleanSupplier s, int times, int timeoutMs)166 public static boolean pollUntilTrue(BooleanSupplier s, int times, int timeoutMs) { 167 boolean successful = false; 168 for (int i = 0; i < times; i++) { 169 successful = s.getAsBoolean(); 170 if (successful) break; 171 try { 172 Thread.sleep(timeoutMs); 173 } catch (InterruptedException e) { } 174 } 175 return successful; 176 } 177 toHexString(byte[] array)178 public static String toHexString(byte[] array) { 179 int length = array.length; 180 char[] buf = new char[length * 2]; 181 182 int bufIndex = 0; 183 for (byte b : array) { 184 buf[bufIndex++] = HEX_DIGITS[(b >>> 4) & 0x0F]; 185 buf[bufIndex++] = HEX_DIGITS[b & 0x0F]; 186 } 187 188 return new String(buf); 189 } 190 toByte(char c)191 private static int toByte(char c) { 192 if (c >= '0' && c <= '9') return (c - '0'); 193 if (c >= 'A' && c <= 'F') return (c - 'A' + 10); 194 if (c >= 'a' && c <= 'f') return (c - 'a' + 10); 195 196 throw new RuntimeException("Invalid hex char '" + c + "'"); 197 } 198 hexStringToByteArray(String hexString)199 public static byte[] hexStringToByteArray(String hexString) { 200 int length = hexString.length(); 201 byte[] buffer = new byte[length / 2]; 202 203 for (int i = 0; i < length; i += 2) { 204 buffer[i / 2] = 205 (byte) ((toByte(hexString.charAt(i)) << 4) | toByte(hexString.charAt(i + 1))); 206 } 207 208 return buffer; 209 } 210 } 211