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 17 package android.telephony.ims.cts; 18 19 import android.content.Context; 20 import android.content.Intent; 21 import android.content.pm.PackageManager; 22 import android.content.pm.ResolveInfo; 23 import android.os.Binder; 24 import android.service.carrier.CarrierService; 25 import android.telephony.SubscriptionInfo; 26 import android.telephony.SubscriptionManager; 27 import android.telephony.TelephonyManager; 28 29 import androidx.test.platform.app.InstrumentationRegistry; 30 31 import com.android.compatibility.common.util.ShellIdentityUtils; 32 33 import java.io.ByteArrayInputStream; 34 import java.io.ByteArrayOutputStream; 35 import java.io.IOException; 36 import java.util.List; 37 import java.util.concurrent.Callable; 38 import java.util.zip.GZIPInputStream; 39 import java.util.zip.GZIPOutputStream; 40 41 public class ImsUtils { 42 public static final boolean VDBG = true; 43 44 // ImsService rebind has an exponential backoff capping at 64 seconds. Wait for 70 seconds to 45 // allow for the new poll to happen in the framework. 46 public static final int TEST_TIMEOUT_MS = 70000; 47 48 // Id for non compressed auto configuration xml. 49 public static final int ITEM_NON_COMPRESSED = 2000; 50 // Id for compressed auto configuration xml. 51 public static final int ITEM_COMPRESSED = 2001; 52 shouldTestTelephony()53 public static boolean shouldTestTelephony() { 54 final PackageManager pm = InstrumentationRegistry.getInstrumentation().getContext() 55 .getPackageManager(); 56 return pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY); 57 } 58 shouldTestImsService()59 public static boolean shouldTestImsService() { 60 final PackageManager pm = InstrumentationRegistry.getInstrumentation().getContext() 61 .getPackageManager(); 62 boolean hasTelephony = pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY); 63 boolean hasIms = pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY_IMS); 64 return hasTelephony && hasIms; 65 } 66 shouldTestImsSingleRegistration()67 public static boolean shouldTestImsSingleRegistration() { 68 final PackageManager pm = InstrumentationRegistry.getInstrumentation().getContext() 69 .getPackageManager(); 70 boolean hasIms = pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY_IMS); 71 boolean hasSingleReg = pm.hasSystemFeature( 72 PackageManager.FEATURE_TELEPHONY_IMS_SINGLE_REGISTRATION); 73 return hasIms && hasSingleReg; 74 } 75 getPreferredActiveSubId()76 public static int getPreferredActiveSubId() { 77 Context context = InstrumentationRegistry.getInstrumentation().getContext(); 78 SubscriptionManager sm = (SubscriptionManager) context.getSystemService( 79 Context.TELEPHONY_SUBSCRIPTION_SERVICE); 80 List<SubscriptionInfo> infos = ShellIdentityUtils.invokeMethodWithShellPermissions(sm, 81 SubscriptionManager::getActiveSubscriptionInfoList); 82 83 int defaultSubId = SubscriptionManager.getDefaultVoiceSubscriptionId(); 84 if (defaultSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID 85 && isSubIdInInfoList(infos, defaultSubId)) { 86 return defaultSubId; 87 } 88 89 defaultSubId = SubscriptionManager.getDefaultSubscriptionId(); 90 if (defaultSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID 91 && isSubIdInInfoList(infos, defaultSubId)) { 92 return defaultSubId; 93 } 94 95 // Couldn't resolve a default. We can try to resolve a default using the active 96 // subscriptions. 97 if (!infos.isEmpty()) { 98 return infos.get(0).getSubscriptionId(); 99 } 100 // There must be at least one active subscription. 101 return SubscriptionManager.INVALID_SUBSCRIPTION_ID; 102 } 103 isSubIdInInfoList(List<SubscriptionInfo> infos, int subId)104 private static boolean isSubIdInInfoList(List<SubscriptionInfo> infos, int subId) { 105 return infos.stream().anyMatch(info -> info.getSubscriptionId() == subId); 106 } 107 108 /** 109 * If a carrier app implements CarrierMessagingService it can choose to take care of handling 110 * SMS OTT so SMS over IMS APIs won't be triggered which would be WAI so we do not run the tests 111 * if there exist a carrier app that declares a CarrierMessagingService 112 */ shouldRunSmsImsTests(int subId)113 public static boolean shouldRunSmsImsTests(int subId) { 114 if (!shouldTestImsService()) { 115 return false; 116 } 117 Context context = InstrumentationRegistry.getInstrumentation().getContext(); 118 TelephonyManager tm = 119 (TelephonyManager) InstrumentationRegistry.getInstrumentation().getContext() 120 .getSystemService(Context.TELEPHONY_SERVICE); 121 tm = tm.createForSubscriptionId(subId); 122 final long token = Binder.clearCallingIdentity(); 123 List<String> carrierPackages; 124 try { 125 carrierPackages = ShellIdentityUtils.invokeMethodWithShellPermissions(tm, 126 (m) -> m.getCarrierPackageNamesForIntent( 127 new Intent(CarrierService.CARRIER_SERVICE_INTERFACE))); 128 } finally { 129 Binder.restoreCallingIdentity(token); 130 } 131 132 if (carrierPackages == null || carrierPackages.size() == 0) { 133 return true; 134 } 135 final PackageManager packageManager = context.getPackageManager(); 136 Intent intent = new Intent("android.service.carrier.CarrierMessagingService"); 137 List<ResolveInfo> resolveInfos = packageManager.queryIntentServices(intent, 0); 138 for (ResolveInfo info : resolveInfos) { 139 if (carrierPackages.contains(info.serviceInfo.packageName)) { 140 return false; 141 } 142 } 143 144 return true; 145 } 146 147 /** 148 * Retry every 5 seconds until the condition is true or fail after TEST_TIMEOUT_MS seconds. 149 */ retryUntilTrue(Callable<Boolean> condition)150 public static boolean retryUntilTrue(Callable<Boolean> condition) throws Exception { 151 return retryUntilTrue(condition, TEST_TIMEOUT_MS, 14 /*numTries*/); 152 } 153 154 /** 155 * Retry every timeoutMs/numTimes until the condition is true or fail if the condition is never 156 * met. 157 */ retryUntilTrue(Callable<Boolean> condition, int timeoutMs, int numTimes)158 public static boolean retryUntilTrue(Callable<Boolean> condition, 159 int timeoutMs, int numTimes) throws Exception { 160 int sleepTime = timeoutMs / numTimes; 161 int retryCounter = 0; 162 while (retryCounter < numTimes) { 163 try { 164 Boolean isSuccessful = condition.call(); 165 isSuccessful = (isSuccessful == null) ? false : isSuccessful; 166 if (isSuccessful) return true; 167 } catch (Exception e) { 168 // we will retry 169 } 170 Thread.sleep(sleepTime); 171 retryCounter++; 172 } 173 return false; 174 } 175 176 /** 177 * compress the gzip format data 178 * @hide 179 */ compressGzip(byte[] data)180 public static byte[] compressGzip(byte[] data) { 181 if (data == null || data.length == 0) { 182 return data; 183 } 184 byte[] out = null; 185 try { 186 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(data.length); 187 GZIPOutputStream gzipCompressingStream = 188 new GZIPOutputStream(outputStream); 189 gzipCompressingStream.write(data); 190 gzipCompressingStream.close(); 191 out = outputStream.toByteArray(); 192 outputStream.close(); 193 } catch (IOException e) { 194 } 195 return out; 196 } 197 198 /** 199 * decompress the gzip format data 200 * @hide 201 */ decompressGzip(byte[] data)202 public static byte[] decompressGzip(byte[] data) { 203 if (data == null || data.length == 0) { 204 return data; 205 } 206 byte[] out = null; 207 try { 208 ByteArrayInputStream inputStream = new ByteArrayInputStream(data); 209 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 210 GZIPInputStream gzipDecompressingStream = 211 new GZIPInputStream(inputStream); 212 byte[] buf = new byte[1024]; 213 int size = gzipDecompressingStream.read(buf); 214 while (size >= 0) { 215 outputStream.write(buf, 0, size); 216 size = gzipDecompressingStream.read(buf); 217 } 218 gzipDecompressingStream.close(); 219 inputStream.close(); 220 out = outputStream.toByteArray(); 221 outputStream.close(); 222 } catch (IOException e) { 223 } 224 return out; 225 } 226 } 227