• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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