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.PackageManager; 32 import android.content.pm.ResolveInfo; 33 import android.content.res.Configuration; 34 import android.database.ContentObserver; 35 import android.net.TrafficStats; 36 import android.net.Uri; 37 import android.net.ip.IpClientCallbacks; 38 import android.net.ip.IpClientUtil; 39 import android.os.PersistableBundle; 40 import android.os.Process; 41 import android.os.UserHandle; 42 import android.os.WorkSource; 43 import android.provider.Settings; 44 import android.security.KeyChain; 45 import android.telephony.CarrierConfigManager; 46 import android.util.Log; 47 import android.widget.Toast; 48 49 import com.android.server.wifi.util.WifiAsyncChannel; 50 51 import java.util.List; 52 import java.util.NoSuchElementException; 53 54 /** 55 * This class allows overriding objects with mocks to write unit tests 56 */ 57 public class FrameworkFacade { 58 public static final String TAG = "FrameworkFacade"; 59 60 private ContentResolver mContentResolver = null; 61 private CarrierConfigManager mCarrierConfigManager = null; 62 private ActivityManager mActivityManager = null; 63 getContentResolver(Context context)64 private ContentResolver getContentResolver(Context context) { 65 if (mContentResolver == null) { 66 mContentResolver = context.getContentResolver(); 67 } 68 return mContentResolver; 69 } 70 getCarrierConfigManager(Context context)71 private CarrierConfigManager getCarrierConfigManager(Context context) { 72 if (mCarrierConfigManager == null) { 73 mCarrierConfigManager = 74 (CarrierConfigManager) context.getSystemService(Context.CARRIER_CONFIG_SERVICE); 75 } 76 return mCarrierConfigManager; 77 } 78 getActivityManager(Context context)79 private ActivityManager getActivityManager(Context context) { 80 if (mActivityManager == null) { 81 mActivityManager = 82 (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); 83 } 84 return mActivityManager; 85 } 86 87 /** 88 * Mockable setter for Settings.Global 89 */ setIntegerSetting(ContentResolver contentResolver, String name, int value)90 public boolean setIntegerSetting(ContentResolver contentResolver, String name, int value) { 91 return Settings.Global.putInt(contentResolver, name, value); 92 } 93 94 /** 95 * Mockable getter for Settings.Global 96 */ getIntegerSetting(ContentResolver contentResolver, String name, int def)97 public int getIntegerSetting(ContentResolver contentResolver, String name, int def) { 98 return Settings.Global.getInt(contentResolver, name, def); 99 } 100 setIntegerSetting(Context context, String name, int def)101 public boolean setIntegerSetting(Context context, String name, int def) { 102 return Settings.Global.putInt(getContentResolver(context), name, def); 103 } 104 getIntegerSetting(Context context, String name, int def)105 public int getIntegerSetting(Context context, String name, int def) { 106 return Settings.Global.getInt(getContentResolver(context), name, def); 107 } 108 getLongSetting(Context context, String name, long def)109 public long getLongSetting(Context context, String name, long def) { 110 return Settings.Global.getLong(getContentResolver(context), name, def); 111 } 112 setStringSetting(Context context, String name, String def)113 public boolean setStringSetting(Context context, String name, String def) { 114 return Settings.Global.putString(getContentResolver(context), name, def); 115 } 116 getStringSetting(Context context, String name)117 public String getStringSetting(Context context, String name) { 118 return Settings.Global.getString(getContentResolver(context), name); 119 } 120 121 /** 122 * Mockable facade to Settings.Secure.getInt(.). 123 */ getSecureIntegerSetting(Context context, String name, int def)124 public int getSecureIntegerSetting(Context context, String name, int def) { 125 return Settings.Secure.getInt(getContentResolver(context), name, def); 126 } 127 128 /** 129 * Mockable facade to Settings.Secure.getString(.). 130 */ getSecureStringSetting(Context context, String name)131 public String getSecureStringSetting(Context context, String name) { 132 return Settings.Secure.getString(getContentResolver(context), name); 133 } 134 135 /** 136 * Returns whether the device is in NIAP mode or not. 137 */ isNiapModeOn(Context context)138 public boolean isNiapModeOn(Context context) { 139 DevicePolicyManager devicePolicyManager = 140 context.getSystemService(DevicePolicyManager.class); 141 if (devicePolicyManager == null 142 && context.getPackageManager().hasSystemFeature(FEATURE_DEVICE_ADMIN)) { 143 Log.e(TAG, "Error retrieving DPM service"); 144 } 145 if (devicePolicyManager == null) return false; 146 return devicePolicyManager.isCommonCriteriaModeEnabled(null); 147 } 148 149 /** 150 * Helper method for classes to register a ContentObserver 151 * {@see ContentResolver#registerContentObserver(Uri,boolean,ContentObserver)}. 152 * 153 * @param context 154 * @param uri 155 * @param notifyForDescendants 156 * @param contentObserver 157 */ registerContentObserver(Context context, Uri uri, boolean notifyForDescendants, ContentObserver contentObserver)158 public void registerContentObserver(Context context, Uri uri, 159 boolean notifyForDescendants, ContentObserver contentObserver) { 160 getContentResolver(context).registerContentObserver(uri, notifyForDescendants, 161 contentObserver); 162 } 163 164 /** 165 * Helper method for classes to unregister a ContentObserver 166 * {@see ContentResolver#unregisterContentObserver(ContentObserver)}. 167 * 168 * @param context 169 * @param contentObserver 170 */ unregisterContentObserver(Context context, ContentObserver contentObserver)171 public void unregisterContentObserver(Context context, ContentObserver contentObserver) { 172 getContentResolver(context).unregisterContentObserver(contentObserver); 173 } 174 getBroadcast(Context context, int requestCode, Intent intent, int flags)175 public PendingIntent getBroadcast(Context context, int requestCode, Intent intent, int flags) { 176 return PendingIntent.getBroadcast(context, requestCode, intent, flags); 177 } 178 179 /** 180 * Wrapper for {@link PendingIntent#getActivity}. 181 */ getActivity(Context context, int requestCode, Intent intent, int flags)182 public PendingIntent getActivity(Context context, int requestCode, Intent intent, int flags) { 183 return PendingIntent.getActivity(context, requestCode, intent, flags); 184 } 185 getConfigWiFiDisableInECBM(Context context)186 public boolean getConfigWiFiDisableInECBM(Context context) { 187 CarrierConfigManager configManager = getCarrierConfigManager(context); 188 if (configManager == null) { 189 return false; 190 } 191 PersistableBundle bundle = configManager.getConfig(); 192 if (bundle == null) { 193 return false; 194 } 195 return bundle.getBoolean(CarrierConfigManager.KEY_CONFIG_WIFI_DISABLE_IN_ECBM); 196 } 197 getTxPackets(String iface)198 public long getTxPackets(String iface) { 199 return TrafficStats.getTxPackets(iface); 200 } 201 getRxPackets(String iface)202 public long getRxPackets(String iface) { 203 return TrafficStats.getRxPackets(iface); 204 } 205 206 /** 207 * Request a new IpClient to be created asynchronously. 208 * @param context Context to use for creation. 209 * @param iface Interface the client should act on. 210 * @param callback IpClient event callbacks. 211 */ makeIpClient(Context context, String iface, IpClientCallbacks callback)212 public void makeIpClient(Context context, String iface, IpClientCallbacks callback) { 213 IpClientUtil.makeIpClient(context, iface, callback); 214 } 215 216 /** 217 * Create a new instance of WifiAsyncChannel 218 * @param tag String corresponding to the service creating the channel 219 * @return WifiAsyncChannel object created 220 */ makeWifiAsyncChannel(String tag)221 public WifiAsyncChannel makeWifiAsyncChannel(String tag) { 222 return new WifiAsyncChannel(tag); 223 } 224 225 /** 226 * Check if the provided uid is the app in the foreground. 227 * @param uid the uid to check 228 * @return true if the app is in the foreground, false otherwise 229 */ isAppForeground(Context context, int uid)230 public boolean isAppForeground(Context context, int uid) { 231 ActivityManager activityManager = getActivityManager(context); 232 if (activityManager == null) return false; 233 return activityManager.getUidImportance(uid) <= IMPORTANCE_VISIBLE; 234 } 235 236 /** 237 * Create a new instance of {@link Notification.Builder}. 238 * @param context reference to a Context 239 * @param channelId ID of the notification channel 240 * @return an instance of Notification.Builder 241 */ makeNotificationBuilder(Context context, String channelId)242 public Notification.Builder makeNotificationBuilder(Context context, String channelId) { 243 return new Notification.Builder(context, channelId); 244 } 245 246 /** 247 * Starts supplicant 248 */ startSupplicant()249 public boolean startSupplicant() { 250 try { 251 SupplicantManager.start(); 252 return true; 253 } catch (NoSuchElementException e) { 254 return false; 255 } 256 } 257 258 /** 259 * Stops supplicant 260 */ stopSupplicant()261 public void stopSupplicant() { 262 SupplicantManager.stop(); 263 } 264 265 /** 266 * Create a new instance of {@link AlertDialog.Builder}. 267 * @param context reference to a Context 268 * @return an instance of AlertDialog.Builder 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