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