blob: d931350047cebf26b24d8082f5d62637750825ce [file] [log] [blame]
San Mehat873f2142010-01-14 10:25:07 -08001/*
2 * Copyright (C) 2007 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 com.android.server;
18
19import android.app.PendingIntent;
20import android.content.BroadcastReceiver;
21import android.content.Context;
22import android.content.Intent;
23import android.content.IntentFilter;
24import android.content.res.Resources;
25import android.content.pm.PackageManager;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070026import android.net.NetworkStats;
San Mehat873f2142010-01-14 10:25:07 -080027import android.net.Uri;
San Mehated4fc8a2010-01-22 12:28:36 -080028import android.net.InterfaceConfiguration;
San Mehat4d02d002010-01-22 16:07:46 -080029import android.net.INetworkManagementEventObserver;
Robert Greenwalted126402011-01-28 15:34:55 -080030import android.net.LinkAddress;
31import android.net.NetworkUtils;
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -080032import android.net.wifi.WifiConfiguration;
33import android.net.wifi.WifiConfiguration.KeyMgmt;
San Mehat873f2142010-01-14 10:25:07 -080034import android.os.INetworkManagementService;
35import android.os.Handler;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070036import android.os.RemoteException;
37import android.os.SystemClock;
Marco Nelissen62dbb222010-02-18 10:56:30 -080038import android.os.SystemProperties;
San Mehat873f2142010-01-14 10:25:07 -080039import android.text.TextUtils;
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -080040import android.util.Log;
Joe Onorato8a9b2202010-02-26 18:56:32 -080041import android.util.Slog;
San Mehat873f2142010-01-14 10:25:07 -080042import java.util.ArrayList;
Kenny Roota80ce062010-06-01 13:23:53 -070043import java.util.NoSuchElementException;
San Mehated4fc8a2010-01-22 12:28:36 -080044import java.util.StringTokenizer;
San Mehat873f2142010-01-14 10:25:07 -080045import android.provider.Settings;
46import android.content.ContentResolver;
47import android.database.ContentObserver;
48
49import java.io.File;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070050import java.io.FileInputStream;
San Mehat873f2142010-01-14 10:25:07 -080051import java.io.FileReader;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070052import java.io.IOException;
53import java.io.InputStream;
54import java.io.InputStreamReader;
55import java.io.RandomAccessFile;
56import java.io.Reader;
San Mehat873f2142010-01-14 10:25:07 -080057import java.lang.IllegalStateException;
58
59import java.net.InetAddress;
60import java.net.UnknownHostException;
Robert Greenwalte5c3afb2010-09-22 14:32:35 -070061import java.util.concurrent.CountDownLatch;
San Mehat873f2142010-01-14 10:25:07 -080062
Jeff Sharkey9a13f362011-04-26 16:25:36 -070063import libcore.io.IoUtils;
64
San Mehat873f2142010-01-14 10:25:07 -080065/**
66 * @hide
67 */
68class NetworkManagementService extends INetworkManagementService.Stub {
69
70 private static final String TAG = "NetworkManagmentService";
Dianne Hackborncef65ee2010-09-30 18:27:22 -070071 private static final boolean DBG = false;
Kenny Root305bcbf2010-09-03 07:56:38 -070072 private static final String NETD_TAG = "NetdConnector";
73
San Mehat873f2142010-01-14 10:25:07 -080074 class NetdResponseCode {
75 public static final int InterfaceListResult = 110;
76 public static final int TetherInterfaceListResult = 111;
77 public static final int TetherDnsFwdTgtListResult = 112;
San Mehat72759df2010-01-19 13:50:37 -080078 public static final int TtyListResult = 113;
San Mehat873f2142010-01-14 10:25:07 -080079
80 public static final int TetherStatusResult = 210;
81 public static final int IpFwdStatusResult = 211;
San Mehated4fc8a2010-01-22 12:28:36 -080082 public static final int InterfaceGetCfgResult = 213;
Robert Greenwalte3253922010-02-18 09:23:25 -080083 public static final int SoftapStatusResult = 214;
84 public static final int UsbRNDISStatusResult = 215;
San Mehat91cac642010-03-31 14:31:36 -070085 public static final int InterfaceRxCounterResult = 216;
86 public static final int InterfaceTxCounterResult = 217;
87 public static final int InterfaceRxThrottleResult = 218;
88 public static final int InterfaceTxThrottleResult = 219;
Robert Greenwalte3253922010-02-18 09:23:25 -080089
90 public static final int InterfaceChange = 600;
San Mehat873f2142010-01-14 10:25:07 -080091 }
92
93 /**
94 * Binder context for this service
95 */
96 private Context mContext;
97
98 /**
99 * connector object for communicating with netd
100 */
101 private NativeDaemonConnector mConnector;
102
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700103 private Thread mThread;
104 private final CountDownLatch mConnectedSignal = new CountDownLatch(1);
105
San Mehat4d02d002010-01-22 16:07:46 -0800106 private ArrayList<INetworkManagementEventObserver> mObservers;
107
San Mehat873f2142010-01-14 10:25:07 -0800108 /**
109 * Constructs a new NetworkManagementService instance
110 *
111 * @param context Binder context for this service
112 */
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700113 private NetworkManagementService(Context context) {
San Mehat873f2142010-01-14 10:25:07 -0800114 mContext = context;
San Mehat4d02d002010-01-22 16:07:46 -0800115 mObservers = new ArrayList<INetworkManagementEventObserver>();
116
Marco Nelissen62dbb222010-02-18 10:56:30 -0800117 if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
118 return;
119 }
120
San Mehat873f2142010-01-14 10:25:07 -0800121 mConnector = new NativeDaemonConnector(
Kenny Root305bcbf2010-09-03 07:56:38 -0700122 new NetdCallbackReceiver(), "netd", 10, NETD_TAG);
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700123 mThread = new Thread(mConnector, NETD_TAG);
124 }
125
126 public static NetworkManagementService create(Context context) throws InterruptedException {
127 NetworkManagementService service = new NetworkManagementService(context);
128 if (DBG) Slog.d(TAG, "Creating NetworkManagementService");
129 service.mThread.start();
130 if (DBG) Slog.d(TAG, "Awaiting socket connection");
131 service.mConnectedSignal.await();
132 if (DBG) Slog.d(TAG, "Connected");
133 return service;
San Mehat873f2142010-01-14 10:25:07 -0800134 }
135
San Mehat4d02d002010-01-22 16:07:46 -0800136 public void registerObserver(INetworkManagementEventObserver obs) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800137 Slog.d(TAG, "Registering observer");
San Mehat4d02d002010-01-22 16:07:46 -0800138 mObservers.add(obs);
139 }
140
141 public void unregisterObserver(INetworkManagementEventObserver obs) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800142 Slog.d(TAG, "Unregistering observer");
San Mehat4d02d002010-01-22 16:07:46 -0800143 mObservers.remove(mObservers.indexOf(obs));
144 }
145
146 /**
Wink Saville1a7e6712011-01-09 12:16:38 -0800147 * Notify our observers of an interface link status change
San Mehat4d02d002010-01-22 16:07:46 -0800148 */
Wink Saville1a7e6712011-01-09 12:16:38 -0800149 private void notifyInterfaceLinkStatusChanged(String iface, boolean link) {
San Mehat4d02d002010-01-22 16:07:46 -0800150 for (INetworkManagementEventObserver obs : mObservers) {
151 try {
Wink Saville1a7e6712011-01-09 12:16:38 -0800152 obs.interfaceLinkStatusChanged(iface, link);
San Mehat4d02d002010-01-22 16:07:46 -0800153 } catch (Exception ex) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800154 Slog.w(TAG, "Observer notifier failed", ex);
San Mehat4d02d002010-01-22 16:07:46 -0800155 }
156 }
157 }
158
159 /**
160 * Notify our observers of an interface addition.
161 */
162 private void notifyInterfaceAdded(String iface) {
163 for (INetworkManagementEventObserver obs : mObservers) {
164 try {
165 obs.interfaceAdded(iface);
166 } catch (Exception ex) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800167 Slog.w(TAG, "Observer notifier failed", ex);
San Mehat4d02d002010-01-22 16:07:46 -0800168 }
169 }
170 }
171
172 /**
173 * Notify our observers of an interface removal.
174 */
175 private void notifyInterfaceRemoved(String iface) {
176 for (INetworkManagementEventObserver obs : mObservers) {
177 try {
178 obs.interfaceRemoved(iface);
179 } catch (Exception ex) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800180 Slog.w(TAG, "Observer notifier failed", ex);
San Mehat4d02d002010-01-22 16:07:46 -0800181 }
182 }
183 }
184
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700185 /**
186 * Let us know the daemon is connected
187 */
188 protected void onConnected() {
189 if (DBG) Slog.d(TAG, "onConnected");
190 mConnectedSignal.countDown();
191 }
192
San Mehat4d02d002010-01-22 16:07:46 -0800193
San Mehat873f2142010-01-14 10:25:07 -0800194 //
195 // Netd Callback handling
196 //
197
198 class NetdCallbackReceiver implements INativeDaemonConnectorCallbacks {
199 public void onDaemonConnected() {
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700200 NetworkManagementService.this.onConnected();
San Mehat873f2142010-01-14 10:25:07 -0800201 new Thread() {
202 public void run() {
San Mehat873f2142010-01-14 10:25:07 -0800203 }
204 }.start();
205 }
206 public boolean onEvent(int code, String raw, String[] cooked) {
Robert Greenwalte3253922010-02-18 09:23:25 -0800207 if (code == NetdResponseCode.InterfaceChange) {
208 /*
209 * a network interface change occured
210 * Format: "NNN Iface added <name>"
211 * "NNN Iface removed <name>"
212 * "NNN Iface changed <name> <up/down>"
213 */
214 if (cooked.length < 4 || !cooked[1].equals("Iface")) {
215 throw new IllegalStateException(
216 String.format("Invalid event from daemon (%s)", raw));
217 }
218 if (cooked[2].equals("added")) {
219 notifyInterfaceAdded(cooked[3]);
220 return true;
221 } else if (cooked[2].equals("removed")) {
222 notifyInterfaceRemoved(cooked[3]);
223 return true;
224 } else if (cooked[2].equals("changed") && cooked.length == 5) {
Wink Saville1a7e6712011-01-09 12:16:38 -0800225 notifyInterfaceLinkStatusChanged(cooked[3], cooked[4].equals("up"));
Robert Greenwalte3253922010-02-18 09:23:25 -0800226 return true;
227 }
228 throw new IllegalStateException(
229 String.format("Invalid event from daemon (%s)", raw));
230 }
231 return false;
San Mehat873f2142010-01-14 10:25:07 -0800232 }
233 }
234
San Mehated4fc8a2010-01-22 12:28:36 -0800235
San Mehat873f2142010-01-14 10:25:07 -0800236 //
237 // INetworkManagementService members
238 //
239
240 public String[] listInterfaces() throws IllegalStateException {
241 mContext.enforceCallingOrSelfPermission(
242 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
243
Kenny Roota80ce062010-06-01 13:23:53 -0700244 try {
245 return mConnector.doListCommand("interface list", NetdResponseCode.InterfaceListResult);
246 } catch (NativeDaemonConnectorException e) {
247 throw new IllegalStateException(
248 "Cannot communicate with native daemon to list interfaces");
249 }
San Mehated4fc8a2010-01-22 12:28:36 -0800250 }
251
252 public InterfaceConfiguration getInterfaceConfig(String iface) throws IllegalStateException {
Kenny Roota80ce062010-06-01 13:23:53 -0700253 String rsp;
254 try {
255 rsp = mConnector.doCommand("interface getcfg " + iface).get(0);
256 } catch (NativeDaemonConnectorException e) {
257 throw new IllegalStateException(
258 "Cannot communicate with native daemon to get interface config");
259 }
Joe Onorato8a9b2202010-02-26 18:56:32 -0800260 Slog.d(TAG, String.format("rsp <%s>", rsp));
San Mehated4fc8a2010-01-22 12:28:36 -0800261
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800262 // Rsp: 213 xx:xx:xx:xx:xx:xx yyy.yyy.yyy.yyy zzz [flag1 flag2 flag3]
San Mehated4fc8a2010-01-22 12:28:36 -0800263 StringTokenizer st = new StringTokenizer(rsp);
264
Kenny Roota80ce062010-06-01 13:23:53 -0700265 InterfaceConfiguration cfg;
San Mehated4fc8a2010-01-22 12:28:36 -0800266 try {
Kenny Roota80ce062010-06-01 13:23:53 -0700267 try {
268 int code = Integer.parseInt(st.nextToken(" "));
269 if (code != NetdResponseCode.InterfaceGetCfgResult) {
270 throw new IllegalStateException(
271 String.format("Expected code %d, but got %d",
272 NetdResponseCode.InterfaceGetCfgResult, code));
273 }
274 } catch (NumberFormatException nfe) {
San Mehated4fc8a2010-01-22 12:28:36 -0800275 throw new IllegalStateException(
Kenny Roota80ce062010-06-01 13:23:53 -0700276 String.format("Invalid response from daemon (%s)", rsp));
San Mehated4fc8a2010-01-22 12:28:36 -0800277 }
Kenny Roota80ce062010-06-01 13:23:53 -0700278
279 cfg = new InterfaceConfiguration();
280 cfg.hwAddr = st.nextToken(" ");
Robert Greenwalted126402011-01-28 15:34:55 -0800281 InetAddress addr = null;
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800282 int prefixLength = 0;
Kenny Roota80ce062010-06-01 13:23:53 -0700283 try {
Robert Greenwalte5903732011-02-22 16:00:42 -0800284 addr = NetworkUtils.numericToInetAddress(st.nextToken(" "));
285 } catch (IllegalArgumentException iae) {
286 Slog.e(TAG, "Failed to parse ipaddr", iae);
Kenny Roota80ce062010-06-01 13:23:53 -0700287 }
288
289 try {
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800290 prefixLength = Integer.parseInt(st.nextToken(" "));
291 } catch (NumberFormatException nfe) {
292 Slog.e(TAG, "Failed to parse prefixLength", nfe);
Kenny Roota80ce062010-06-01 13:23:53 -0700293 }
Robert Greenwalt04808c22010-12-13 17:01:41 -0800294
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800295 cfg.addr = new LinkAddress(addr, prefixLength);
Kenny Roota80ce062010-06-01 13:23:53 -0700296 cfg.interfaceFlags = st.nextToken("]").trim() +"]";
297 } catch (NoSuchElementException nsee) {
San Mehated4fc8a2010-01-22 12:28:36 -0800298 throw new IllegalStateException(
299 String.format("Invalid response from daemon (%s)", rsp));
300 }
Joe Onorato8a9b2202010-02-26 18:56:32 -0800301 Slog.d(TAG, String.format("flags <%s>", cfg.interfaceFlags));
San Mehated4fc8a2010-01-22 12:28:36 -0800302 return cfg;
303 }
304
305 public void setInterfaceConfig(
306 String iface, InterfaceConfiguration cfg) throws IllegalStateException {
Robert Greenwalted126402011-01-28 15:34:55 -0800307 LinkAddress linkAddr = cfg.addr;
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800308 if (linkAddr == null || linkAddr.getAddress() == null) {
309 throw new IllegalStateException("Null LinkAddress given");
Robert Greenwalted126402011-01-28 15:34:55 -0800310 }
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800311 String cmd = String.format("interface setcfg %s %s %d %s", iface,
312 linkAddr.getAddress().getHostAddress(),
313 linkAddr.getNetworkPrefixLength(),
314 cfg.interfaceFlags);
Kenny Roota80ce062010-06-01 13:23:53 -0700315 try {
316 mConnector.doCommand(cmd);
317 } catch (NativeDaemonConnectorException e) {
318 throw new IllegalStateException(
Robert Greenwalt81d5ad52010-12-16 11:27:38 -0800319 "Unable to communicate with native daemon to interface setcfg - " + e);
Kenny Roota80ce062010-06-01 13:23:53 -0700320 }
San Mehat873f2142010-01-14 10:25:07 -0800321 }
322
323 public void shutdown() {
324 if (mContext.checkCallingOrSelfPermission(
325 android.Manifest.permission.SHUTDOWN)
326 != PackageManager.PERMISSION_GRANTED) {
327 throw new SecurityException("Requires SHUTDOWN permission");
328 }
329
Joe Onorato8a9b2202010-02-26 18:56:32 -0800330 Slog.d(TAG, "Shutting down");
San Mehat873f2142010-01-14 10:25:07 -0800331 }
332
333 public boolean getIpForwardingEnabled() throws IllegalStateException{
334 mContext.enforceCallingOrSelfPermission(
335 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
336
Kenny Roota80ce062010-06-01 13:23:53 -0700337 ArrayList<String> rsp;
338 try {
339 rsp = mConnector.doCommand("ipfwd status");
340 } catch (NativeDaemonConnectorException e) {
341 throw new IllegalStateException(
342 "Unable to communicate with native daemon to ipfwd status");
343 }
San Mehat873f2142010-01-14 10:25:07 -0800344
345 for (String line : rsp) {
Kenny Roota80ce062010-06-01 13:23:53 -0700346 String[] tok = line.split(" ");
347 if (tok.length < 3) {
348 Slog.e(TAG, "Malformed response from native daemon: " + line);
349 return false;
350 }
351
San Mehat873f2142010-01-14 10:25:07 -0800352 int code = Integer.parseInt(tok[0]);
353 if (code == NetdResponseCode.IpFwdStatusResult) {
354 // 211 Forwarding <enabled/disabled>
Kenny Roota80ce062010-06-01 13:23:53 -0700355 return "enabled".equals(tok[2]);
San Mehat873f2142010-01-14 10:25:07 -0800356 } else {
357 throw new IllegalStateException(String.format("Unexpected response code %d", code));
358 }
359 }
360 throw new IllegalStateException("Got an empty response");
361 }
362
363 public void setIpForwardingEnabled(boolean enable) throws IllegalStateException {
364 mContext.enforceCallingOrSelfPermission(
365 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
366 mConnector.doCommand(String.format("ipfwd %sable", (enable ? "en" : "dis")));
367 }
368
Robert Greenwaltbfb7bfa2010-03-24 16:03:21 -0700369 public void startTethering(String[] dhcpRange)
San Mehat873f2142010-01-14 10:25:07 -0800370 throws IllegalStateException {
371 mContext.enforceCallingOrSelfPermission(
372 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Robert Greenwaltbfb7bfa2010-03-24 16:03:21 -0700373 // cmd is "tether start first_start first_stop second_start second_stop ..."
374 // an odd number of addrs will fail
375 String cmd = "tether start";
376 for (String d : dhcpRange) {
377 cmd += " " + d;
378 }
Kenny Roota80ce062010-06-01 13:23:53 -0700379
380 try {
381 mConnector.doCommand(cmd);
382 } catch (NativeDaemonConnectorException e) {
383 throw new IllegalStateException("Unable to communicate to native daemon");
384 }
San Mehat873f2142010-01-14 10:25:07 -0800385 }
386
387 public void stopTethering() throws IllegalStateException {
388 mContext.enforceCallingOrSelfPermission(
389 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700390 try {
391 mConnector.doCommand("tether stop");
392 } catch (NativeDaemonConnectorException e) {
393 throw new IllegalStateException("Unable to communicate to native daemon to stop tether");
394 }
San Mehat873f2142010-01-14 10:25:07 -0800395 }
396
397 public boolean isTetheringStarted() throws IllegalStateException {
398 mContext.enforceCallingOrSelfPermission(
399 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
400
Kenny Roota80ce062010-06-01 13:23:53 -0700401 ArrayList<String> rsp;
402 try {
403 rsp = mConnector.doCommand("tether status");
404 } catch (NativeDaemonConnectorException e) {
405 throw new IllegalStateException(
406 "Unable to communicate to native daemon to get tether status");
407 }
San Mehat873f2142010-01-14 10:25:07 -0800408
409 for (String line : rsp) {
Kenny Roota80ce062010-06-01 13:23:53 -0700410 String[] tok = line.split(" ");
411 if (tok.length < 3) {
412 throw new IllegalStateException("Malformed response for tether status: " + line);
413 }
San Mehat873f2142010-01-14 10:25:07 -0800414 int code = Integer.parseInt(tok[0]);
415 if (code == NetdResponseCode.TetherStatusResult) {
416 // XXX: Tethering services <started/stopped> <TBD>...
Kenny Roota80ce062010-06-01 13:23:53 -0700417 return "started".equals(tok[2]);
San Mehat873f2142010-01-14 10:25:07 -0800418 } else {
419 throw new IllegalStateException(String.format("Unexpected response code %d", code));
420 }
421 }
422 throw new IllegalStateException("Got an empty response");
423 }
424
425 public void tetherInterface(String iface) throws IllegalStateException {
426 mContext.enforceCallingOrSelfPermission(
427 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700428 try {
429 mConnector.doCommand("tether interface add " + iface);
430 } catch (NativeDaemonConnectorException e) {
431 throw new IllegalStateException(
432 "Unable to communicate to native daemon for adding tether interface");
433 }
San Mehat873f2142010-01-14 10:25:07 -0800434 }
435
436 public void untetherInterface(String iface) {
437 mContext.enforceCallingOrSelfPermission(
438 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700439 try {
440 mConnector.doCommand("tether interface remove " + iface);
441 } catch (NativeDaemonConnectorException e) {
442 throw new IllegalStateException(
443 "Unable to communicate to native daemon for removing tether interface");
444 }
San Mehat873f2142010-01-14 10:25:07 -0800445 }
446
447 public String[] listTetheredInterfaces() throws IllegalStateException {
448 mContext.enforceCallingOrSelfPermission(
449 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700450 try {
451 return mConnector.doListCommand(
452 "tether interface list", NetdResponseCode.TetherInterfaceListResult);
453 } catch (NativeDaemonConnectorException e) {
454 throw new IllegalStateException(
455 "Unable to communicate to native daemon for listing tether interfaces");
456 }
San Mehat873f2142010-01-14 10:25:07 -0800457 }
458
459 public void setDnsForwarders(String[] dns) throws IllegalStateException {
460 mContext.enforceCallingOrSelfPermission(
461 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
462 try {
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800463 String cmd = "tether dns set";
San Mehat873f2142010-01-14 10:25:07 -0800464 for (String s : dns) {
Robert Greenwalte5903732011-02-22 16:00:42 -0800465 cmd += " " + NetworkUtils.numericToInetAddress(s).getHostAddress();
San Mehat873f2142010-01-14 10:25:07 -0800466 }
Kenny Roota80ce062010-06-01 13:23:53 -0700467 try {
468 mConnector.doCommand(cmd);
469 } catch (NativeDaemonConnectorException e) {
470 throw new IllegalStateException(
471 "Unable to communicate to native daemon for setting tether dns");
472 }
Robert Greenwalte5903732011-02-22 16:00:42 -0800473 } catch (IllegalArgumentException e) {
San Mehat873f2142010-01-14 10:25:07 -0800474 throw new IllegalStateException("Error resolving dns name", e);
475 }
476 }
477
478 public String[] getDnsForwarders() throws IllegalStateException {
479 mContext.enforceCallingOrSelfPermission(
480 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700481 try {
482 return mConnector.doListCommand(
483 "tether dns list", NetdResponseCode.TetherDnsFwdTgtListResult);
484 } catch (NativeDaemonConnectorException e) {
485 throw new IllegalStateException(
486 "Unable to communicate to native daemon for listing tether dns");
487 }
San Mehat873f2142010-01-14 10:25:07 -0800488 }
489
490 public void enableNat(String internalInterface, String externalInterface)
491 throws IllegalStateException {
492 mContext.enforceCallingOrSelfPermission(
493 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700494 try {
495 mConnector.doCommand(
496 String.format("nat enable %s %s", internalInterface, externalInterface));
497 } catch (NativeDaemonConnectorException e) {
498 throw new IllegalStateException(
499 "Unable to communicate to native daemon for enabling NAT interface");
500 }
San Mehat873f2142010-01-14 10:25:07 -0800501 }
502
503 public void disableNat(String internalInterface, String externalInterface)
504 throws IllegalStateException {
505 mContext.enforceCallingOrSelfPermission(
506 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700507 try {
508 mConnector.doCommand(
509 String.format("nat disable %s %s", internalInterface, externalInterface));
510 } catch (NativeDaemonConnectorException e) {
511 throw new IllegalStateException(
512 "Unable to communicate to native daemon for disabling NAT interface");
513 }
San Mehat873f2142010-01-14 10:25:07 -0800514 }
San Mehat72759df2010-01-19 13:50:37 -0800515
516 public String[] listTtys() throws IllegalStateException {
517 mContext.enforceCallingOrSelfPermission(
518 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700519 try {
520 return mConnector.doListCommand("list_ttys", NetdResponseCode.TtyListResult);
521 } catch (NativeDaemonConnectorException e) {
522 throw new IllegalStateException(
523 "Unable to communicate to native daemon for listing TTYs");
524 }
San Mehat72759df2010-01-19 13:50:37 -0800525 }
526
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800527 public void attachPppd(String tty, String localAddr, String remoteAddr, String dns1Addr,
528 String dns2Addr) throws IllegalStateException {
San Mehat72759df2010-01-19 13:50:37 -0800529 try {
530 mContext.enforceCallingOrSelfPermission(
531 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800532 mConnector.doCommand(String.format("pppd attach %s %s %s %s %s", tty,
Robert Greenwalte5903732011-02-22 16:00:42 -0800533 NetworkUtils.numericToInetAddress(localAddr).getHostAddress(),
534 NetworkUtils.numericToInetAddress(remoteAddr).getHostAddress(),
535 NetworkUtils.numericToInetAddress(dns1Addr).getHostAddress(),
536 NetworkUtils.numericToInetAddress(dns2Addr).getHostAddress()));
537 } catch (IllegalArgumentException e) {
San Mehat72759df2010-01-19 13:50:37 -0800538 throw new IllegalStateException("Error resolving addr", e);
Kenny Roota80ce062010-06-01 13:23:53 -0700539 } catch (NativeDaemonConnectorException e) {
540 throw new IllegalStateException("Error communicating to native daemon to attach pppd", e);
San Mehat72759df2010-01-19 13:50:37 -0800541 }
542 }
543
544 public void detachPppd(String tty) throws IllegalStateException {
545 mContext.enforceCallingOrSelfPermission(
546 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700547 try {
548 mConnector.doCommand(String.format("pppd detach %s", tty));
549 } catch (NativeDaemonConnectorException e) {
550 throw new IllegalStateException("Error communicating to native daemon to detach pppd", e);
551 }
San Mehat72759df2010-01-19 13:50:37 -0800552 }
Robert Greenwaltce1200d2010-02-18 11:25:54 -0800553
554 public void startUsbRNDIS() throws IllegalStateException {
555 mContext.enforceCallingOrSelfPermission(
556 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700557 try {
558 mConnector.doCommand("usb startrndis");
559 } catch (NativeDaemonConnectorException e) {
560 throw new IllegalStateException(
561 "Error communicating to native daemon for starting RNDIS", e);
562 }
Robert Greenwaltce1200d2010-02-18 11:25:54 -0800563 }
564
565 public void stopUsbRNDIS() throws IllegalStateException {
566 mContext.enforceCallingOrSelfPermission(
567 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700568 try {
569 mConnector.doCommand("usb stoprndis");
570 } catch (NativeDaemonConnectorException e) {
571 throw new IllegalStateException("Error communicating to native daemon", e);
572 }
Robert Greenwaltce1200d2010-02-18 11:25:54 -0800573 }
574
575 public boolean isUsbRNDISStarted() throws IllegalStateException {
576 mContext.enforceCallingOrSelfPermission(
577 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700578 ArrayList<String> rsp;
579 try {
580 rsp = mConnector.doCommand("usb rndisstatus");
581 } catch (NativeDaemonConnectorException e) {
582 throw new IllegalStateException(
583 "Error communicating to native daemon to check RNDIS status", e);
584 }
Robert Greenwaltce1200d2010-02-18 11:25:54 -0800585
586 for (String line : rsp) {
587 String []tok = line.split(" ");
588 int code = Integer.parseInt(tok[0]);
589 if (code == NetdResponseCode.UsbRNDISStatusResult) {
Mike Lockwood51cb9d52010-03-03 15:12:00 -0500590 if (tok[3].equals("started"))
Robert Greenwaltce1200d2010-02-18 11:25:54 -0800591 return true;
592 return false;
593 } else {
594 throw new IllegalStateException(String.format("Unexpected response code %d", code));
595 }
596 }
597 throw new IllegalStateException("Got an empty response");
598 }
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800599
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700600 public void startAccessPoint(WifiConfiguration wifiConfig, String wlanIface, String softapIface)
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800601 throws IllegalStateException {
602 mContext.enforceCallingOrSelfPermission(
603 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
604 mContext.enforceCallingOrSelfPermission(
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700605 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700606 try {
607 mConnector.doCommand(String.format("softap stop " + wlanIface));
608 mConnector.doCommand(String.format("softap fwreload " + wlanIface + " AP"));
609 mConnector.doCommand(String.format("softap start " + wlanIface));
610 if (wifiConfig == null) {
611 mConnector.doCommand(String.format("softap set " + wlanIface + " " + softapIface));
612 } else {
613 /**
614 * softap set arg1 arg2 arg3 [arg4 arg5 arg6 arg7 arg8]
615 * argv1 - wlan interface
616 * argv2 - softap interface
617 * argv3 - SSID
618 * argv4 - Security
619 * argv5 - Key
620 * argv6 - Channel
621 * argv7 - Preamble
622 * argv8 - Max SCB
623 */
Irfan Sheriffec8d23a2011-02-16 17:00:33 -0800624 String str = String.format("softap set " + wlanIface + " " + softapIface +
625 " %s %s %s", convertQuotedString(wifiConfig.SSID),
626 getSecurityType(wifiConfig),
627 convertQuotedString(wifiConfig.preSharedKey));
Kenny Roota80ce062010-06-01 13:23:53 -0700628 mConnector.doCommand(str);
629 }
630 mConnector.doCommand(String.format("softap startap"));
631 } catch (NativeDaemonConnectorException e) {
632 throw new IllegalStateException("Error communicating to native daemon to start softap", e);
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -0800633 }
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800634 }
635
Irfan Sheriffa6e559e2010-05-24 14:55:42 -0700636 private String convertQuotedString(String s) {
Irfan Sheriff7baec0f2010-05-26 17:16:47 -0700637 if (s == null) {
638 return s;
639 }
640 /* Replace \ with \\, then " with \" and add quotes at end */
641 return '"' + s.replaceAll("\\\\","\\\\\\\\").replaceAll("\"","\\\\\"") + '"';
Irfan Sheriffa6e559e2010-05-24 14:55:42 -0700642 }
643
Irfan Sheriffec8d23a2011-02-16 17:00:33 -0800644 private String getSecurityType(WifiConfiguration wifiConfig) {
645 switch (wifiConfig.getAuthType()) {
646 case KeyMgmt.WPA_PSK:
647 return "wpa-psk";
648 case KeyMgmt.WPA2_PSK:
649 return "wpa2-psk";
650 default:
651 return "open";
652 }
653 }
654
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800655 public void stopAccessPoint() throws IllegalStateException {
656 mContext.enforceCallingOrSelfPermission(
657 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
658 mContext.enforceCallingOrSelfPermission(
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700659 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700660 try {
661 mConnector.doCommand("softap stopap");
662 } catch (NativeDaemonConnectorException e) {
663 throw new IllegalStateException("Error communicating to native daemon to stop soft AP",
664 e);
665 }
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800666 }
667
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700668 public void setAccessPoint(WifiConfiguration wifiConfig, String wlanIface, String softapIface)
669 throws IllegalStateException {
670 mContext.enforceCallingOrSelfPermission(
671 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
672 mContext.enforceCallingOrSelfPermission(
673 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700674 try {
675 if (wifiConfig == null) {
676 mConnector.doCommand(String.format("softap set " + wlanIface + " " + softapIface));
677 } else {
678 String str = String.format("softap set " + wlanIface + " " + softapIface
679 + " %s %s %s", convertQuotedString(wifiConfig.SSID),
Irfan Sheriffec8d23a2011-02-16 17:00:33 -0800680 getSecurityType(wifiConfig),
Kenny Roota80ce062010-06-01 13:23:53 -0700681 convertQuotedString(wifiConfig.preSharedKey));
682 mConnector.doCommand(str);
683 }
684 } catch (NativeDaemonConnectorException e) {
685 throw new IllegalStateException("Error communicating to native daemon to set soft AP",
686 e);
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700687 }
688 }
San Mehat91cac642010-03-31 14:31:36 -0700689
690 private long getInterfaceCounter(String iface, boolean rx) {
691 mContext.enforceCallingOrSelfPermission(
692 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
693 try {
Kenny Roota80ce062010-06-01 13:23:53 -0700694 String rsp;
695 try {
696 rsp = mConnector.doCommand(
697 String.format("interface read%scounter %s", (rx ? "rx" : "tx"), iface)).get(0);
698 } catch (NativeDaemonConnectorException e1) {
699 Slog.e(TAG, "Error communicating with native daemon", e1);
700 return -1;
701 }
702
703 String[] tok = rsp.split(" ");
704 if (tok.length < 2) {
705 Slog.e(TAG, String.format("Malformed response for reading %s interface",
706 (rx ? "rx" : "tx")));
707 return -1;
708 }
709
San Mehat91cac642010-03-31 14:31:36 -0700710 int code;
711 try {
712 code = Integer.parseInt(tok[0]);
713 } catch (NumberFormatException nfe) {
714 Slog.e(TAG, String.format("Error parsing code %s", tok[0]));
715 return -1;
716 }
717 if ((rx && code != NetdResponseCode.InterfaceRxCounterResult) || (
718 !rx && code != NetdResponseCode.InterfaceTxCounterResult)) {
719 Slog.e(TAG, String.format("Unexpected response code %d", code));
720 return -1;
721 }
722 return Long.parseLong(tok[1]);
723 } catch (Exception e) {
724 Slog.e(TAG, String.format(
725 "Failed to read interface %s counters", (rx ? "rx" : "tx")), e);
726 }
727 return -1;
728 }
729
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700730 /** {@inheritDoc} */
731 public NetworkStats getNetworkStatsSummary() {
732 mContext.enforceCallingOrSelfPermission(
733 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
734
735 final String[] ifaces = listInterfaces();
736 final NetworkStats.Builder stats = new NetworkStats.Builder(
737 SystemClock.elapsedRealtime(), ifaces.length);
738
739 for (String iface : ifaces) {
740 final long rx = getInterfaceCounter(iface, true);
741 final long tx = getInterfaceCounter(iface, false);
742 stats.addEntry(iface, NetworkStats.UID_ALL, rx, tx);
743 }
744
745 return stats.build();
San Mehat91cac642010-03-31 14:31:36 -0700746 }
747
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700748 /** {@inheritDoc} */
749 public NetworkStats getNetworkStatsDetail() {
750 mContext.enforceCallingOrSelfPermission(
751 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
752
753 final File procPath = new File("/proc/uid_stat");
754 final String[] knownUids = procPath.list();
755 final NetworkStats.Builder stats = new NetworkStats.Builder(
756 SystemClock.elapsedRealtime(), knownUids.length);
757
758 // TODO: kernel module will provide interface-level stats in future
759 // TODO: migrate these stats to come across netd in bulk, instead of all
760 // these individual file reads.
761 for (String uid : knownUids) {
762 final File uidPath = new File(procPath, uid);
763 final int rx = readSingleIntFromFile(new File(uidPath, "tcp_rcv"));
764 final int tx = readSingleIntFromFile(new File(uidPath, "tcp_snd"));
765
766 final int uidInt = Integer.parseInt(uid);
767 stats.addEntry(NetworkStats.IFACE_ALL, uidInt, rx, tx);
768 }
769
770 return stats.build();
San Mehat91cac642010-03-31 14:31:36 -0700771 }
772
San Mehatf0db6e12010-04-07 15:22:10 -0700773 public void setInterfaceThrottle(String iface, int rxKbps, int txKbps) {
San Mehat91cac642010-03-31 14:31:36 -0700774 mContext.enforceCallingOrSelfPermission(
775 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700776 try {
777 mConnector.doCommand(String.format(
778 "interface setthrottle %s %d %d", iface, rxKbps, txKbps));
779 } catch (NativeDaemonConnectorException e) {
780 Slog.e(TAG, "Error communicating with native daemon to set throttle", e);
781 }
San Mehat91cac642010-03-31 14:31:36 -0700782 }
783
784 private int getInterfaceThrottle(String iface, boolean rx) {
785 mContext.enforceCallingOrSelfPermission(
786 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
787 try {
Kenny Roota80ce062010-06-01 13:23:53 -0700788 String rsp;
789 try {
790 rsp = mConnector.doCommand(
791 String.format("interface getthrottle %s %s", iface,
792 (rx ? "rx" : "tx"))).get(0);
793 } catch (NativeDaemonConnectorException e) {
794 Slog.e(TAG, "Error communicating with native daemon to getthrottle", e);
795 return -1;
796 }
797
798 String[] tok = rsp.split(" ");
799 if (tok.length < 2) {
800 Slog.e(TAG, "Malformed response to getthrottle command");
801 return -1;
802 }
803
San Mehat91cac642010-03-31 14:31:36 -0700804 int code;
805 try {
806 code = Integer.parseInt(tok[0]);
807 } catch (NumberFormatException nfe) {
808 Slog.e(TAG, String.format("Error parsing code %s", tok[0]));
809 return -1;
810 }
811 if ((rx && code != NetdResponseCode.InterfaceRxThrottleResult) || (
812 !rx && code != NetdResponseCode.InterfaceTxThrottleResult)) {
813 Slog.e(TAG, String.format("Unexpected response code %d", code));
814 return -1;
815 }
816 return Integer.parseInt(tok[1]);
817 } catch (Exception e) {
818 Slog.e(TAG, String.format(
819 "Failed to read interface %s throttle value", (rx ? "rx" : "tx")), e);
820 }
821 return -1;
822 }
823
824 public int getInterfaceRxThrottle(String iface) {
825 return getInterfaceThrottle(iface, true);
826 }
827
828 public int getInterfaceTxThrottle(String iface) {
829 return getInterfaceThrottle(iface, false);
830 }
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700831
832 /**
833 * Utility method to read a single plain-text {@link Integer} from the given
834 * {@link File}, usually from a {@code /proc/} filesystem.
835 */
836 private static int readSingleIntFromFile(File file) {
837 RandomAccessFile f = null;
838 try {
839 f = new RandomAccessFile(file, "r");
840 byte[] buffer = new byte[(int) f.length()];
841 f.readFully(buffer);
842 return Integer.parseInt(new String(buffer).trim());
843 } catch (NumberFormatException e) {
844 return -1;
845 } catch (IOException e) {
846 return -1;
847 } finally {
848 IoUtils.closeQuietly(f);
849 }
850 }
San Mehat873f2142010-01-14 10:25:07 -0800851}