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 189 result.putInt("result", connector.addNetwork(ssid, null, scanSsid)); 190 191 } else if ("addWpaPskNetwork".equals(method)) { 192 final String ssid = expectString("ssid"); 193 final boolean scanSsid = getBoolean("scan_ssid", false); 194 final String psk = expectString("psk"); 195 196 result.putInt("result", connector.addNetwork(ssid, psk, scanSsid)); 197 198 } else if ("associateNetwork".equals(method)) { 199 final int id = expectInteger("id"); 200 201 result.putBoolean("result", 202 wifiManager.enableNetwork(id, true /* disable other networks */)); 203 204 } else if ("disconnect".equals(method)) { 205 result.putBoolean("result", wifiManager.disconnect()); 206 207 } else if ("disableNetwork".equals(method)) { 208 final int id = expectInteger("id"); 209 210 result.putBoolean("result", wifiManager.disableNetwork(id)); 211 212 } else if ("isWifiEnabled".equals(method)) { 213 result.putBoolean("result", wifiManager.isWifiEnabled()); 214 215 } else if ("getIpAddress".equals(method)) { 216 final WifiInfo info = wifiManager.getConnectionInfo(); 217 final int addr = info.getIpAddress(); 218 219 // IP address is stored with the first octet in the lowest byte 220 final int a = (addr >> 0) & 0xff; 221 final int b = (addr >> 8) & 0xff; 222 final int c = (addr >> 16) & 0xff; 223 final int d = (addr >> 24) & 0xff; 224 225 result.putString("result", String.format("%s.%s.%s.%s", a, b, c, d)); 226 227 } else if ("getSSID".equals(method)) { 228 final WifiInfo info = wifiManager.getConnectionInfo(); 229 230 result.putString("result", info.getSSID()); 231 232 } else if ("getBSSID".equals(method)) { 233 final WifiInfo info = wifiManager.getConnectionInfo(); 234 235 result.putString("result", info.getBSSID()); 236 237 } else if ("removeAllNetworks".equals(method)) { 238 connector.removeAllNetworks(true); 239 240 result.putBoolean("result", true); 241 242 } else if ("removeNetwork".equals(method)) { 243 final int id = expectInteger("id"); 244 245 result.putBoolean("result", wifiManager.removeNetwork(id)); 246 247 } else if ("saveConfiguration".equals(method)) { 248 result.putBoolean("result", wifiManager.saveConfiguration()); 249 250 } else if ("getSupplicantState".equals(method)) { 251 String state = wifiManager.getConnectionInfo().getSupplicantState().name(); 252 result.putString("result", state); 253 254 } else if ("checkConnectivity".equals(method)) { 255 final String url = getString("urlToCheck", DEFAULT_URL_TO_CHECK); 256 257 result.putBoolean("result", connector.checkConnectivity(url)); 258 259 } else if ("connectToNetwork".equals(method)) { 260 final String ssid = expectString("ssid"); 261 final boolean scanSsid = getBoolean("scan_ssid", false); 262 final String psk = getString("psk", null); 263 final String pingUrl = getString("urlToCheck", DEFAULT_URL_TO_CHECK); 264 final long connectTimeout = getInteger("connectTimeout", -1); 265 connector.connectToNetwork(ssid, psk, pingUrl, connectTimeout, scanSsid); 266 267 result.putBoolean("result", true); 268 269 } else if ("disconnectFromNetwork".equals(method)) { 270 connector.disconnectFromNetwork(); 271 272 result.putBoolean("result", true); 273 274 } else if ("getWifiInfo".equals(method)) { 275 result.putString("result", connector.getWifiInfo().toString()); 276 277 } else if ("startMonitor".equals(method)) { 278 final int interval = expectInteger("interval"); 279 final String urlToCheck = getString("urlToCheck", DEFAULT_URL_TO_CHECK); 280 281 WifiMonitorService.enable(getContext(), interval, urlToCheck); 282 283 result.putBoolean("result", true); 284 285 } else if ("stopMonitor".equals(method)) { 286 final Context context = getContext(); 287 WifiMonitorService.disable(context); 288 289 result.putString("result", WifiMonitorService.getData(context)); 290 291 } else { 292 fail(String.format("Didn't recognize method '%s'", method)); 293 return; 294 } 295 } catch (WifiException | MissingArgException e) { 296 fail(e.getMessage()); 297 return; 298 } 299 300 finish(Activity.RESULT_OK, result); 301 } 302 } 303