1 /* 2 * Copyright (C) 2012 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.tradefed.utils.wifi; 18 import android.app.Activity; 19 import android.app.Instrumentation; 20 import android.content.Context; 21 import android.net.wifi.WifiInfo; 22 import android.net.wifi.WifiManager; 23 import android.os.Build; 24 import android.os.Bundle; 25 import android.text.TextUtils; 26 import android.util.Log; 27 28 import com.android.tradefed.utils.wifi.WifiConnector.WifiException; 29 30 /** 31 * An instrumentation class to manipulate Wi-Fi services on device. 32 * 33 * <p>adb shell am instrument -e method (method name) -e arg1 val1 -e arg2 val2 -e arg3 val3 -w 34 * com.android.tradefed.utils.wifi/.WifiUtil 35 */ 36 public class WifiUtil extends Instrumentation { 37 // FIXME: document exposed API methods and arguments 38 private static final String TAG = "WifiUtil"; 39 40 private static final String DEFAULT_URL_TO_CHECK = "http://www.google.com"; 41 private static final int API_LEVEL_Q_TBD = 29; 42 43 private Bundle mArguments; 44 45 static class MissingArgException extends Exception { MissingArgException(String msg)46 public MissingArgException(String msg) { 47 super(msg); 48 } 49 fromArg(String arg)50 public static MissingArgException fromArg(String arg) { 51 return new MissingArgException( 52 String.format("Error: missing mandatory argument '%s'", arg)); 53 } 54 } 55 56 @Override onCreate(Bundle arguments)57 public void onCreate(Bundle arguments) { 58 super.onCreate(arguments); 59 mArguments = arguments; 60 // elevate permission if on Qt or later 61 int apiLevel = Build.VERSION.SDK_INT; 62 if (!"REL".equals(Build.VERSION.CODENAME)) { 63 // add one extra if platform is under development 64 // i.e. trying to predict the next API level number 65 apiLevel++; 66 } 67 // on Qt or higher 68 // FIXEME: change to Build.VERSION_CODES.Q after API level is finalized 69 if (apiLevel >= API_LEVEL_Q_TBD) { 70 getUiAutomation().adoptShellPermissionIdentity(); 71 } 72 start(); 73 } 74 75 /** 76 * Fails an instrumentation request. 77 * 78 * @param errMsg an error message 79 */ fail(String errMsg)80 private void fail(String errMsg) { 81 Log.e(TAG, errMsg); 82 Bundle result = new Bundle(); 83 result.putString("error", errMsg); 84 finish(Activity.RESULT_CANCELED, result); 85 } 86 87 /** 88 * Returns the string value of an argument for the specified name, or throws 89 * {@link MissingArgException} if the argument is not found or empty. 90 * 91 * @param arg the name of an argument 92 * @return the value of an argument 93 * @throws MissingArgException if the argument is not found 94 */ expectString(String arg)95 private String expectString(String arg) throws MissingArgException { 96 String val = mArguments.getString(arg); 97 if (TextUtils.isEmpty(val)) { 98 throw MissingArgException.fromArg(arg); 99 } 100 101 return val; 102 } 103 104 /** 105 * Returns the value of a string argument for the specified name, or defaultValue if the 106 * argument is not found or empty. 107 * 108 * @param arg the name of an argument 109 * @param defaultValue a value to return if the argument is not found 110 * @return the value of an argument 111 */ getString(String arg, String defaultValue)112 private String getString(String arg, String defaultValue) { 113 String val = mArguments.getString(arg); 114 if (TextUtils.isEmpty(val)) { 115 return defaultValue; 116 } 117 118 return val; 119 } 120 121 /** 122 * Returns the integer value of an argument for the specified name, or throws 123 * {@link MissingArgException} if the argument is not found or cannot be parsed to an integer. 124 * 125 * @param arg the name of an argument 126 * @return the value of an argument 127 * @throws MissingArgException if the argument is not found 128 */ expectInteger(String arg)129 private int expectInteger(String arg) throws MissingArgException { 130 String val = expectString(arg); 131 int intVal; 132 try { 133 intVal = Integer.parseInt(val); 134 } catch (NumberFormatException e) { 135 final String msg = String.format("Couldn't parse arg '%s': %s", arg, 136 e.getMessage()); 137 throw new MissingArgException(msg); 138 } 139 140 return intVal; 141 } 142 143 /** 144 * Returns the integer value of an argument for the specified name, or defaultValue if the 145 * argument is not found, empty, or cannot be parsed. 146 * 147 * @param arg the name of an argument 148 * @param defaultValue a value to return if the argument is not found 149 * @return the value of an argument 150 */ getInteger(String arg, int defaultValue)151 private int getInteger(String arg, int defaultValue) { 152 try { 153 return expectInteger(arg); 154 } catch (MissingArgException e) { 155 return defaultValue; 156 } 157 } 158 getBoolean(String arg, boolean defaultValue)159 private boolean getBoolean(String arg, boolean defaultValue) { 160 try { 161 return Boolean.parseBoolean(expectString(arg)); 162 } catch (MissingArgException e) { 163 return defaultValue; 164 } 165 } 166 167 @Override onStart()168 public void onStart() { 169 super.onStart(); 170 final Bundle result = new Bundle(); 171 172 try { 173 final String method = expectString("method"); 174 175 WifiManager wifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); 176 if (wifiManager == null) { 177 fail("Couldn't get WifiManager reference; goodbye!"); 178 return; 179 } 180 WifiConnector connector = new WifiConnector(getContext()); 181 182 // As a pattern, method implementations below should gather arguments _first_, and then 183 // use those arguments so that the system is not left in an inconsistent state if an 184 // argument is missing in the middle of an implementation. 185 if ("addOpenNetwork".equals(method)) { 186 final String ssid = expectString("ssid"); 187 final boolean scanSsid = getBoolean("scan_ssid", false); 188 final boolean disableMacRandomization = 189 getBoolean("disableMacRandomization", false); 190 191 result.putInt( 192 "result", 193 connector.addNetwork(ssid, null, scanSsid, disableMacRandomization)); 194 195 } else if ("addWpaPskNetwork".equals(method)) { 196 final String ssid = expectString("ssid"); 197 final boolean scanSsid = getBoolean("scan_ssid", false); 198 final String psk = expectString("psk"); 199 final boolean disableMacRandomization = 200 getBoolean("disableMacRandomization", false); 201 202 result.putInt( 203 "result", 204 connector.addNetwork(ssid, psk, scanSsid, disableMacRandomization)); 205 206 } else if ("associateNetwork".equals(method)) { 207 final int id = expectInteger("id"); 208 209 result.putBoolean("result", 210 wifiManager.enableNetwork(id, true /* disable other networks */)); 211 212 } else if ("disconnect".equals(method)) { 213 result.putBoolean("result", wifiManager.disconnect()); 214 215 } else if ("disableNetwork".equals(method)) { 216 final int id = expectInteger("id"); 217 218 result.putBoolean("result", wifiManager.disableNetwork(id)); 219 220 } else if ("isWifiEnabled".equals(method)) { 221 result.putBoolean("result", wifiManager.isWifiEnabled()); 222 223 } else if ("getIpAddress".equals(method)) { 224 final WifiInfo info = wifiManager.getConnectionInfo(); 225 final int addr = info.getIpAddress(); 226 227 // IP address is stored with the first octet in the lowest byte 228 final int a = (addr >> 0) & 0xff; 229 final int b = (addr >> 8) & 0xff; 230 final int c = (addr >> 16) & 0xff; 231 final int d = (addr >> 24) & 0xff; 232 233 result.putString("result", String.format("%s.%s.%s.%s", a, b, c, d)); 234 235 } else if ("getSSID".equals(method)) { 236 final WifiInfo info = wifiManager.getConnectionInfo(); 237 238 result.putString("result", info.getSSID()); 239 240 } else if ("getBSSID".equals(method)) { 241 final WifiInfo info = wifiManager.getConnectionInfo(); 242 243 result.putString("result", info.getBSSID()); 244 245 } else if ("removeAllNetworks".equals(method)) { 246 connector.removeAllNetworks(true); 247 248 result.putBoolean("result", true); 249 250 } else if ("removeNetwork".equals(method)) { 251 final int id = expectInteger("id"); 252 253 result.putBoolean("result", wifiManager.removeNetwork(id)); 254 255 } else if ("saveConfiguration".equals(method)) { 256 result.putBoolean("result", wifiManager.saveConfiguration()); 257 258 } else if ("getSupplicantState".equals(method)) { 259 String state = wifiManager.getConnectionInfo().getSupplicantState().name(); 260 result.putString("result", state); 261 262 } else if ("checkConnectivity".equals(method)) { 263 final String url = getString("urlToCheck", DEFAULT_URL_TO_CHECK); 264 265 result.putBoolean("result", connector.checkConnectivity(url)); 266 267 } else if ("connectToNetwork".equals(method)) { 268 final String ssid = expectString("ssid"); 269 final boolean scanSsid = getBoolean("scan_ssid", false); 270 final String psk = getString("psk", null); 271 final String pingUrl = getString("urlToCheck", DEFAULT_URL_TO_CHECK); 272 final long connectTimeout = getInteger("connectTimeout", -1); 273 final boolean disableMacRandomization = 274 getBoolean("disableMacRandomization", false); 275 connector.connectToNetwork( 276 ssid, psk, pingUrl, connectTimeout, scanSsid, disableMacRandomization); 277 278 result.putBoolean("result", true); 279 280 } else if ("disconnectFromNetwork".equals(method)) { 281 connector.disconnectFromNetwork(); 282 283 result.putBoolean("result", true); 284 285 } else if ("getWifiInfo".equals(method)) { 286 result.putString("result", connector.getWifiInfo().toString()); 287 288 } else if ("startMonitor".equals(method)) { 289 final int interval = expectInteger("interval"); 290 final String urlToCheck = getString("urlToCheck", DEFAULT_URL_TO_CHECK); 291 292 WifiMonitorService.enable(getContext(), interval, urlToCheck); 293 294 result.putBoolean("result", true); 295 296 } else if ("stopMonitor".equals(method)) { 297 final Context context = getContext(); 298 WifiMonitorService.disable(context); 299 300 result.putString("result", WifiMonitorService.getData(context)); 301 302 } else { 303 fail(String.format("Didn't recognize method '%s'", method)); 304 return; 305 } 306 } catch (WifiException | MissingArgException e) { 307 fail(e.getMessage()); 308 return; 309 } 310 311 finish(Activity.RESULT_OK, result); 312 } 313 } 314