• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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 com.android.server.wifi;
18 
19 import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
20 import static android.content.pm.PackageManager.FEATURE_DEVICE_ADMIN;
21 
22 import android.annotation.NonNull;
23 import android.app.ActivityManager;
24 import android.app.AlertDialog;
25 import android.app.Notification;
26 import android.app.PendingIntent;
27 import android.app.admin.DevicePolicyManager;
28 import android.content.ContentResolver;
29 import android.content.Context;
30 import android.content.Intent;
31 import android.content.pm.ApplicationInfo;
32 import android.content.pm.PackageManager;
33 import android.content.pm.ResolveInfo;
34 import android.content.res.Configuration;
35 import android.database.ContentObserver;
36 import android.net.TrafficStats;
37 import android.net.Uri;
38 import android.net.ip.IpClientCallbacks;
39 import android.net.ip.IpClientUtil;
40 import android.os.PersistableBundle;
41 import android.os.Process;
42 import android.os.UserHandle;
43 import android.os.WorkSource;
44 import android.provider.Settings;
45 import android.security.KeyChain;
46 import android.telephony.CarrierConfigManager;
47 import android.util.Log;
48 import android.widget.Toast;
49 
50 import java.util.List;
51 import java.util.NoSuchElementException;
52 
53 /**
54  * This class allows overriding objects with mocks to write unit tests
55  */
56 public class FrameworkFacade {
57     public static final String TAG = "FrameworkFacade";
58 
59     private ContentResolver mContentResolver = null;
60     private CarrierConfigManager mCarrierConfigManager = null;
61     private ActivityManager mActivityManager = null;
62 
63     // verbose logging controlled by user
64     private static final int VERBOSE_LOGGING_ALWAYS_ON_LEVEL_NONE = 0;
65     // verbose logging on by default for userdebug
66     private static final int VERBOSE_LOGGING_ALWAYS_ON_LEVEL_USERDEBUG = 1;
67     // verbose logging on by default for all builds -->
68     private static final int VERBOSE_LOGGING_ALWAYS_ON_LEVEL_ALL = 2;
69 
getContentResolver(Context context)70     private ContentResolver getContentResolver(Context context) {
71         if (mContentResolver == null) {
72             mContentResolver = context.getContentResolver();
73         }
74         return mContentResolver;
75     }
76 
getCarrierConfigManager(Context context)77     private CarrierConfigManager getCarrierConfigManager(Context context) {
78         if (mCarrierConfigManager == null) {
79             mCarrierConfigManager =
80                 (CarrierConfigManager) context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
81         }
82         return mCarrierConfigManager;
83     }
84 
getActivityManager(Context context)85     private ActivityManager getActivityManager(Context context) {
86         if (mActivityManager == null) {
87             mActivityManager =
88                 (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
89         }
90         return mActivityManager;
91     }
92 
93     /**
94      * Mockable setter for Settings.Global
95      */
setIntegerSetting(ContentResolver contentResolver, String name, int value)96     public boolean setIntegerSetting(ContentResolver contentResolver, String name, int value) {
97         return Settings.Global.putInt(contentResolver, name, value);
98     }
99 
100     /**
101      * Mockable getter for Settings.Global
102      */
getIntegerSetting(ContentResolver contentResolver, String name, int def)103     public int getIntegerSetting(ContentResolver contentResolver, String name, int def) {
104         return Settings.Global.getInt(contentResolver, name, def);
105     }
106 
setIntegerSetting(Context context, String name, int def)107     public boolean setIntegerSetting(Context context, String name, int def) {
108         return Settings.Global.putInt(getContentResolver(context), name, def);
109     }
110 
getIntegerSetting(Context context, String name, int def)111     public int getIntegerSetting(Context context, String name, int def) {
112         return Settings.Global.getInt(getContentResolver(context), name, def);
113     }
114 
getLongSetting(Context context, String name, long def)115     public long getLongSetting(Context context, String name, long def) {
116         return Settings.Global.getLong(getContentResolver(context), name, def);
117     }
118 
setStringSetting(Context context, String name, String def)119     public boolean setStringSetting(Context context, String name, String def) {
120         return Settings.Global.putString(getContentResolver(context), name, def);
121     }
122 
getStringSetting(Context context, String name)123     public String getStringSetting(Context context, String name) {
124         return Settings.Global.getString(getContentResolver(context), name);
125     }
126 
127     /**
128      * Mockable facade to Settings.Secure.getInt(.).
129      */
getSecureIntegerSetting(Context context, String name, int def)130     public int getSecureIntegerSetting(Context context, String name, int def) {
131         return Settings.Secure.getInt(getContentResolver(context), name, def);
132     }
133 
134     /**
135      * Mockable facade to Settings.Secure.getString(.).
136      */
getSecureStringSetting(Context context, String name)137     public String getSecureStringSetting(Context context, String name) {
138         return Settings.Secure.getString(getContentResolver(context), name);
139     }
140 
141     /**
142      * Returns whether the device is in NIAP mode or not.
143      */
isNiapModeOn(Context context)144     public boolean isNiapModeOn(Context context) {
145         DevicePolicyManager devicePolicyManager =
146                 context.getSystemService(DevicePolicyManager.class);
147         if (devicePolicyManager == null
148                 && context.getPackageManager().hasSystemFeature(FEATURE_DEVICE_ADMIN)) {
149             Log.e(TAG, "Error retrieving DPM service");
150         }
151         if (devicePolicyManager == null) return false;
152         return devicePolicyManager.isCommonCriteriaModeEnabled(null);
153     }
154 
155     /**
156      * Helper method for classes to register a ContentObserver
157      * {@see ContentResolver#registerContentObserver(Uri,boolean,ContentObserver)}.
158      *
159      * @param context
160      * @param uri
161      * @param notifyForDescendants
162      * @param contentObserver
163      */
registerContentObserver(Context context, Uri uri, boolean notifyForDescendants, ContentObserver contentObserver)164     public void registerContentObserver(Context context, Uri uri,
165             boolean notifyForDescendants, ContentObserver contentObserver) {
166         getContentResolver(context).registerContentObserver(uri, notifyForDescendants,
167                 contentObserver);
168     }
169 
170     /**
171      * Helper method for classes to unregister a ContentObserver
172      * {@see ContentResolver#unregisterContentObserver(ContentObserver)}.
173      *
174      * @param context
175      * @param contentObserver
176      */
unregisterContentObserver(Context context, ContentObserver contentObserver)177     public void unregisterContentObserver(Context context, ContentObserver contentObserver) {
178         getContentResolver(context).unregisterContentObserver(contentObserver);
179     }
180 
getBroadcast(Context context, int requestCode, Intent intent, int flags)181     public PendingIntent getBroadcast(Context context, int requestCode, Intent intent, int flags) {
182         return PendingIntent.getBroadcast(context, requestCode, intent, flags);
183     }
184 
185     /**
186      * Wrapper for {@link PendingIntent#getActivity} using the current foreground user.
187      */
getActivity(Context context, int requestCode, Intent intent, int flags)188     public PendingIntent getActivity(Context context, int requestCode, Intent intent, int flags) {
189         return PendingIntent.getActivity(context.createContextAsUser(UserHandle.CURRENT, 0),
190                 requestCode, intent, flags);
191     }
192 
getConfigWiFiDisableInECBM(Context context)193     public boolean getConfigWiFiDisableInECBM(Context context) {
194         CarrierConfigManager configManager = getCarrierConfigManager(context);
195         if (configManager == null) {
196             return false;
197         }
198         PersistableBundle bundle = configManager.getConfig();
199         if (bundle == null) {
200             return false;
201         }
202         return bundle.getBoolean(CarrierConfigManager.KEY_CONFIG_WIFI_DISABLE_IN_ECBM);
203     }
204 
getTxPackets(String iface)205     public long getTxPackets(String iface) {
206         return TrafficStats.getTxPackets(iface);
207     }
208 
getRxPackets(String iface)209     public long getRxPackets(String iface) {
210         return TrafficStats.getRxPackets(iface);
211     }
212 
213     /**
214      * Request a new IpClient to be created asynchronously.
215      * @param context Context to use for creation.
216      * @param iface Interface the client should act on.
217      * @param callback IpClient event callbacks.
218      */
makeIpClient(Context context, String iface, IpClientCallbacks callback)219     public void makeIpClient(Context context, String iface, IpClientCallbacks callback) {
220         IpClientUtil.makeIpClient(context, iface, callback);
221     }
222 
223     /**
224      * Check if the provided uid is the app in the foreground.
225      * @param uid the uid to check
226      * @return true if the app is in the foreground, false otherwise
227      */
isAppForeground(Context context, int uid)228     public boolean isAppForeground(Context context, int uid) {
229         ActivityManager activityManager = getActivityManager(context);
230         if (activityManager == null) return false;
231         return activityManager.getUidImportance(uid) <= IMPORTANCE_VISIBLE;
232     }
233 
234     /**
235      * Create a new instance of {@link Notification.Builder}.
236      * @param context reference to a Context
237      * @param channelId ID of the notification channel
238      * @return an instance of Notification.Builder
239      */
makeNotificationBuilder(Context context, String channelId)240     public Notification.Builder makeNotificationBuilder(Context context, String channelId) {
241         return new Notification.Builder(context, channelId);
242     }
243 
244     /**
245      * Starts supplicant
246      */
startSupplicant()247     public boolean startSupplicant() {
248         try {
249             SupplicantManager.start();
250             return true;
251         } catch (NoSuchElementException e) {
252             return false;
253         }
254     }
255 
256     /**
257      * Stops supplicant
258      */
stopSupplicant()259     public void stopSupplicant() {
260         SupplicantManager.stop();
261     }
262 
263     /**
264      * Create a new instance of {@link AlertDialog.Builder}.
265      * @param context reference to a Context
266      * @return an instance of AlertDialog.Builder
267      * @deprecated Use {@link WifiDialogManager#createSimpleDialog} instead, or create another
268      *             dialog type in WifiDialogManager.
269      */
makeAlertDialogBuilder(Context context)270     public AlertDialog.Builder makeAlertDialogBuilder(Context context) {
271         boolean isDarkTheme = (context.getResources().getConfiguration().uiMode
272                 & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES;
273         return new AlertDialog.Builder(context, isDarkTheme
274                 ? android.R.style.Theme_DeviceDefault_Dialog_Alert : 0);
275     }
276 
277     /**
278      * Show a toast message
279      * @param context reference to a Context
280      * @param text the message to display
281      */
showToast(Context context, String text)282     public void showToast(Context context, String text) {
283         Toast toast = Toast.makeText(context, text, Toast.LENGTH_SHORT);
284         toast.show();
285     }
286 
287     /**
288      * Wrapper for {@link TrafficStats#getMobileTxBytes}.
289      */
getMobileTxBytes()290     public long getMobileTxBytes() {
291         return TrafficStats.getMobileTxBytes();
292     }
293 
294     /**
295      * Wrapper for {@link TrafficStats#getMobileRxBytes}.
296      */
getMobileRxBytes()297     public long getMobileRxBytes() {
298         return TrafficStats.getMobileRxBytes();
299     }
300 
301     /**
302      * Wrapper for {@link TrafficStats#getTotalTxBytes}.
303      */
getTotalTxBytes()304     public long getTotalTxBytes() {
305         return TrafficStats.getTotalTxBytes();
306     }
307 
308     /**
309      * Wrapper for {@link TrafficStats#getTotalRxBytes}.
310      */
getTotalRxBytes()311     public long getTotalRxBytes() {
312         return TrafficStats.getTotalRxBytes();
313     }
314 
315     private String mSettingsPackageName;
316 
317     /**
318      * @return Get settings package name.
319      */
getSettingsPackageName(@onNull Context context)320     public String getSettingsPackageName(@NonNull Context context) {
321         if (mSettingsPackageName != null) return mSettingsPackageName;
322 
323         Intent intent = new Intent(Settings.ACTION_WIFI_SETTINGS);
324         List<ResolveInfo> resolveInfos = context.getPackageManager().queryIntentActivitiesAsUser(
325                 intent, PackageManager.MATCH_SYSTEM_ONLY | PackageManager.MATCH_DEFAULT_ONLY,
326                 UserHandle.of(ActivityManager.getCurrentUser()));
327         if (resolveInfos == null || resolveInfos.isEmpty()) {
328             Log.e(TAG, "Failed to resolve wifi settings activity");
329             return null;
330         }
331         // Pick the first one if there are more than 1 since the list is ordered from best to worst.
332         mSettingsPackageName = resolveInfos.get(0).activityInfo.packageName;
333         return mSettingsPackageName;
334     }
335 
336     /**
337      * @return Get a worksource to blame settings apps.
338      */
getSettingsWorkSource(Context context)339     public WorkSource getSettingsWorkSource(Context context) {
340         String settingsPackageName = getSettingsPackageName(context);
341         if (settingsPackageName == null) return new WorkSource(Process.SYSTEM_UID);
342         return new WorkSource(Process.SYSTEM_UID, settingsPackageName);
343     }
344 
345     /**
346      * Returns whether a KeyChain key is granted to the WiFi stack.
347      */
hasWifiKeyGrantAsUser(Context context, UserHandle user, String alias)348     public boolean hasWifiKeyGrantAsUser(Context context, UserHandle user, String alias) {
349         return KeyChain.hasWifiKeyGrantAsUser(context, user, alias);
350     }
351 
352     /**
353      * Returns grant string for a given KeyChain alias or null if key not granted.
354      */
getWifiKeyGrantAsUser(Context context, UserHandle user, String alias)355     public String getWifiKeyGrantAsUser(Context context, UserHandle user, String alias) {
356         return KeyChain.getWifiKeyGrantAsUser(context, user, alias);
357     }
358 
359     /**
360      * Check if the request comes from foreground app/service.
361      * @param context Application context
362      * @param requestorPackageName requestor package name
363      * @return true if the requestor is foreground app/service.
364      */
isRequestFromForegroundAppOrService(Context context, @NonNull String requestorPackageName)365     public boolean isRequestFromForegroundAppOrService(Context context,
366             @NonNull String requestorPackageName) {
367         ActivityManager activityManager = getActivityManager(context);
368         if (activityManager == null) return false;
369         try {
370             return activityManager.getPackageImportance(requestorPackageName)
371                     <= ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
372         } catch (SecurityException e) {
373             Log.e(TAG, "Failed to check the app state", e);
374             return false;
375         }
376     }
377 
378     /**
379      * Check if the request comes from foreground app.
380      * @param context Application context
381      * @param requestorPackageName requestor package name
382      * @return true if requestor is foreground app.
383      */
isRequestFromForegroundApp(Context context, @NonNull String requestorPackageName)384     public boolean isRequestFromForegroundApp(Context context,
385             @NonNull String requestorPackageName) {
386         ActivityManager activityManager = getActivityManager(context);
387         if (activityManager == null) return false;
388         try {
389             return activityManager.getPackageImportance(requestorPackageName)
390                     <= ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
391         } catch (SecurityException e) {
392             Log.e(TAG, "Failed to check the app state", e);
393             return false;
394         }
395     }
396 
397     /**
398      * Check if the verbose always on is enabled
399      * @param alwaysOnLevel verbose logging always on level
400      * @param buildProperties build property of current build
401      * @return true if verbose always on is enabled on current build
402      */
isVerboseLoggingAlwaysOn(int alwaysOnLevel, @NonNull BuildProperties buildProperties)403     public boolean isVerboseLoggingAlwaysOn(int alwaysOnLevel,
404             @NonNull BuildProperties buildProperties) {
405         switch (alwaysOnLevel) {
406             // If the overlay setting enabled for all builds
407             case VERBOSE_LOGGING_ALWAYS_ON_LEVEL_ALL:
408                 return true;
409             //If the overlay setting enabled for userdebug builds only
410             case VERBOSE_LOGGING_ALWAYS_ON_LEVEL_USERDEBUG:
411                 // If it is a userdebug build
412                 if (buildProperties.isUserdebugBuild()) return true;
413                 break;
414             case VERBOSE_LOGGING_ALWAYS_ON_LEVEL_NONE:
415                 // nothing
416                 break;
417             default:
418                 Log.e(TAG, "Unrecognized config_wifiVerboseLoggingAlwaysOnLevel " + alwaysOnLevel);
419                 break;
420         }
421         return false;
422     }
423 
424     /**
425      * Return the (displayable) application name corresponding to the (uid, packageName).
426      */
getAppName(Context context, @NonNull String packageName, int uid)427     public @NonNull CharSequence getAppName(Context context, @NonNull String packageName, int uid) {
428         ApplicationInfo applicationInfo = null;
429         try {
430             applicationInfo = context.getPackageManager().getApplicationInfoAsUser(
431                     packageName, 0, UserHandle.getUserHandleForUid(uid));
432         } catch (PackageManager.NameNotFoundException e) {
433             Log.e(TAG, "Failed to find app name for " + packageName);
434             return "";
435         }
436         CharSequence appName = context.getPackageManager().getApplicationLabel(applicationInfo);
437         return (appName != null) ? appName : "";
438     }
439 }
440