blob: cd6ec33c6492cf50347997be9220d5248bcc4489 [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
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -070019import static android.net.NetworkStats.IFACE_ALL;
20import static android.net.NetworkStats.TAG_NONE;
21import static android.net.NetworkStats.UID_ALL;
Jeff Sharkey0a9ee122011-06-22 16:32:41 -070022import static android.Manifest.permission.MANAGE_NETWORK_POLICY;
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -070023
San Mehat873f2142010-01-14 10:25:07 -080024import android.content.Context;
San Mehat873f2142010-01-14 10:25:07 -080025import android.content.pm.PackageManager;
San Mehat4d02d002010-01-22 16:07:46 -080026import android.net.INetworkManagementEventObserver;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070027import android.net.InterfaceConfiguration;
Robert Greenwalted126402011-01-28 15:34:55 -080028import android.net.LinkAddress;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070029import android.net.NetworkStats;
Robert Greenwalted126402011-01-28 15:34:55 -080030import android.net.NetworkUtils;
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -070031import android.net.RouteInfo;
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -080032import android.net.wifi.WifiConfiguration;
33import android.net.wifi.WifiConfiguration.KeyMgmt;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070034import android.os.Binder;
San Mehat873f2142010-01-14 10:25:07 -080035import android.os.INetworkManagementService;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070036import android.os.SystemClock;
Marco Nelissen62dbb222010-02-18 10:56:30 -080037import android.os.SystemProperties;
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -080038import android.util.Log;
Joe Onorato8a9b2202010-02-26 18:56:32 -080039import android.util.Slog;
San Mehat873f2142010-01-14 10:25:07 -080040
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -070041import java.io.BufferedReader;
42import java.io.DataInputStream;
San Mehat873f2142010-01-14 10:25:07 -080043import java.io.File;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070044import java.io.FileInputStream;
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -070045import java.io.FileReader;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070046import java.io.IOException;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070047import java.io.InputStreamReader;
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -070048import java.net.Inet4Address;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070049import java.net.InetAddress;
50import java.util.ArrayList;
51import java.util.NoSuchElementException;
52import java.util.StringTokenizer;
Robert Greenwalte5c3afb2010-09-22 14:32:35 -070053import java.util.concurrent.CountDownLatch;
San Mehat873f2142010-01-14 10:25:07 -080054
Jeff Sharkey9a13f362011-04-26 16:25:36 -070055import libcore.io.IoUtils;
56
San Mehat873f2142010-01-14 10:25:07 -080057/**
58 * @hide
59 */
60class NetworkManagementService extends INetworkManagementService.Stub {
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070061 private static final String TAG = "NetworkManagementService";
Dianne Hackborncef65ee2010-09-30 18:27:22 -070062 private static final boolean DBG = false;
Kenny Root305bcbf2010-09-03 07:56:38 -070063 private static final String NETD_TAG = "NetdConnector";
64
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -070065 private static final int ADD = 1;
66 private static final int REMOVE = 2;
67
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -070068 @Deprecated
69 private static final File STATS_UIDSTAT = new File("/proc/uid_stat");
70 private static final File STATS_NETFILTER = new File("/proc/net/xt_qtaguid/stats");
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070071
San Mehat873f2142010-01-14 10:25:07 -080072 class NetdResponseCode {
73 public static final int InterfaceListResult = 110;
74 public static final int TetherInterfaceListResult = 111;
75 public static final int TetherDnsFwdTgtListResult = 112;
San Mehat72759df2010-01-19 13:50:37 -080076 public static final int TtyListResult = 113;
San Mehat873f2142010-01-14 10:25:07 -080077
78 public static final int TetherStatusResult = 210;
79 public static final int IpFwdStatusResult = 211;
San Mehated4fc8a2010-01-22 12:28:36 -080080 public static final int InterfaceGetCfgResult = 213;
Robert Greenwalte3253922010-02-18 09:23:25 -080081 public static final int SoftapStatusResult = 214;
San Mehat91cac642010-03-31 14:31:36 -070082 public static final int InterfaceRxCounterResult = 216;
83 public static final int InterfaceTxCounterResult = 217;
84 public static final int InterfaceRxThrottleResult = 218;
85 public static final int InterfaceTxThrottleResult = 219;
Robert Greenwalte3253922010-02-18 09:23:25 -080086
87 public static final int InterfaceChange = 600;
San Mehat873f2142010-01-14 10:25:07 -080088 }
89
90 /**
91 * Binder context for this service
92 */
93 private Context mContext;
94
95 /**
96 * connector object for communicating with netd
97 */
98 private NativeDaemonConnector mConnector;
99
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700100 private Thread mThread;
101 private final CountDownLatch mConnectedSignal = new CountDownLatch(1);
102
San Mehat4d02d002010-01-22 16:07:46 -0800103 private ArrayList<INetworkManagementEventObserver> mObservers;
104
San Mehat873f2142010-01-14 10:25:07 -0800105 /**
106 * Constructs a new NetworkManagementService instance
107 *
108 * @param context Binder context for this service
109 */
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700110 private NetworkManagementService(Context context) {
San Mehat873f2142010-01-14 10:25:07 -0800111 mContext = context;
San Mehat4d02d002010-01-22 16:07:46 -0800112 mObservers = new ArrayList<INetworkManagementEventObserver>();
113
Marco Nelissen62dbb222010-02-18 10:56:30 -0800114 if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
115 return;
116 }
117
San Mehat873f2142010-01-14 10:25:07 -0800118 mConnector = new NativeDaemonConnector(
Kenny Root305bcbf2010-09-03 07:56:38 -0700119 new NetdCallbackReceiver(), "netd", 10, NETD_TAG);
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700120 mThread = new Thread(mConnector, NETD_TAG);
121 }
122
123 public static NetworkManagementService create(Context context) throws InterruptedException {
124 NetworkManagementService service = new NetworkManagementService(context);
125 if (DBG) Slog.d(TAG, "Creating NetworkManagementService");
126 service.mThread.start();
127 if (DBG) Slog.d(TAG, "Awaiting socket connection");
128 service.mConnectedSignal.await();
129 if (DBG) Slog.d(TAG, "Connected");
130 return service;
San Mehat873f2142010-01-14 10:25:07 -0800131 }
132
San Mehat4d02d002010-01-22 16:07:46 -0800133 public void registerObserver(INetworkManagementEventObserver obs) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800134 Slog.d(TAG, "Registering observer");
San Mehat4d02d002010-01-22 16:07:46 -0800135 mObservers.add(obs);
136 }
137
138 public void unregisterObserver(INetworkManagementEventObserver obs) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800139 Slog.d(TAG, "Unregistering observer");
San Mehat4d02d002010-01-22 16:07:46 -0800140 mObservers.remove(mObservers.indexOf(obs));
141 }
142
143 /**
Mike J. Chen6143f5f2011-06-23 15:17:51 -0700144 * Notify our observers of an interface status change
San Mehat4d02d002010-01-22 16:07:46 -0800145 */
Mike J. Chen6143f5f2011-06-23 15:17:51 -0700146 private void notifyInterfaceStatusChanged(String iface, boolean up) {
San Mehat4d02d002010-01-22 16:07:46 -0800147 for (INetworkManagementEventObserver obs : mObservers) {
148 try {
Mike J. Chen6143f5f2011-06-23 15:17:51 -0700149 obs.interfaceStatusChanged(iface, up);
150 } catch (Exception ex) {
151 Slog.w(TAG, "Observer notifier failed", ex);
152 }
153 }
154 }
155
156 /**
157 * Notify our observers of an interface link status change.
158 * (typically, an Ethernet cable has been plugged-in or unplugged).
159 */
160 private void notifyInterfaceLinkStateChanged(String iface, boolean up) {
161 for (INetworkManagementEventObserver obs : mObservers) {
162 try {
163 obs.interfaceLinkStateChanged(iface, up);
San Mehat4d02d002010-01-22 16:07:46 -0800164 } catch (Exception ex) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800165 Slog.w(TAG, "Observer notifier failed", ex);
San Mehat4d02d002010-01-22 16:07:46 -0800166 }
167 }
168 }
169
170 /**
171 * Notify our observers of an interface addition.
172 */
173 private void notifyInterfaceAdded(String iface) {
174 for (INetworkManagementEventObserver obs : mObservers) {
175 try {
176 obs.interfaceAdded(iface);
177 } catch (Exception ex) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800178 Slog.w(TAG, "Observer notifier failed", ex);
San Mehat4d02d002010-01-22 16:07:46 -0800179 }
180 }
181 }
182
183 /**
184 * Notify our observers of an interface removal.
185 */
186 private void notifyInterfaceRemoved(String iface) {
187 for (INetworkManagementEventObserver obs : mObservers) {
188 try {
189 obs.interfaceRemoved(iface);
190 } catch (Exception ex) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800191 Slog.w(TAG, "Observer notifier failed", ex);
San Mehat4d02d002010-01-22 16:07:46 -0800192 }
193 }
194 }
195
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700196 /**
197 * Let us know the daemon is connected
198 */
199 protected void onConnected() {
200 if (DBG) Slog.d(TAG, "onConnected");
201 mConnectedSignal.countDown();
202 }
203
San Mehat4d02d002010-01-22 16:07:46 -0800204
San Mehat873f2142010-01-14 10:25:07 -0800205 //
206 // Netd Callback handling
207 //
208
209 class NetdCallbackReceiver implements INativeDaemonConnectorCallbacks {
210 public void onDaemonConnected() {
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700211 NetworkManagementService.this.onConnected();
San Mehat873f2142010-01-14 10:25:07 -0800212 new Thread() {
213 public void run() {
San Mehat873f2142010-01-14 10:25:07 -0800214 }
215 }.start();
216 }
217 public boolean onEvent(int code, String raw, String[] cooked) {
Robert Greenwalte3253922010-02-18 09:23:25 -0800218 if (code == NetdResponseCode.InterfaceChange) {
219 /*
220 * a network interface change occured
221 * Format: "NNN Iface added <name>"
222 * "NNN Iface removed <name>"
223 * "NNN Iface changed <name> <up/down>"
Mike J. Chen6143f5f2011-06-23 15:17:51 -0700224 * "NNN Iface linkstatus <name> <up/down>"
Robert Greenwalte3253922010-02-18 09:23:25 -0800225 */
226 if (cooked.length < 4 || !cooked[1].equals("Iface")) {
227 throw new IllegalStateException(
228 String.format("Invalid event from daemon (%s)", raw));
229 }
230 if (cooked[2].equals("added")) {
231 notifyInterfaceAdded(cooked[3]);
232 return true;
233 } else if (cooked[2].equals("removed")) {
234 notifyInterfaceRemoved(cooked[3]);
235 return true;
236 } else if (cooked[2].equals("changed") && cooked.length == 5) {
Mike J. Chen6143f5f2011-06-23 15:17:51 -0700237 notifyInterfaceStatusChanged(cooked[3], cooked[4].equals("up"));
238 return true;
239 } else if (cooked[2].equals("linkstatus") && cooked.length == 5) {
240 notifyInterfaceLinkStateChanged(cooked[3], cooked[4].equals("up"));
Robert Greenwalte3253922010-02-18 09:23:25 -0800241 return true;
242 }
243 throw new IllegalStateException(
244 String.format("Invalid event from daemon (%s)", raw));
245 }
246 return false;
San Mehat873f2142010-01-14 10:25:07 -0800247 }
248 }
249
San Mehated4fc8a2010-01-22 12:28:36 -0800250
San Mehat873f2142010-01-14 10:25:07 -0800251 //
252 // INetworkManagementService members
253 //
254
255 public String[] listInterfaces() throws IllegalStateException {
256 mContext.enforceCallingOrSelfPermission(
257 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
258
Kenny Roota80ce062010-06-01 13:23:53 -0700259 try {
260 return mConnector.doListCommand("interface list", NetdResponseCode.InterfaceListResult);
261 } catch (NativeDaemonConnectorException e) {
262 throw new IllegalStateException(
263 "Cannot communicate with native daemon to list interfaces");
264 }
San Mehated4fc8a2010-01-22 12:28:36 -0800265 }
266
267 public InterfaceConfiguration getInterfaceConfig(String iface) throws IllegalStateException {
Kenny Roota80ce062010-06-01 13:23:53 -0700268 String rsp;
269 try {
270 rsp = mConnector.doCommand("interface getcfg " + iface).get(0);
271 } catch (NativeDaemonConnectorException e) {
272 throw new IllegalStateException(
273 "Cannot communicate with native daemon to get interface config");
274 }
Joe Onorato8a9b2202010-02-26 18:56:32 -0800275 Slog.d(TAG, String.format("rsp <%s>", rsp));
San Mehated4fc8a2010-01-22 12:28:36 -0800276
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800277 // Rsp: 213 xx:xx:xx:xx:xx:xx yyy.yyy.yyy.yyy zzz [flag1 flag2 flag3]
San Mehated4fc8a2010-01-22 12:28:36 -0800278 StringTokenizer st = new StringTokenizer(rsp);
279
Kenny Roota80ce062010-06-01 13:23:53 -0700280 InterfaceConfiguration cfg;
San Mehated4fc8a2010-01-22 12:28:36 -0800281 try {
Kenny Roota80ce062010-06-01 13:23:53 -0700282 try {
283 int code = Integer.parseInt(st.nextToken(" "));
284 if (code != NetdResponseCode.InterfaceGetCfgResult) {
285 throw new IllegalStateException(
286 String.format("Expected code %d, but got %d",
287 NetdResponseCode.InterfaceGetCfgResult, code));
288 }
289 } catch (NumberFormatException nfe) {
San Mehated4fc8a2010-01-22 12:28:36 -0800290 throw new IllegalStateException(
Kenny Roota80ce062010-06-01 13:23:53 -0700291 String.format("Invalid response from daemon (%s)", rsp));
San Mehated4fc8a2010-01-22 12:28:36 -0800292 }
Kenny Roota80ce062010-06-01 13:23:53 -0700293
294 cfg = new InterfaceConfiguration();
295 cfg.hwAddr = st.nextToken(" ");
Robert Greenwalted126402011-01-28 15:34:55 -0800296 InetAddress addr = null;
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800297 int prefixLength = 0;
Kenny Roota80ce062010-06-01 13:23:53 -0700298 try {
Robert Greenwalte5903732011-02-22 16:00:42 -0800299 addr = NetworkUtils.numericToInetAddress(st.nextToken(" "));
300 } catch (IllegalArgumentException iae) {
301 Slog.e(TAG, "Failed to parse ipaddr", iae);
Kenny Roota80ce062010-06-01 13:23:53 -0700302 }
303
304 try {
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800305 prefixLength = Integer.parseInt(st.nextToken(" "));
306 } catch (NumberFormatException nfe) {
307 Slog.e(TAG, "Failed to parse prefixLength", nfe);
Kenny Roota80ce062010-06-01 13:23:53 -0700308 }
Robert Greenwalt04808c22010-12-13 17:01:41 -0800309
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800310 cfg.addr = new LinkAddress(addr, prefixLength);
Kenny Roota80ce062010-06-01 13:23:53 -0700311 cfg.interfaceFlags = st.nextToken("]").trim() +"]";
312 } catch (NoSuchElementException nsee) {
San Mehated4fc8a2010-01-22 12:28:36 -0800313 throw new IllegalStateException(
314 String.format("Invalid response from daemon (%s)", rsp));
315 }
Joe Onorato8a9b2202010-02-26 18:56:32 -0800316 Slog.d(TAG, String.format("flags <%s>", cfg.interfaceFlags));
San Mehated4fc8a2010-01-22 12:28:36 -0800317 return cfg;
318 }
319
320 public void setInterfaceConfig(
321 String iface, InterfaceConfiguration cfg) throws IllegalStateException {
Robert Greenwalted126402011-01-28 15:34:55 -0800322 LinkAddress linkAddr = cfg.addr;
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800323 if (linkAddr == null || linkAddr.getAddress() == null) {
324 throw new IllegalStateException("Null LinkAddress given");
Robert Greenwalted126402011-01-28 15:34:55 -0800325 }
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800326 String cmd = String.format("interface setcfg %s %s %d %s", iface,
327 linkAddr.getAddress().getHostAddress(),
328 linkAddr.getNetworkPrefixLength(),
329 cfg.interfaceFlags);
Kenny Roota80ce062010-06-01 13:23:53 -0700330 try {
331 mConnector.doCommand(cmd);
332 } catch (NativeDaemonConnectorException e) {
333 throw new IllegalStateException(
Robert Greenwalt81d5ad52010-12-16 11:27:38 -0800334 "Unable to communicate with native daemon to interface setcfg - " + e);
Kenny Roota80ce062010-06-01 13:23:53 -0700335 }
San Mehat873f2142010-01-14 10:25:07 -0800336 }
337
Irfan Sherifff5600612011-06-16 10:26:28 -0700338 /* TODO: This is right now a IPv4 only function. Works for wifi which loses its
339 IPv6 addresses on interface down, but we need to do full clean up here */
340 public void clearInterfaceAddresses(String iface) throws IllegalStateException {
341 String cmd = String.format("interface clearaddrs %s", iface);
342 try {
343 mConnector.doCommand(cmd);
344 } catch (NativeDaemonConnectorException e) {
345 throw new IllegalStateException(
346 "Unable to communicate with native daemon to interface clearallips - " + e);
347 }
348 }
349
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -0700350 public void addRoute(String interfaceName, RouteInfo route) {
351 modifyRoute(interfaceName, ADD, route);
352 }
353
354 public void removeRoute(String interfaceName, RouteInfo route) {
355 modifyRoute(interfaceName, REMOVE, route);
356 }
357
358 private void modifyRoute(String interfaceName, int action, RouteInfo route) {
359 ArrayList<String> rsp;
360
361 StringBuilder cmd;
362
363 switch (action) {
364 case ADD:
365 {
366 cmd = new StringBuilder("interface route add " + interfaceName);
367 break;
368 }
369 case REMOVE:
370 {
371 cmd = new StringBuilder("interface route remove " + interfaceName);
372 break;
373 }
374 default:
375 throw new IllegalStateException("Unknown action type " + action);
376 }
377
378 // create triplet: dest-ip-addr prefixlength gateway-ip-addr
379 LinkAddress la = route.getDestination();
380 cmd.append(' ');
381 cmd.append(la.getAddress().getHostAddress());
382 cmd.append(' ');
383 cmd.append(la.getNetworkPrefixLength());
384 cmd.append(' ');
385 if (route.getGateway() == null) {
386 if (la.getAddress() instanceof Inet4Address) {
387 cmd.append("0.0.0.0");
388 } else {
389 cmd.append ("::0");
390 }
391 } else {
392 cmd.append(route.getGateway().getHostAddress());
393 }
394 try {
395 rsp = mConnector.doCommand(cmd.toString());
396 } catch (NativeDaemonConnectorException e) {
397 throw new IllegalStateException(
398 "Unable to communicate with native dameon to add routes - "
399 + e);
400 }
401
402 for (String line : rsp) {
403 Log.v(TAG, "add route response is " + line);
404 }
405 }
406
407 private ArrayList<String> readRouteList(String filename) {
408 FileInputStream fstream = null;
409 ArrayList<String> list = new ArrayList<String>();
410
411 try {
412 fstream = new FileInputStream(filename);
413 DataInputStream in = new DataInputStream(fstream);
414 BufferedReader br = new BufferedReader(new InputStreamReader(in));
415 String s;
416
417 // throw away the title line
418
419 while (((s = br.readLine()) != null) && (s.length() != 0)) {
420 list.add(s);
421 }
422 } catch (IOException ex) {
423 // return current list, possibly empty
424 } finally {
425 if (fstream != null) {
426 try {
427 fstream.close();
428 } catch (IOException ex) {}
429 }
430 }
431
432 return list;
433 }
434
435 public RouteInfo[] getRoutes(String interfaceName) {
436 ArrayList<RouteInfo> routes = new ArrayList<RouteInfo>();
437
438 // v4 routes listed as:
439 // iface dest-addr gateway-addr flags refcnt use metric netmask mtu window IRTT
440 for (String s : readRouteList("/proc/net/route")) {
441 String[] fields = s.split("\t");
442
443 if (fields.length > 7) {
444 String iface = fields[0];
445
446 if (interfaceName.equals(iface)) {
447 String dest = fields[1];
448 String gate = fields[2];
449 String flags = fields[3]; // future use?
450 String mask = fields[7];
451 try {
452 // address stored as a hex string, ex: 0014A8C0
453 InetAddress destAddr =
454 NetworkUtils.intToInetAddress((int)Long.parseLong(dest, 16));
455 int prefixLength =
456 NetworkUtils.netmaskIntToPrefixLength(
457 (int)Long.parseLong(mask, 16));
458 LinkAddress linkAddress = new LinkAddress(destAddr, prefixLength);
459
460 // address stored as a hex string, ex 0014A8C0
461 InetAddress gatewayAddr =
462 NetworkUtils.intToInetAddress((int)Long.parseLong(gate, 16));
463
464 RouteInfo route = new RouteInfo(linkAddress, gatewayAddr);
465 routes.add(route);
466 } catch (Exception e) {
467 Log.e(TAG, "Error parsing route " + s + " : " + e);
468 continue;
469 }
470 }
471 }
472 }
473
474 // v6 routes listed as:
475 // dest-addr prefixlength ?? ?? gateway-addr ?? ?? ?? ?? iface
476 for (String s : readRouteList("/proc/net/ipv6_route")) {
477 String[]fields = s.split("\\s+");
478 if (fields.length > 9) {
479 String iface = fields[9].trim();
480 if (interfaceName.equals(iface)) {
481 String dest = fields[0];
482 String prefix = fields[1];
483 String gate = fields[4];
484
485 try {
486 // prefix length stored as a hex string, ex 40
487 int prefixLength = Integer.parseInt(prefix, 16);
488
489 // address stored as a 32 char hex string
490 // ex fe800000000000000000000000000000
491 InetAddress destAddr = NetworkUtils.hexToInet6Address(dest);
492 LinkAddress linkAddress = new LinkAddress(destAddr, prefixLength);
493
494 InetAddress gateAddr = NetworkUtils.hexToInet6Address(gate);
495
496 RouteInfo route = new RouteInfo(linkAddress, gateAddr);
497 routes.add(route);
498 } catch (Exception e) {
499 Log.e(TAG, "Error parsing route " + s + " : " + e);
500 continue;
501 }
502 }
503 }
504 }
505 return (RouteInfo[]) routes.toArray(new RouteInfo[0]);
506 }
507
San Mehat873f2142010-01-14 10:25:07 -0800508 public void shutdown() {
509 if (mContext.checkCallingOrSelfPermission(
510 android.Manifest.permission.SHUTDOWN)
511 != PackageManager.PERMISSION_GRANTED) {
512 throw new SecurityException("Requires SHUTDOWN permission");
513 }
514
Joe Onorato8a9b2202010-02-26 18:56:32 -0800515 Slog.d(TAG, "Shutting down");
San Mehat873f2142010-01-14 10:25:07 -0800516 }
517
518 public boolean getIpForwardingEnabled() throws IllegalStateException{
519 mContext.enforceCallingOrSelfPermission(
520 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
521
Kenny Roota80ce062010-06-01 13:23:53 -0700522 ArrayList<String> rsp;
523 try {
524 rsp = mConnector.doCommand("ipfwd status");
525 } catch (NativeDaemonConnectorException e) {
526 throw new IllegalStateException(
527 "Unable to communicate with native daemon to ipfwd status");
528 }
San Mehat873f2142010-01-14 10:25:07 -0800529
530 for (String line : rsp) {
Kenny Roota80ce062010-06-01 13:23:53 -0700531 String[] tok = line.split(" ");
532 if (tok.length < 3) {
533 Slog.e(TAG, "Malformed response from native daemon: " + line);
534 return false;
535 }
536
San Mehat873f2142010-01-14 10:25:07 -0800537 int code = Integer.parseInt(tok[0]);
538 if (code == NetdResponseCode.IpFwdStatusResult) {
539 // 211 Forwarding <enabled/disabled>
Kenny Roota80ce062010-06-01 13:23:53 -0700540 return "enabled".equals(tok[2]);
San Mehat873f2142010-01-14 10:25:07 -0800541 } else {
542 throw new IllegalStateException(String.format("Unexpected response code %d", code));
543 }
544 }
545 throw new IllegalStateException("Got an empty response");
546 }
547
548 public void setIpForwardingEnabled(boolean enable) throws IllegalStateException {
549 mContext.enforceCallingOrSelfPermission(
550 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
551 mConnector.doCommand(String.format("ipfwd %sable", (enable ? "en" : "dis")));
552 }
553
Robert Greenwaltbfb7bfa2010-03-24 16:03:21 -0700554 public void startTethering(String[] dhcpRange)
San Mehat873f2142010-01-14 10:25:07 -0800555 throws IllegalStateException {
556 mContext.enforceCallingOrSelfPermission(
557 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Robert Greenwaltbfb7bfa2010-03-24 16:03:21 -0700558 // cmd is "tether start first_start first_stop second_start second_stop ..."
559 // an odd number of addrs will fail
560 String cmd = "tether start";
561 for (String d : dhcpRange) {
562 cmd += " " + d;
563 }
Kenny Roota80ce062010-06-01 13:23:53 -0700564
565 try {
566 mConnector.doCommand(cmd);
567 } catch (NativeDaemonConnectorException e) {
568 throw new IllegalStateException("Unable to communicate to native daemon");
569 }
San Mehat873f2142010-01-14 10:25:07 -0800570 }
571
572 public void stopTethering() throws IllegalStateException {
573 mContext.enforceCallingOrSelfPermission(
574 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700575 try {
576 mConnector.doCommand("tether stop");
577 } catch (NativeDaemonConnectorException e) {
578 throw new IllegalStateException("Unable to communicate to native daemon to stop tether");
579 }
San Mehat873f2142010-01-14 10:25:07 -0800580 }
581
582 public boolean isTetheringStarted() throws IllegalStateException {
583 mContext.enforceCallingOrSelfPermission(
584 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
585
Kenny Roota80ce062010-06-01 13:23:53 -0700586 ArrayList<String> rsp;
587 try {
588 rsp = mConnector.doCommand("tether status");
589 } catch (NativeDaemonConnectorException e) {
590 throw new IllegalStateException(
591 "Unable to communicate to native daemon to get tether status");
592 }
San Mehat873f2142010-01-14 10:25:07 -0800593
594 for (String line : rsp) {
Kenny Roota80ce062010-06-01 13:23:53 -0700595 String[] tok = line.split(" ");
596 if (tok.length < 3) {
597 throw new IllegalStateException("Malformed response for tether status: " + line);
598 }
San Mehat873f2142010-01-14 10:25:07 -0800599 int code = Integer.parseInt(tok[0]);
600 if (code == NetdResponseCode.TetherStatusResult) {
601 // XXX: Tethering services <started/stopped> <TBD>...
Kenny Roota80ce062010-06-01 13:23:53 -0700602 return "started".equals(tok[2]);
San Mehat873f2142010-01-14 10:25:07 -0800603 } else {
604 throw new IllegalStateException(String.format("Unexpected response code %d", code));
605 }
606 }
607 throw new IllegalStateException("Got an empty response");
608 }
609
610 public void tetherInterface(String iface) throws IllegalStateException {
611 mContext.enforceCallingOrSelfPermission(
612 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700613 try {
614 mConnector.doCommand("tether interface add " + iface);
615 } catch (NativeDaemonConnectorException e) {
616 throw new IllegalStateException(
617 "Unable to communicate to native daemon for adding tether interface");
618 }
San Mehat873f2142010-01-14 10:25:07 -0800619 }
620
621 public void untetherInterface(String iface) {
622 mContext.enforceCallingOrSelfPermission(
623 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700624 try {
625 mConnector.doCommand("tether interface remove " + iface);
626 } catch (NativeDaemonConnectorException e) {
627 throw new IllegalStateException(
628 "Unable to communicate to native daemon for removing tether interface");
629 }
San Mehat873f2142010-01-14 10:25:07 -0800630 }
631
632 public String[] listTetheredInterfaces() throws IllegalStateException {
633 mContext.enforceCallingOrSelfPermission(
634 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700635 try {
636 return mConnector.doListCommand(
637 "tether interface list", NetdResponseCode.TetherInterfaceListResult);
638 } catch (NativeDaemonConnectorException e) {
639 throw new IllegalStateException(
640 "Unable to communicate to native daemon for listing tether interfaces");
641 }
San Mehat873f2142010-01-14 10:25:07 -0800642 }
643
644 public void setDnsForwarders(String[] dns) throws IllegalStateException {
645 mContext.enforceCallingOrSelfPermission(
646 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
647 try {
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800648 String cmd = "tether dns set";
San Mehat873f2142010-01-14 10:25:07 -0800649 for (String s : dns) {
Robert Greenwalte5903732011-02-22 16:00:42 -0800650 cmd += " " + NetworkUtils.numericToInetAddress(s).getHostAddress();
San Mehat873f2142010-01-14 10:25:07 -0800651 }
Kenny Roota80ce062010-06-01 13:23:53 -0700652 try {
653 mConnector.doCommand(cmd);
654 } catch (NativeDaemonConnectorException e) {
655 throw new IllegalStateException(
656 "Unable to communicate to native daemon for setting tether dns");
657 }
Robert Greenwalte5903732011-02-22 16:00:42 -0800658 } catch (IllegalArgumentException e) {
San Mehat873f2142010-01-14 10:25:07 -0800659 throw new IllegalStateException("Error resolving dns name", e);
660 }
661 }
662
663 public String[] getDnsForwarders() throws IllegalStateException {
664 mContext.enforceCallingOrSelfPermission(
665 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700666 try {
667 return mConnector.doListCommand(
668 "tether dns list", NetdResponseCode.TetherDnsFwdTgtListResult);
669 } catch (NativeDaemonConnectorException e) {
670 throw new IllegalStateException(
671 "Unable to communicate to native daemon for listing tether dns");
672 }
San Mehat873f2142010-01-14 10:25:07 -0800673 }
674
675 public void enableNat(String internalInterface, String externalInterface)
676 throws IllegalStateException {
677 mContext.enforceCallingOrSelfPermission(
678 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700679 try {
680 mConnector.doCommand(
681 String.format("nat enable %s %s", internalInterface, externalInterface));
682 } catch (NativeDaemonConnectorException e) {
683 throw new IllegalStateException(
684 "Unable to communicate to native daemon for enabling NAT interface");
685 }
San Mehat873f2142010-01-14 10:25:07 -0800686 }
687
688 public void disableNat(String internalInterface, String externalInterface)
689 throws IllegalStateException {
690 mContext.enforceCallingOrSelfPermission(
691 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700692 try {
693 mConnector.doCommand(
694 String.format("nat disable %s %s", internalInterface, externalInterface));
695 } catch (NativeDaemonConnectorException e) {
696 throw new IllegalStateException(
697 "Unable to communicate to native daemon for disabling NAT interface");
698 }
San Mehat873f2142010-01-14 10:25:07 -0800699 }
San Mehat72759df2010-01-19 13:50:37 -0800700
701 public String[] listTtys() throws IllegalStateException {
702 mContext.enforceCallingOrSelfPermission(
703 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700704 try {
705 return mConnector.doListCommand("list_ttys", NetdResponseCode.TtyListResult);
706 } catch (NativeDaemonConnectorException e) {
707 throw new IllegalStateException(
708 "Unable to communicate to native daemon for listing TTYs");
709 }
San Mehat72759df2010-01-19 13:50:37 -0800710 }
711
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800712 public void attachPppd(String tty, String localAddr, String remoteAddr, String dns1Addr,
713 String dns2Addr) throws IllegalStateException {
San Mehat72759df2010-01-19 13:50:37 -0800714 try {
715 mContext.enforceCallingOrSelfPermission(
716 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800717 mConnector.doCommand(String.format("pppd attach %s %s %s %s %s", tty,
Robert Greenwalte5903732011-02-22 16:00:42 -0800718 NetworkUtils.numericToInetAddress(localAddr).getHostAddress(),
719 NetworkUtils.numericToInetAddress(remoteAddr).getHostAddress(),
720 NetworkUtils.numericToInetAddress(dns1Addr).getHostAddress(),
721 NetworkUtils.numericToInetAddress(dns2Addr).getHostAddress()));
722 } catch (IllegalArgumentException e) {
San Mehat72759df2010-01-19 13:50:37 -0800723 throw new IllegalStateException("Error resolving addr", e);
Kenny Roota80ce062010-06-01 13:23:53 -0700724 } catch (NativeDaemonConnectorException e) {
725 throw new IllegalStateException("Error communicating to native daemon to attach pppd", e);
San Mehat72759df2010-01-19 13:50:37 -0800726 }
727 }
728
729 public void detachPppd(String tty) throws IllegalStateException {
730 mContext.enforceCallingOrSelfPermission(
731 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700732 try {
733 mConnector.doCommand(String.format("pppd detach %s", tty));
734 } catch (NativeDaemonConnectorException e) {
735 throw new IllegalStateException("Error communicating to native daemon to detach pppd", e);
736 }
San Mehat72759df2010-01-19 13:50:37 -0800737 }
Robert Greenwaltce1200d2010-02-18 11:25:54 -0800738
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700739 public void startAccessPoint(WifiConfiguration wifiConfig, String wlanIface, String softapIface)
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800740 throws IllegalStateException {
741 mContext.enforceCallingOrSelfPermission(
742 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
743 mContext.enforceCallingOrSelfPermission(
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700744 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700745 try {
746 mConnector.doCommand(String.format("softap stop " + wlanIface));
747 mConnector.doCommand(String.format("softap fwreload " + wlanIface + " AP"));
748 mConnector.doCommand(String.format("softap start " + wlanIface));
749 if (wifiConfig == null) {
750 mConnector.doCommand(String.format("softap set " + wlanIface + " " + softapIface));
751 } else {
752 /**
753 * softap set arg1 arg2 arg3 [arg4 arg5 arg6 arg7 arg8]
754 * argv1 - wlan interface
755 * argv2 - softap interface
756 * argv3 - SSID
757 * argv4 - Security
758 * argv5 - Key
759 * argv6 - Channel
760 * argv7 - Preamble
761 * argv8 - Max SCB
762 */
Irfan Sheriffec8d23a2011-02-16 17:00:33 -0800763 String str = String.format("softap set " + wlanIface + " " + softapIface +
764 " %s %s %s", convertQuotedString(wifiConfig.SSID),
765 getSecurityType(wifiConfig),
766 convertQuotedString(wifiConfig.preSharedKey));
Kenny Roota80ce062010-06-01 13:23:53 -0700767 mConnector.doCommand(str);
768 }
769 mConnector.doCommand(String.format("softap startap"));
770 } catch (NativeDaemonConnectorException e) {
771 throw new IllegalStateException("Error communicating to native daemon to start softap", e);
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -0800772 }
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800773 }
774
Irfan Sheriffa6e559e2010-05-24 14:55:42 -0700775 private String convertQuotedString(String s) {
Irfan Sheriff7baec0f2010-05-26 17:16:47 -0700776 if (s == null) {
777 return s;
778 }
779 /* Replace \ with \\, then " with \" and add quotes at end */
780 return '"' + s.replaceAll("\\\\","\\\\\\\\").replaceAll("\"","\\\\\"") + '"';
Irfan Sheriffa6e559e2010-05-24 14:55:42 -0700781 }
782
Irfan Sheriffec8d23a2011-02-16 17:00:33 -0800783 private String getSecurityType(WifiConfiguration wifiConfig) {
784 switch (wifiConfig.getAuthType()) {
785 case KeyMgmt.WPA_PSK:
786 return "wpa-psk";
787 case KeyMgmt.WPA2_PSK:
788 return "wpa2-psk";
789 default:
790 return "open";
791 }
792 }
793
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800794 public void stopAccessPoint() throws IllegalStateException {
795 mContext.enforceCallingOrSelfPermission(
796 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
797 mContext.enforceCallingOrSelfPermission(
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700798 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700799 try {
800 mConnector.doCommand("softap stopap");
801 } catch (NativeDaemonConnectorException e) {
802 throw new IllegalStateException("Error communicating to native daemon to stop soft AP",
803 e);
804 }
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800805 }
806
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700807 public void setAccessPoint(WifiConfiguration wifiConfig, String wlanIface, String softapIface)
808 throws IllegalStateException {
809 mContext.enforceCallingOrSelfPermission(
810 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
811 mContext.enforceCallingOrSelfPermission(
812 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700813 try {
814 if (wifiConfig == null) {
815 mConnector.doCommand(String.format("softap set " + wlanIface + " " + softapIface));
816 } else {
817 String str = String.format("softap set " + wlanIface + " " + softapIface
818 + " %s %s %s", convertQuotedString(wifiConfig.SSID),
Irfan Sheriffec8d23a2011-02-16 17:00:33 -0800819 getSecurityType(wifiConfig),
Kenny Roota80ce062010-06-01 13:23:53 -0700820 convertQuotedString(wifiConfig.preSharedKey));
821 mConnector.doCommand(str);
822 }
823 } catch (NativeDaemonConnectorException e) {
824 throw new IllegalStateException("Error communicating to native daemon to set soft AP",
825 e);
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700826 }
827 }
San Mehat91cac642010-03-31 14:31:36 -0700828
829 private long getInterfaceCounter(String iface, boolean rx) {
830 mContext.enforceCallingOrSelfPermission(
831 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
832 try {
Kenny Roota80ce062010-06-01 13:23:53 -0700833 String rsp;
834 try {
835 rsp = mConnector.doCommand(
836 String.format("interface read%scounter %s", (rx ? "rx" : "tx"), iface)).get(0);
837 } catch (NativeDaemonConnectorException e1) {
838 Slog.e(TAG, "Error communicating with native daemon", e1);
839 return -1;
840 }
841
842 String[] tok = rsp.split(" ");
843 if (tok.length < 2) {
844 Slog.e(TAG, String.format("Malformed response for reading %s interface",
845 (rx ? "rx" : "tx")));
846 return -1;
847 }
848
San Mehat91cac642010-03-31 14:31:36 -0700849 int code;
850 try {
851 code = Integer.parseInt(tok[0]);
852 } catch (NumberFormatException nfe) {
853 Slog.e(TAG, String.format("Error parsing code %s", tok[0]));
854 return -1;
855 }
856 if ((rx && code != NetdResponseCode.InterfaceRxCounterResult) || (
857 !rx && code != NetdResponseCode.InterfaceTxCounterResult)) {
858 Slog.e(TAG, String.format("Unexpected response code %d", code));
859 return -1;
860 }
861 return Long.parseLong(tok[1]);
862 } catch (Exception e) {
863 Slog.e(TAG, String.format(
864 "Failed to read interface %s counters", (rx ? "rx" : "tx")), e);
865 }
866 return -1;
867 }
868
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700869 @Override
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700870 public NetworkStats getNetworkStatsSummary() {
871 mContext.enforceCallingOrSelfPermission(
872 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
873
874 final String[] ifaces = listInterfaces();
Jeff Sharkey4a971222011-06-11 22:16:55 -0700875 final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), ifaces.length);
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700876
877 for (String iface : ifaces) {
878 final long rx = getInterfaceCounter(iface, true);
879 final long tx = getInterfaceCounter(iface, false);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700880 stats.addEntry(iface, UID_ALL, TAG_NONE, rx, tx);
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700881 }
882
Jeff Sharkey4a971222011-06-11 22:16:55 -0700883 return stats;
San Mehat91cac642010-03-31 14:31:36 -0700884 }
885
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700886 @Override
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700887 public NetworkStats getNetworkStatsDetail() {
888 mContext.enforceCallingOrSelfPermission(
889 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
890
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700891 if (STATS_NETFILTER.exists()) {
892 return getNetworkStatsDetailNetfilter(UID_ALL);
893 } else {
894 return getNetworkStatsDetailUidstat(UID_ALL);
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700895 }
San Mehat91cac642010-03-31 14:31:36 -0700896 }
897
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700898 @Override
899 public NetworkStats getNetworkStatsUidDetail(int uid) {
900 if (Binder.getCallingUid() != uid) {
901 mContext.enforceCallingOrSelfPermission(
902 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
903 }
904
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700905 if (STATS_NETFILTER.exists()) {
906 return getNetworkStatsDetailNetfilter(uid);
907 } else {
908 return getNetworkStatsDetailUidstat(uid);
909 }
910 }
911
912 /**
913 * Build {@link NetworkStats} with detailed UID statistics.
914 */
915 private NetworkStats getNetworkStatsDetailNetfilter(int limitUid) {
916 final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 24);
917
918 BufferedReader reader = null;
919 try {
920 reader = new BufferedReader(new FileReader(STATS_NETFILTER));
921
922 // assumes format from kernel:
923 // idx iface acct_tag_hex uid_tag_int rx_bytes tx_bytes
924
925 // skip first line, which is legend
926 String line = reader.readLine();
927 while ((line = reader.readLine()) != null) {
928 final StringTokenizer t = new StringTokenizer(line);
929
930 final String idx = t.nextToken();
931 final String iface = t.nextToken();
932
933 try {
934 // TODO: kernel currently emits tag in upper half of long;
935 // eventually switch to directly using int.
936 final int tag = (int) (Long.parseLong(t.nextToken().substring(2), 16) >> 32);
937 final int uid = Integer.parseInt(t.nextToken());
938 final long rx = Long.parseLong(t.nextToken());
939 final long tx = Long.parseLong(t.nextToken());
Jeff Sharkeyd03fd3f2011-06-19 20:55:09 -0700940
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700941 if (limitUid == UID_ALL || limitUid == uid) {
942 stats.addEntry(iface, uid, tag, rx, tx);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700943 }
944 } catch (NumberFormatException e) {
945 Slog.w(TAG, "problem parsing stats for idx " + idx + ": " + e);
946 }
947 }
948 } catch (IOException e) {
949 Slog.w(TAG, "problem parsing stats: " + e);
950 } finally {
951 IoUtils.closeQuietly(reader);
952 }
953
Jeff Sharkey4a971222011-06-11 22:16:55 -0700954 return stats;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700955 }
956
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700957 /**
958 * Build {@link NetworkStats} with detailed UID statistics.
959 *
960 * @deprecated since this uses older "uid_stat" data, and doesn't provide
961 * tag-level granularity or additional variables.
962 */
963 @Deprecated
964 private NetworkStats getNetworkStatsDetailUidstat(int limitUid) {
965 final String[] knownUids;
966 if (limitUid == UID_ALL) {
967 knownUids = STATS_UIDSTAT.list();
968 } else {
969 knownUids = new String[] { String.valueOf(limitUid) };
970 }
971
972 final NetworkStats stats = new NetworkStats(
973 SystemClock.elapsedRealtime(), knownUids.length);
974 for (String uid : knownUids) {
975 final int uidInt = Integer.parseInt(uid);
976 final File uidPath = new File(STATS_UIDSTAT, uid);
977 final long rx = readSingleLongFromFile(new File(uidPath, "tcp_rcv"));
978 final long tx = readSingleLongFromFile(new File(uidPath, "tcp_snd"));
979 stats.addEntry(IFACE_ALL, uidInt, TAG_NONE, rx, tx);
980 }
981
982 return stats;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700983 }
984
San Mehatf0db6e12010-04-07 15:22:10 -0700985 public void setInterfaceThrottle(String iface, int rxKbps, int txKbps) {
San Mehat91cac642010-03-31 14:31:36 -0700986 mContext.enforceCallingOrSelfPermission(
987 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700988 try {
989 mConnector.doCommand(String.format(
990 "interface setthrottle %s %d %d", iface, rxKbps, txKbps));
991 } catch (NativeDaemonConnectorException e) {
992 Slog.e(TAG, "Error communicating with native daemon to set throttle", e);
993 }
San Mehat91cac642010-03-31 14:31:36 -0700994 }
995
996 private int getInterfaceThrottle(String iface, boolean rx) {
997 mContext.enforceCallingOrSelfPermission(
998 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
999 try {
Kenny Roota80ce062010-06-01 13:23:53 -07001000 String rsp;
1001 try {
1002 rsp = mConnector.doCommand(
1003 String.format("interface getthrottle %s %s", iface,
1004 (rx ? "rx" : "tx"))).get(0);
1005 } catch (NativeDaemonConnectorException e) {
1006 Slog.e(TAG, "Error communicating with native daemon to getthrottle", e);
1007 return -1;
1008 }
1009
1010 String[] tok = rsp.split(" ");
1011 if (tok.length < 2) {
1012 Slog.e(TAG, "Malformed response to getthrottle command");
1013 return -1;
1014 }
1015
San Mehat91cac642010-03-31 14:31:36 -07001016 int code;
1017 try {
1018 code = Integer.parseInt(tok[0]);
1019 } catch (NumberFormatException nfe) {
1020 Slog.e(TAG, String.format("Error parsing code %s", tok[0]));
1021 return -1;
1022 }
1023 if ((rx && code != NetdResponseCode.InterfaceRxThrottleResult) || (
1024 !rx && code != NetdResponseCode.InterfaceTxThrottleResult)) {
1025 Slog.e(TAG, String.format("Unexpected response code %d", code));
1026 return -1;
1027 }
1028 return Integer.parseInt(tok[1]);
1029 } catch (Exception e) {
1030 Slog.e(TAG, String.format(
1031 "Failed to read interface %s throttle value", (rx ? "rx" : "tx")), e);
1032 }
1033 return -1;
1034 }
1035
1036 public int getInterfaceRxThrottle(String iface) {
1037 return getInterfaceThrottle(iface, true);
1038 }
1039
1040 public int getInterfaceTxThrottle(String iface) {
1041 return getInterfaceThrottle(iface, false);
1042 }
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001043
Jeff Sharkey0a9ee122011-06-22 16:32:41 -07001044 @Override
1045 public void setBandwidthControlEnabled(boolean enabled) {
1046 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1047 mConnector.doCommand(String.format("bandwidth %s", (enabled ? "enable" : "disable")));
1048 }
1049
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001050 /**
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001051 * Utility method to read a single plain-text {@link Long} from the given
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001052 * {@link File}, usually from a {@code /proc/} filesystem.
1053 */
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001054 private static long readSingleLongFromFile(File file) {
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001055 try {
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001056 final byte[] buffer = IoUtils.readFileAsByteArray(file.toString());
1057 return Long.parseLong(new String(buffer).trim());
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001058 } catch (NumberFormatException e) {
1059 return -1;
1060 } catch (IOException e) {
1061 return -1;
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001062 }
1063 }
San Mehat873f2142010-01-14 10:25:07 -08001064}