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