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 package com.android.internal.telephony.util; 17 18 import static android.telephony.Annotation.DataState; 19 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.content.Context; 23 import android.content.pm.ComponentInfo; 24 import android.content.pm.PackageManager; 25 import android.content.pm.ResolveInfo; 26 import android.os.Binder; 27 import android.os.Bundle; 28 import android.os.PersistableBundle; 29 import android.os.RemoteException; 30 import android.os.SystemProperties; 31 import android.telephony.TelephonyManager; 32 33 import java.io.PrintWriter; 34 import java.util.Collections; 35 import java.util.List; 36 import java.util.concurrent.CountDownLatch; 37 import java.util.concurrent.Executor; 38 import java.util.concurrent.TimeUnit; 39 import java.util.function.Supplier; 40 41 /** 42 * This class provides various util functions 43 */ 44 public final class TelephonyUtils { 45 public static boolean IS_USER = "user".equals(android.os.Build.TYPE); 46 public static boolean IS_DEBUGGABLE = SystemProperties.getInt("ro.debuggable", 0) == 1; 47 48 public static final Executor DIRECT_EXECUTOR = Runnable::run; 49 50 /** 51 * Verify that caller holds {@link android.Manifest.permission#DUMP}. 52 * 53 * @return true if access should be granted. 54 */ checkDumpPermission(Context context, String tag, PrintWriter pw)55 public static boolean checkDumpPermission(Context context, String tag, PrintWriter pw) { 56 if (context.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 57 != PackageManager.PERMISSION_GRANTED) { 58 pw.println("Permission Denial: can't dump " + tag + " from from pid=" 59 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid() 60 + " due to missing android.permission.DUMP permission"); 61 return false; 62 } else { 63 return true; 64 } 65 } 66 67 /** Returns an empty string if the input is {@code null}. */ emptyIfNull(@ullable String str)68 public static String emptyIfNull(@Nullable String str) { 69 return str == null ? "" : str; 70 } 71 72 /** Returns an empty list if the input is {@code null}. */ emptyIfNull(@ullable List<T> cur)73 public static @NonNull <T> List<T> emptyIfNull(@Nullable List<T> cur) { 74 return cur == null ? Collections.emptyList() : cur; 75 } 76 77 /** Throws a {@link RuntimeException} that wrapps the {@link RemoteException}. */ rethrowAsRuntimeException(RemoteException remoteException)78 public static RuntimeException rethrowAsRuntimeException(RemoteException remoteException) { 79 throw new RuntimeException(remoteException); 80 } 81 82 /** 83 * Returns a {@link ComponentInfo} from the {@link ResolveInfo}, 84 * or throws an {@link IllegalStateException} if not available. 85 */ getComponentInfo(@onNull ResolveInfo resolveInfo)86 public static ComponentInfo getComponentInfo(@NonNull ResolveInfo resolveInfo) { 87 if (resolveInfo.activityInfo != null) return resolveInfo.activityInfo; 88 if (resolveInfo.serviceInfo != null) return resolveInfo.serviceInfo; 89 if (resolveInfo.providerInfo != null) return resolveInfo.providerInfo; 90 throw new IllegalStateException("Missing ComponentInfo!"); 91 } 92 93 /** 94 * Convenience method for running the provided action enclosed in 95 * {@link Binder#clearCallingIdentity}/{@link Binder#restoreCallingIdentity} 96 * 97 * Any exception thrown by the given action will need to be handled by caller. 98 * 99 */ runWithCleanCallingIdentity( @onNull Runnable action)100 public static void runWithCleanCallingIdentity( 101 @NonNull Runnable action) { 102 final long callingIdentity = Binder.clearCallingIdentity(); 103 try { 104 action.run(); 105 } finally { 106 Binder.restoreCallingIdentity(callingIdentity); 107 } 108 } 109 110 111 /** 112 * Convenience method for running the provided action enclosed in 113 * {@link Binder#clearCallingIdentity}/{@link Binder#restoreCallingIdentity} and return 114 * the result. 115 * 116 * Any exception thrown by the given action will need to be handled by caller. 117 * 118 */ runWithCleanCallingIdentity( @onNull Supplier<T> action)119 public static <T> T runWithCleanCallingIdentity( 120 @NonNull Supplier<T> action) { 121 final long callingIdentity = Binder.clearCallingIdentity(); 122 try { 123 return action.get(); 124 } finally { 125 Binder.restoreCallingIdentity(callingIdentity); 126 } 127 } 128 129 /** 130 * Filter values in bundle to only basic types. 131 */ filterValues(Bundle bundle)132 public static Bundle filterValues(Bundle bundle) { 133 Bundle ret = new Bundle(bundle); 134 for (String key : bundle.keySet()) { 135 Object value = bundle.get(key); 136 if ((value instanceof Integer) || (value instanceof Long) 137 || (value instanceof Double) || (value instanceof String) 138 || (value instanceof int[]) || (value instanceof long[]) 139 || (value instanceof double[]) || (value instanceof String[]) 140 || (value instanceof PersistableBundle) || (value == null) 141 || (value instanceof Boolean) || (value instanceof boolean[])) { 142 continue; 143 } 144 if (value instanceof Bundle) { 145 ret.putBundle(key, filterValues((Bundle) value)); 146 continue; 147 } 148 if (value.getClass().getName().startsWith("android.")) { 149 continue; 150 } 151 ret.remove(key); 152 } 153 return ret; 154 } 155 156 /** Wait for latch to trigger */ waitUntilReady(CountDownLatch latch, long timeoutMs)157 public static void waitUntilReady(CountDownLatch latch, long timeoutMs) { 158 try { 159 latch.await(timeoutMs, TimeUnit.MILLISECONDS); 160 } catch (InterruptedException ignored) { 161 } 162 } 163 164 /** 165 * Convert data state to string 166 * 167 * @return The data state in string format. 168 */ dataStateToString(@ataState int state)169 public static String dataStateToString(@DataState int state) { 170 switch (state) { 171 case TelephonyManager.DATA_DISCONNECTED: return "DISCONNECTED"; 172 case TelephonyManager.DATA_CONNECTING: return "CONNECTING"; 173 case TelephonyManager.DATA_CONNECTED: return "CONNECTED"; 174 case TelephonyManager.DATA_SUSPENDED: return "SUSPENDED"; 175 case TelephonyManager.DATA_DISCONNECTING: return "DISCONNECTING"; 176 case TelephonyManager.DATA_UNKNOWN: return "UNKNOWN"; 177 } 178 // This is the error case. The well-defined value for UNKNOWN is -1. 179 return "UNKNOWN(" + state + ")"; 180 } 181 } 182