WifiNative.java revision bfed2d6c618e0bf2c271dad1f4acf6d29ebbea51
1/* 2 * Copyright (C) 2008 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 17package android.net.wifi; 18 19import android.net.wifi.p2p.WifiP2pConfig; 20import android.net.wifi.p2p.WifiP2pGroup; 21import android.net.wifi.p2p.WifiP2pDevice; 22import android.text.TextUtils; 23import android.util.Log; 24 25import java.io.InputStream; 26import java.lang.Process; 27import java.util.ArrayList; 28import java.util.List; 29 30/** 31 * Native calls for sending requests to the supplicant daemon, and for 32 * receiving asynchronous events. All methods of the form "xxxxCommand()" 33 * must be single-threaded, to avoid requests and responses initiated 34 * from multiple threads from being intermingled. 35 * <p/> 36 * Note that methods whose names are not of the form "xxxCommand()" do 37 * not talk to the supplicant daemon. 38 * Also, note that all WifiNative calls should happen in the 39 * WifiStateTracker class except for waitForEvent() call which is 40 * on a separate monitor channel for WifiMonitor 41 * 42 * TODO: clean up the API and move the functionality from JNI to here. We should 43 * be able to get everything done with doBooleanCommand, doIntCommand and 44 * doStringCommand native commands 45 * 46 * {@hide} 47 */ 48public class WifiNative { 49 50 static final int BLUETOOTH_COEXISTENCE_MODE_ENABLED = 0; 51 static final int BLUETOOTH_COEXISTENCE_MODE_DISABLED = 1; 52 static final int BLUETOOTH_COEXISTENCE_MODE_SENSE = 2; 53 54 public native static String getErrorString(int errorCode); 55 56 public native static boolean loadDriver(); 57 58 public native static boolean isDriverLoaded(); 59 60 public native static boolean unloadDriver(); 61 62 public native static boolean startSupplicant(); 63 64 public native static boolean startP2pSupplicant(); 65 66 /* Does a graceful shutdown of supplicant. Is a common stop function for both p2p and sta. 67 * 68 * Note that underneath we use a harsh-sounding "terminate" supplicant command 69 * for a graceful stop and a mild-sounding "stop" interface 70 * to kill the process 71 */ 72 public native static boolean stopSupplicant(); 73 74 /* Sends a kill signal to supplicant. To be used when we have lost connection 75 or when the supplicant is hung */ 76 public native static boolean killSupplicant(); 77 78 public native static boolean connectToSupplicant(); 79 80 public native static void closeSupplicantConnection(); 81 82 public native static boolean pingCommand(); 83 84 public native static boolean scanCommand(boolean forceActive); 85 86 public native static boolean setScanModeCommand(boolean setActive); 87 88 public native static String listNetworksCommand(); 89 90 public native static int addNetworkCommand(); 91 92 public native static boolean setNetworkVariableCommand(int netId, String name, String value); 93 94 public native static String getNetworkVariableCommand(int netId, String name); 95 96 public native static boolean removeNetworkCommand(int netId); 97 98 public native static boolean enableNetworkCommand(int netId, boolean disableOthers); 99 100 public native static boolean disableNetworkCommand(int netId); 101 102 public native static boolean reconnectCommand(); 103 104 public native static boolean reassociateCommand(); 105 106 public native static boolean disconnectCommand(); 107 108 public native static String statusCommand(); 109 110 public native static String getMacAddressCommand(); 111 112 public native static String scanResultsCommand(); 113 114 public native static boolean startDriverCommand(); 115 116 public native static boolean stopDriverCommand(); 117 118 119 /** 120 * Start filtering out Multicast V4 packets 121 * @return {@code true} if the operation succeeded, {@code false} otherwise 122 */ 123 public native static boolean startFilteringMulticastV4Packets(); 124 125 /** 126 * Stop filtering out Multicast V4 packets. 127 * @return {@code true} if the operation succeeded, {@code false} otherwise 128 */ 129 public native static boolean stopFilteringMulticastV4Packets(); 130 131 /** 132 * Start filtering out Multicast V6 packets 133 * @return {@code true} if the operation succeeded, {@code false} otherwise 134 */ 135 public native static boolean startFilteringMulticastV6Packets(); 136 137 /** 138 * Stop filtering out Multicast V6 packets. 139 * @return {@code true} if the operation succeeded, {@code false} otherwise 140 */ 141 public native static boolean stopFilteringMulticastV6Packets(); 142 143 public native static boolean setPowerModeCommand(int mode); 144 145 public native static int getBandCommand(); 146 147 public native static boolean setBandCommand(int band); 148 149 public native static int getPowerModeCommand(); 150 151 /** 152 * Sets the bluetooth coexistence mode. 153 * 154 * @param mode One of {@link #BLUETOOTH_COEXISTENCE_MODE_DISABLED}, 155 * {@link #BLUETOOTH_COEXISTENCE_MODE_ENABLED}, or 156 * {@link #BLUETOOTH_COEXISTENCE_MODE_SENSE}. 157 * @return Whether the mode was successfully set. 158 */ 159 public native static boolean setBluetoothCoexistenceModeCommand(int mode); 160 161 /** 162 * Enable or disable Bluetooth coexistence scan mode. When this mode is on, 163 * some of the low-level scan parameters used by the driver are changed to 164 * reduce interference with A2DP streaming. 165 * 166 * @param isSet whether to enable or disable this mode 167 * @return {@code true} if the command succeeded, {@code false} otherwise. 168 */ 169 public native static boolean setBluetoothCoexistenceScanModeCommand(boolean setCoexScanMode); 170 171 public native static boolean saveConfigCommand(); 172 173 public native static boolean reloadConfigCommand(); 174 175 public native static boolean setScanResultHandlingCommand(int mode); 176 177 public native static boolean addToBlacklistCommand(String bssid); 178 179 public native static boolean clearBlacklistCommand(); 180 181 public native static boolean startWpsPbcCommand(String bssid); 182 183 public native static boolean startWpsWithPinFromAccessPointCommand(String bssid, String apPin); 184 185 public native static String startWpsWithPinFromDeviceCommand(String bssid); 186 187 public native static boolean setSuspendOptimizationsCommand(boolean enabled); 188 189 public native static boolean setCountryCodeCommand(String countryCode); 190 191 /** 192 * Wait for the supplicant to send an event, returning the event string. 193 * @return the event string sent by the supplicant. 194 */ 195 public native static String waitForEvent(); 196 197 public native static void enableBackgroundScanCommand(boolean enable); 198 199 public native static void setScanIntervalCommand(int scanInterval); 200 201 private native static boolean doBooleanCommand(String command); 202 203 private native static int doIntCommand(String command); 204 205 private native static String doStringCommand(String command); 206 207 /** Example output: 208 * RSSI=-65 209 * LINKSPEED=48 210 * NOISE=9999 211 * FREQUENCY=0 212 */ 213 public static String signalPoll() { 214 return doStringCommand("SIGNAL_POLL"); 215 } 216 217 public static boolean wpsPbc() { 218 return doBooleanCommand("WPS_PBC"); 219 } 220 221 public static boolean wpsPin(String pin) { 222 return doBooleanCommand("WPS_PIN any " + pin); 223 } 224 225 public static boolean setPersistentReconnect(boolean enabled) { 226 int value = (enabled == true) ? 1 : 0; 227 return WifiNative.doBooleanCommand("SET persistent_reconnect " + value); 228 } 229 230 public static boolean setDeviceName(String name) { 231 return WifiNative.doBooleanCommand("SET device_name " + name); 232 } 233 234 public static boolean setDeviceType(String type) { 235 return WifiNative.doBooleanCommand("SET device_type " + type); 236 } 237 238 public static boolean setConfigMethods(String cfg) { 239 return WifiNative.doBooleanCommand("SET config_methods " + cfg); 240 } 241 242 public static boolean setP2pSsidPostfix(String postfix) { 243 return WifiNative.doBooleanCommand("SET p2p_ssid_postfix " + postfix); 244 } 245 246 public static boolean p2pFind() { 247 return doBooleanCommand("P2P_FIND"); 248 } 249 250 public static boolean p2pFind(int timeout) { 251 if (timeout <= 0) { 252 return p2pFind(); 253 } 254 return doBooleanCommand("P2P_FIND " + timeout); 255 } 256 257 public static boolean p2pListen() { 258 return doBooleanCommand("P2P_LISTEN"); 259 } 260 261 public static boolean p2pListen(int timeout) { 262 if (timeout <= 0) { 263 return p2pListen(); 264 } 265 return doBooleanCommand("P2P_LISTEN " + timeout); 266 } 267 268 public static boolean p2pFlush() { 269 return doBooleanCommand("P2P_FLUSH"); 270 } 271 272 /* p2p_connect <peer device address> <pbc|pin|PIN#> [label|display|keypad] 273 [persistent] [join|auth] [go_intent=<0..15>] [freq=<in MHz>] */ 274 public static String p2pConnect(WifiP2pConfig config, boolean joinExistingGroup) { 275 if (config == null) return null; 276 List<String> args = new ArrayList<String>(); 277 WpsInfo wps = config.wps; 278 args.add(config.deviceAddress); 279 280 switch (wps.setup) { 281 case WpsInfo.PBC: 282 args.add("pbc"); 283 break; 284 case WpsInfo.DISPLAY: 285 if (TextUtils.isEmpty(wps.pin)) { 286 args.add("pin"); 287 } else { 288 args.add(wps.pin); 289 } 290 args.add("display"); 291 break; 292 case WpsInfo.KEYPAD: 293 args.add(wps.pin); 294 args.add("keypad"); 295 break; 296 case WpsInfo.LABEL: 297 args.add(wps.pin); 298 args.add("label"); 299 default: 300 break; 301 } 302 303 //TODO: Add persist behavior once the supplicant interaction is fixed for both 304 // group and client scenarios 305 /* Persist unless there is an explicit request to not do so*/ 306 //if (config.persist != WifiP2pConfig.Persist.NO) args.add("persistent"); 307 308 if (joinExistingGroup) args.add("join"); 309 310 //TODO: This can be adapted based on device plugged in state and 311 //device battery state 312 int groupOwnerIntent = config.groupOwnerIntent; 313 if (groupOwnerIntent < 0 || groupOwnerIntent > 15) { 314 groupOwnerIntent = 7; //default value 315 } 316 args.add("go_intent=" + groupOwnerIntent); 317 318 String command = "P2P_CONNECT "; 319 for (String s : args) command += s + " "; 320 321 return doStringCommand(command); 322 } 323 324 public static boolean p2pCancelConnect() { 325 return doBooleanCommand("P2P_CANCEL"); 326 } 327 328 public static boolean p2pProvisionDiscovery(WifiP2pConfig config) { 329 if (config == null) return false; 330 331 switch (config.wps.setup) { 332 case WpsInfo.PBC: 333 return doBooleanCommand("P2P_PROV_DISC " + config.deviceAddress + " pbc"); 334 case WpsInfo.DISPLAY: 335 //We are doing display, so provision discovery is keypad 336 return doBooleanCommand("P2P_PROV_DISC " + config.deviceAddress + " keypad"); 337 case WpsInfo.KEYPAD: 338 //We are doing keypad, so provision discovery is display 339 return doBooleanCommand("P2P_PROV_DISC " + config.deviceAddress + " display"); 340 default: 341 break; 342 } 343 return false; 344 } 345 346 public static boolean p2pGroupAdd() { 347 return doBooleanCommand("P2P_GROUP_ADD"); 348 } 349 350 public static boolean p2pGroupRemove(String iface) { 351 if (iface == null) return false; 352 return doBooleanCommand("P2P_GROUP_REMOVE " + iface); 353 } 354 355 public static boolean p2pReject(String deviceAddress) { 356 return doBooleanCommand("P2P_REJECT " + deviceAddress); 357 } 358 359 /* Invite a peer to a group */ 360 public static boolean p2pInvite(WifiP2pGroup group, String deviceAddress) { 361 if (deviceAddress == null) return false; 362 363 if (group == null) { 364 return doBooleanCommand("P2P_INVITE peer=" + deviceAddress); 365 } else { 366 return doBooleanCommand("P2P_INVITE group=" + group.getInterface() 367 + " peer=" + deviceAddress + " go_dev_addr=" + group.getOwner().deviceAddress); 368 } 369 } 370 371 /* Reinvoke a persistent connection */ 372 public static boolean p2pReinvoke(int netId, String deviceAddress) { 373 if (deviceAddress == null || netId < 0) return false; 374 375 return doBooleanCommand("P2P_INVITE persistent=" + netId + " peer=" + deviceAddress); 376 } 377 378 379 public static String p2pGetInterfaceAddress(String deviceAddress) { 380 if (deviceAddress == null) return null; 381 382 // "p2p_peer deviceAddress" returns a multi-line result containing 383 // intended_addr=fa:7b:7a:42:82:13 384 String peerInfo = p2pPeer(deviceAddress); 385 if (peerInfo == null) return null; 386 String[] tokens= peerInfo.split("\n"); 387 388 for (String token : tokens) { 389 //TODO: update from interface_addr when wpa_supplicant implementation is fixed 390 if (token.startsWith("intended_addr=")) { 391 String[] nameValue = token.split("="); 392 if (nameValue.length != 2) break; 393 return nameValue[1]; 394 } 395 } 396 return null; 397 } 398 399 public static String p2pGetDeviceAddress() { 400 String status = statusCommand(); 401 if (status == null) return ""; 402 403 String[] tokens = status.split("\n"); 404 for (String token : tokens) { 405 if (token.startsWith("p2p_device_address=")) { 406 String[] nameValue = token.split("="); 407 if (nameValue.length != 2) break; 408 return nameValue[1]; 409 } 410 } 411 return ""; 412 } 413 414 public static String p2pPeer(String deviceAddress) { 415 return doStringCommand("P2P_PEER " + deviceAddress); 416 } 417} 418