blob: d5bdd21dd7334219e172d02765319c66318969ee [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;
22
San Mehat873f2142010-01-14 10:25:07 -080023import android.content.Context;
San Mehat873f2142010-01-14 10:25:07 -080024import android.content.pm.PackageManager;
San Mehat4d02d002010-01-22 16:07:46 -080025import android.net.INetworkManagementEventObserver;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070026import android.net.InterfaceConfiguration;
Robert Greenwalted126402011-01-28 15:34:55 -080027import android.net.LinkAddress;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070028import android.net.NetworkStats;
Robert Greenwalted126402011-01-28 15:34:55 -080029import android.net.NetworkUtils;
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -070030import android.net.RouteInfo;
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -080031import android.net.wifi.WifiConfiguration;
32import android.net.wifi.WifiConfiguration.KeyMgmt;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070033import android.os.Binder;
San Mehat873f2142010-01-14 10:25:07 -080034import android.os.INetworkManagementService;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070035import android.os.SystemClock;
Marco Nelissen62dbb222010-02-18 10:56:30 -080036import android.os.SystemProperties;
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -080037import android.util.Log;
Joe Onorato8a9b2202010-02-26 18:56:32 -080038import android.util.Slog;
San Mehat873f2142010-01-14 10:25:07 -080039
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -070040import java.io.BufferedReader;
41import java.io.DataInputStream;
San Mehat873f2142010-01-14 10:25:07 -080042import java.io.File;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070043import java.io.FileInputStream;
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -070044import java.io.FileReader;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070045import java.io.IOException;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070046import java.io.InputStreamReader;
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -070047import java.net.Inet4Address;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070048import java.net.InetAddress;
49import java.util.ArrayList;
50import java.util.NoSuchElementException;
51import java.util.StringTokenizer;
Robert Greenwalte5c3afb2010-09-22 14:32:35 -070052import java.util.concurrent.CountDownLatch;
San Mehat873f2142010-01-14 10:25:07 -080053
Jeff Sharkey9a13f362011-04-26 16:25:36 -070054import libcore.io.IoUtils;
55
San Mehat873f2142010-01-14 10:25:07 -080056/**
57 * @hide
58 */
59class NetworkManagementService extends INetworkManagementService.Stub {
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070060 private static final String TAG = "NetworkManagementService";
Dianne Hackborncef65ee2010-09-30 18:27:22 -070061 private static final boolean DBG = false;
Kenny Root305bcbf2010-09-03 07:56:38 -070062 private static final String NETD_TAG = "NetdConnector";
63
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -070064 private static final int ADD = 1;
65 private static final int REMOVE = 2;
66
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -070067 @Deprecated
68 private static final File STATS_UIDSTAT = new File("/proc/uid_stat");
69 private static final File STATS_NETFILTER = new File("/proc/net/xt_qtaguid/stats");
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070070
San Mehat873f2142010-01-14 10:25:07 -080071 class NetdResponseCode {
72 public static final int InterfaceListResult = 110;
73 public static final int TetherInterfaceListResult = 111;
74 public static final int TetherDnsFwdTgtListResult = 112;
San Mehat72759df2010-01-19 13:50:37 -080075 public static final int TtyListResult = 113;
San Mehat873f2142010-01-14 10:25:07 -080076
77 public static final int TetherStatusResult = 210;
78 public static final int IpFwdStatusResult = 211;
San Mehated4fc8a2010-01-22 12:28:36 -080079 public static final int InterfaceGetCfgResult = 213;
Robert Greenwalte3253922010-02-18 09:23:25 -080080 public static final int SoftapStatusResult = 214;
81 public static final int UsbRNDISStatusResult = 215;
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 /**
Wink Saville1a7e6712011-01-09 12:16:38 -0800144 * Notify our observers of an interface link status change
San Mehat4d02d002010-01-22 16:07:46 -0800145 */
Wink Saville1a7e6712011-01-09 12:16:38 -0800146 private void notifyInterfaceLinkStatusChanged(String iface, boolean link) {
San Mehat4d02d002010-01-22 16:07:46 -0800147 for (INetworkManagementEventObserver obs : mObservers) {
148 try {
Wink Saville1a7e6712011-01-09 12:16:38 -0800149 obs.interfaceLinkStatusChanged(iface, link);
San Mehat4d02d002010-01-22 16:07:46 -0800150 } catch (Exception ex) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800151 Slog.w(TAG, "Observer notifier failed", ex);
San Mehat4d02d002010-01-22 16:07:46 -0800152 }
153 }
154 }
155
156 /**
157 * Notify our observers of an interface addition.
158 */
159 private void notifyInterfaceAdded(String iface) {
160 for (INetworkManagementEventObserver obs : mObservers) {
161 try {
162 obs.interfaceAdded(iface);
163 } catch (Exception ex) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800164 Slog.w(TAG, "Observer notifier failed", ex);
San Mehat4d02d002010-01-22 16:07:46 -0800165 }
166 }
167 }
168
169 /**
170 * Notify our observers of an interface removal.
171 */
172 private void notifyInterfaceRemoved(String iface) {
173 for (INetworkManagementEventObserver obs : mObservers) {
174 try {
175 obs.interfaceRemoved(iface);
176 } catch (Exception ex) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800177 Slog.w(TAG, "Observer notifier failed", ex);
San Mehat4d02d002010-01-22 16:07:46 -0800178 }
179 }
180 }
181
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700182 /**
183 * Let us know the daemon is connected
184 */
185 protected void onConnected() {
186 if (DBG) Slog.d(TAG, "onConnected");
187 mConnectedSignal.countDown();
188 }
189
San Mehat4d02d002010-01-22 16:07:46 -0800190
San Mehat873f2142010-01-14 10:25:07 -0800191 //
192 // Netd Callback handling
193 //
194
195 class NetdCallbackReceiver implements INativeDaemonConnectorCallbacks {
196 public void onDaemonConnected() {
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700197 NetworkManagementService.this.onConnected();
San Mehat873f2142010-01-14 10:25:07 -0800198 new Thread() {
199 public void run() {
San Mehat873f2142010-01-14 10:25:07 -0800200 }
201 }.start();
202 }
203 public boolean onEvent(int code, String raw, String[] cooked) {
Robert Greenwalte3253922010-02-18 09:23:25 -0800204 if (code == NetdResponseCode.InterfaceChange) {
205 /*
206 * a network interface change occured
207 * Format: "NNN Iface added <name>"
208 * "NNN Iface removed <name>"
209 * "NNN Iface changed <name> <up/down>"
210 */
211 if (cooked.length < 4 || !cooked[1].equals("Iface")) {
212 throw new IllegalStateException(
213 String.format("Invalid event from daemon (%s)", raw));
214 }
215 if (cooked[2].equals("added")) {
216 notifyInterfaceAdded(cooked[3]);
217 return true;
218 } else if (cooked[2].equals("removed")) {
219 notifyInterfaceRemoved(cooked[3]);
220 return true;
221 } else if (cooked[2].equals("changed") && cooked.length == 5) {
Wink Saville1a7e6712011-01-09 12:16:38 -0800222 notifyInterfaceLinkStatusChanged(cooked[3], cooked[4].equals("up"));
Robert Greenwalte3253922010-02-18 09:23:25 -0800223 return true;
224 }
225 throw new IllegalStateException(
226 String.format("Invalid event from daemon (%s)", raw));
227 }
228 return false;
San Mehat873f2142010-01-14 10:25:07 -0800229 }
230 }
231
San Mehated4fc8a2010-01-22 12:28:36 -0800232
San Mehat873f2142010-01-14 10:25:07 -0800233 //
234 // INetworkManagementService members
235 //
236
237 public String[] listInterfaces() throws IllegalStateException {
238 mContext.enforceCallingOrSelfPermission(
239 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
240
Kenny Roota80ce062010-06-01 13:23:53 -0700241 try {
242 return mConnector.doListCommand("interface list", NetdResponseCode.InterfaceListResult);
243 } catch (NativeDaemonConnectorException e) {
244 throw new IllegalStateException(
245 "Cannot communicate with native daemon to list interfaces");
246 }
San Mehated4fc8a2010-01-22 12:28:36 -0800247 }
248
249 public InterfaceConfiguration getInterfaceConfig(String iface) throws IllegalStateException {
Kenny Roota80ce062010-06-01 13:23:53 -0700250 String rsp;
251 try {
252 rsp = mConnector.doCommand("interface getcfg " + iface).get(0);
253 } catch (NativeDaemonConnectorException e) {
254 throw new IllegalStateException(
255 "Cannot communicate with native daemon to get interface config");
256 }
Joe Onorato8a9b2202010-02-26 18:56:32 -0800257 Slog.d(TAG, String.format("rsp <%s>", rsp));
San Mehated4fc8a2010-01-22 12:28:36 -0800258
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800259 // Rsp: 213 xx:xx:xx:xx:xx:xx yyy.yyy.yyy.yyy zzz [flag1 flag2 flag3]
San Mehated4fc8a2010-01-22 12:28:36 -0800260 StringTokenizer st = new StringTokenizer(rsp);
261
Kenny Roota80ce062010-06-01 13:23:53 -0700262 InterfaceConfiguration cfg;
San Mehated4fc8a2010-01-22 12:28:36 -0800263 try {
Kenny Roota80ce062010-06-01 13:23:53 -0700264 try {
265 int code = Integer.parseInt(st.nextToken(" "));
266 if (code != NetdResponseCode.InterfaceGetCfgResult) {
267 throw new IllegalStateException(
268 String.format("Expected code %d, but got %d",
269 NetdResponseCode.InterfaceGetCfgResult, code));
270 }
271 } catch (NumberFormatException nfe) {
San Mehated4fc8a2010-01-22 12:28:36 -0800272 throw new IllegalStateException(
Kenny Roota80ce062010-06-01 13:23:53 -0700273 String.format("Invalid response from daemon (%s)", rsp));
San Mehated4fc8a2010-01-22 12:28:36 -0800274 }
Kenny Roota80ce062010-06-01 13:23:53 -0700275
276 cfg = new InterfaceConfiguration();
277 cfg.hwAddr = st.nextToken(" ");
Robert Greenwalted126402011-01-28 15:34:55 -0800278 InetAddress addr = null;
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800279 int prefixLength = 0;
Kenny Roota80ce062010-06-01 13:23:53 -0700280 try {
Robert Greenwalte5903732011-02-22 16:00:42 -0800281 addr = NetworkUtils.numericToInetAddress(st.nextToken(" "));
282 } catch (IllegalArgumentException iae) {
283 Slog.e(TAG, "Failed to parse ipaddr", iae);
Kenny Roota80ce062010-06-01 13:23:53 -0700284 }
285
286 try {
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800287 prefixLength = Integer.parseInt(st.nextToken(" "));
288 } catch (NumberFormatException nfe) {
289 Slog.e(TAG, "Failed to parse prefixLength", nfe);
Kenny Roota80ce062010-06-01 13:23:53 -0700290 }
Robert Greenwalt04808c22010-12-13 17:01:41 -0800291
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800292 cfg.addr = new LinkAddress(addr, prefixLength);
Kenny Roota80ce062010-06-01 13:23:53 -0700293 cfg.interfaceFlags = st.nextToken("]").trim() +"]";
294 } catch (NoSuchElementException nsee) {
San Mehated4fc8a2010-01-22 12:28:36 -0800295 throw new IllegalStateException(
296 String.format("Invalid response from daemon (%s)", rsp));
297 }
Joe Onorato8a9b2202010-02-26 18:56:32 -0800298 Slog.d(TAG, String.format("flags <%s>", cfg.interfaceFlags));
San Mehated4fc8a2010-01-22 12:28:36 -0800299 return cfg;
300 }
301
302 public void setInterfaceConfig(
303 String iface, InterfaceConfiguration cfg) throws IllegalStateException {
Robert Greenwalted126402011-01-28 15:34:55 -0800304 LinkAddress linkAddr = cfg.addr;
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800305 if (linkAddr == null || linkAddr.getAddress() == null) {
306 throw new IllegalStateException("Null LinkAddress given");
Robert Greenwalted126402011-01-28 15:34:55 -0800307 }
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800308 String cmd = String.format("interface setcfg %s %s %d %s", iface,
309 linkAddr.getAddress().getHostAddress(),
310 linkAddr.getNetworkPrefixLength(),
311 cfg.interfaceFlags);
Kenny Roota80ce062010-06-01 13:23:53 -0700312 try {
313 mConnector.doCommand(cmd);
314 } catch (NativeDaemonConnectorException e) {
315 throw new IllegalStateException(
Robert Greenwalt81d5ad52010-12-16 11:27:38 -0800316 "Unable to communicate with native daemon to interface setcfg - " + e);
Kenny Roota80ce062010-06-01 13:23:53 -0700317 }
San Mehat873f2142010-01-14 10:25:07 -0800318 }
319
Irfan Sherifff5600612011-06-16 10:26:28 -0700320 /* TODO: This is right now a IPv4 only function. Works for wifi which loses its
321 IPv6 addresses on interface down, but we need to do full clean up here */
322 public void clearInterfaceAddresses(String iface) throws IllegalStateException {
323 String cmd = String.format("interface clearaddrs %s", iface);
324 try {
325 mConnector.doCommand(cmd);
326 } catch (NativeDaemonConnectorException e) {
327 throw new IllegalStateException(
328 "Unable to communicate with native daemon to interface clearallips - " + e);
329 }
330 }
331
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -0700332 public void addRoute(String interfaceName, RouteInfo route) {
333 modifyRoute(interfaceName, ADD, route);
334 }
335
336 public void removeRoute(String interfaceName, RouteInfo route) {
337 modifyRoute(interfaceName, REMOVE, route);
338 }
339
340 private void modifyRoute(String interfaceName, int action, RouteInfo route) {
341 ArrayList<String> rsp;
342
343 StringBuilder cmd;
344
345 switch (action) {
346 case ADD:
347 {
348 cmd = new StringBuilder("interface route add " + interfaceName);
349 break;
350 }
351 case REMOVE:
352 {
353 cmd = new StringBuilder("interface route remove " + interfaceName);
354 break;
355 }
356 default:
357 throw new IllegalStateException("Unknown action type " + action);
358 }
359
360 // create triplet: dest-ip-addr prefixlength gateway-ip-addr
361 LinkAddress la = route.getDestination();
362 cmd.append(' ');
363 cmd.append(la.getAddress().getHostAddress());
364 cmd.append(' ');
365 cmd.append(la.getNetworkPrefixLength());
366 cmd.append(' ');
367 if (route.getGateway() == null) {
368 if (la.getAddress() instanceof Inet4Address) {
369 cmd.append("0.0.0.0");
370 } else {
371 cmd.append ("::0");
372 }
373 } else {
374 cmd.append(route.getGateway().getHostAddress());
375 }
376 try {
377 rsp = mConnector.doCommand(cmd.toString());
378 } catch (NativeDaemonConnectorException e) {
379 throw new IllegalStateException(
380 "Unable to communicate with native dameon to add routes - "
381 + e);
382 }
383
384 for (String line : rsp) {
385 Log.v(TAG, "add route response is " + line);
386 }
387 }
388
389 private ArrayList<String> readRouteList(String filename) {
390 FileInputStream fstream = null;
391 ArrayList<String> list = new ArrayList<String>();
392
393 try {
394 fstream = new FileInputStream(filename);
395 DataInputStream in = new DataInputStream(fstream);
396 BufferedReader br = new BufferedReader(new InputStreamReader(in));
397 String s;
398
399 // throw away the title line
400
401 while (((s = br.readLine()) != null) && (s.length() != 0)) {
402 list.add(s);
403 }
404 } catch (IOException ex) {
405 // return current list, possibly empty
406 } finally {
407 if (fstream != null) {
408 try {
409 fstream.close();
410 } catch (IOException ex) {}
411 }
412 }
413
414 return list;
415 }
416
417 public RouteInfo[] getRoutes(String interfaceName) {
418 ArrayList<RouteInfo> routes = new ArrayList<RouteInfo>();
419
420 // v4 routes listed as:
421 // iface dest-addr gateway-addr flags refcnt use metric netmask mtu window IRTT
422 for (String s : readRouteList("/proc/net/route")) {
423 String[] fields = s.split("\t");
424
425 if (fields.length > 7) {
426 String iface = fields[0];
427
428 if (interfaceName.equals(iface)) {
429 String dest = fields[1];
430 String gate = fields[2];
431 String flags = fields[3]; // future use?
432 String mask = fields[7];
433 try {
434 // address stored as a hex string, ex: 0014A8C0
435 InetAddress destAddr =
436 NetworkUtils.intToInetAddress((int)Long.parseLong(dest, 16));
437 int prefixLength =
438 NetworkUtils.netmaskIntToPrefixLength(
439 (int)Long.parseLong(mask, 16));
440 LinkAddress linkAddress = new LinkAddress(destAddr, prefixLength);
441
442 // address stored as a hex string, ex 0014A8C0
443 InetAddress gatewayAddr =
444 NetworkUtils.intToInetAddress((int)Long.parseLong(gate, 16));
445
446 RouteInfo route = new RouteInfo(linkAddress, gatewayAddr);
447 routes.add(route);
448 } catch (Exception e) {
449 Log.e(TAG, "Error parsing route " + s + " : " + e);
450 continue;
451 }
452 }
453 }
454 }
455
456 // v6 routes listed as:
457 // dest-addr prefixlength ?? ?? gateway-addr ?? ?? ?? ?? iface
458 for (String s : readRouteList("/proc/net/ipv6_route")) {
459 String[]fields = s.split("\\s+");
460 if (fields.length > 9) {
461 String iface = fields[9].trim();
462 if (interfaceName.equals(iface)) {
463 String dest = fields[0];
464 String prefix = fields[1];
465 String gate = fields[4];
466
467 try {
468 // prefix length stored as a hex string, ex 40
469 int prefixLength = Integer.parseInt(prefix, 16);
470
471 // address stored as a 32 char hex string
472 // ex fe800000000000000000000000000000
473 InetAddress destAddr = NetworkUtils.hexToInet6Address(dest);
474 LinkAddress linkAddress = new LinkAddress(destAddr, prefixLength);
475
476 InetAddress gateAddr = NetworkUtils.hexToInet6Address(gate);
477
478 RouteInfo route = new RouteInfo(linkAddress, gateAddr);
479 routes.add(route);
480 } catch (Exception e) {
481 Log.e(TAG, "Error parsing route " + s + " : " + e);
482 continue;
483 }
484 }
485 }
486 }
487 return (RouteInfo[]) routes.toArray(new RouteInfo[0]);
488 }
489
San Mehat873f2142010-01-14 10:25:07 -0800490 public void shutdown() {
491 if (mContext.checkCallingOrSelfPermission(
492 android.Manifest.permission.SHUTDOWN)
493 != PackageManager.PERMISSION_GRANTED) {
494 throw new SecurityException("Requires SHUTDOWN permission");
495 }
496
Joe Onorato8a9b2202010-02-26 18:56:32 -0800497 Slog.d(TAG, "Shutting down");
San Mehat873f2142010-01-14 10:25:07 -0800498 }
499
500 public boolean getIpForwardingEnabled() throws IllegalStateException{
501 mContext.enforceCallingOrSelfPermission(
502 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
503
Kenny Roota80ce062010-06-01 13:23:53 -0700504 ArrayList<String> rsp;
505 try {
506 rsp = mConnector.doCommand("ipfwd status");
507 } catch (NativeDaemonConnectorException e) {
508 throw new IllegalStateException(
509 "Unable to communicate with native daemon to ipfwd status");
510 }
San Mehat873f2142010-01-14 10:25:07 -0800511
512 for (String line : rsp) {
Kenny Roota80ce062010-06-01 13:23:53 -0700513 String[] tok = line.split(" ");
514 if (tok.length < 3) {
515 Slog.e(TAG, "Malformed response from native daemon: " + line);
516 return false;
517 }
518
San Mehat873f2142010-01-14 10:25:07 -0800519 int code = Integer.parseInt(tok[0]);
520 if (code == NetdResponseCode.IpFwdStatusResult) {
521 // 211 Forwarding <enabled/disabled>
Kenny Roota80ce062010-06-01 13:23:53 -0700522 return "enabled".equals(tok[2]);
San Mehat873f2142010-01-14 10:25:07 -0800523 } else {
524 throw new IllegalStateException(String.format("Unexpected response code %d", code));
525 }
526 }
527 throw new IllegalStateException("Got an empty response");
528 }
529
530 public void setIpForwardingEnabled(boolean enable) throws IllegalStateException {
531 mContext.enforceCallingOrSelfPermission(
532 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
533 mConnector.doCommand(String.format("ipfwd %sable", (enable ? "en" : "dis")));
534 }
535
Robert Greenwaltbfb7bfa2010-03-24 16:03:21 -0700536 public void startTethering(String[] dhcpRange)
San Mehat873f2142010-01-14 10:25:07 -0800537 throws IllegalStateException {
538 mContext.enforceCallingOrSelfPermission(
539 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Robert Greenwaltbfb7bfa2010-03-24 16:03:21 -0700540 // cmd is "tether start first_start first_stop second_start second_stop ..."
541 // an odd number of addrs will fail
542 String cmd = "tether start";
543 for (String d : dhcpRange) {
544 cmd += " " + d;
545 }
Kenny Roota80ce062010-06-01 13:23:53 -0700546
547 try {
548 mConnector.doCommand(cmd);
549 } catch (NativeDaemonConnectorException e) {
550 throw new IllegalStateException("Unable to communicate to native daemon");
551 }
San Mehat873f2142010-01-14 10:25:07 -0800552 }
553
554 public void stopTethering() 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("tether stop");
559 } catch (NativeDaemonConnectorException e) {
560 throw new IllegalStateException("Unable to communicate to native daemon to stop tether");
561 }
San Mehat873f2142010-01-14 10:25:07 -0800562 }
563
564 public boolean isTetheringStarted() throws IllegalStateException {
565 mContext.enforceCallingOrSelfPermission(
566 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
567
Kenny Roota80ce062010-06-01 13:23:53 -0700568 ArrayList<String> rsp;
569 try {
570 rsp = mConnector.doCommand("tether status");
571 } catch (NativeDaemonConnectorException e) {
572 throw new IllegalStateException(
573 "Unable to communicate to native daemon to get tether status");
574 }
San Mehat873f2142010-01-14 10:25:07 -0800575
576 for (String line : rsp) {
Kenny Roota80ce062010-06-01 13:23:53 -0700577 String[] tok = line.split(" ");
578 if (tok.length < 3) {
579 throw new IllegalStateException("Malformed response for tether status: " + line);
580 }
San Mehat873f2142010-01-14 10:25:07 -0800581 int code = Integer.parseInt(tok[0]);
582 if (code == NetdResponseCode.TetherStatusResult) {
583 // XXX: Tethering services <started/stopped> <TBD>...
Kenny Roota80ce062010-06-01 13:23:53 -0700584 return "started".equals(tok[2]);
San Mehat873f2142010-01-14 10:25:07 -0800585 } else {
586 throw new IllegalStateException(String.format("Unexpected response code %d", code));
587 }
588 }
589 throw new IllegalStateException("Got an empty response");
590 }
591
592 public void tetherInterface(String iface) throws IllegalStateException {
593 mContext.enforceCallingOrSelfPermission(
594 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700595 try {
596 mConnector.doCommand("tether interface add " + iface);
597 } catch (NativeDaemonConnectorException e) {
598 throw new IllegalStateException(
599 "Unable to communicate to native daemon for adding tether interface");
600 }
San Mehat873f2142010-01-14 10:25:07 -0800601 }
602
603 public void untetherInterface(String iface) {
604 mContext.enforceCallingOrSelfPermission(
605 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700606 try {
607 mConnector.doCommand("tether interface remove " + iface);
608 } catch (NativeDaemonConnectorException e) {
609 throw new IllegalStateException(
610 "Unable to communicate to native daemon for removing tether interface");
611 }
San Mehat873f2142010-01-14 10:25:07 -0800612 }
613
614 public String[] listTetheredInterfaces() throws IllegalStateException {
615 mContext.enforceCallingOrSelfPermission(
616 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700617 try {
618 return mConnector.doListCommand(
619 "tether interface list", NetdResponseCode.TetherInterfaceListResult);
620 } catch (NativeDaemonConnectorException e) {
621 throw new IllegalStateException(
622 "Unable to communicate to native daemon for listing tether interfaces");
623 }
San Mehat873f2142010-01-14 10:25:07 -0800624 }
625
626 public void setDnsForwarders(String[] dns) throws IllegalStateException {
627 mContext.enforceCallingOrSelfPermission(
628 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
629 try {
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800630 String cmd = "tether dns set";
San Mehat873f2142010-01-14 10:25:07 -0800631 for (String s : dns) {
Robert Greenwalte5903732011-02-22 16:00:42 -0800632 cmd += " " + NetworkUtils.numericToInetAddress(s).getHostAddress();
San Mehat873f2142010-01-14 10:25:07 -0800633 }
Kenny Roota80ce062010-06-01 13:23:53 -0700634 try {
635 mConnector.doCommand(cmd);
636 } catch (NativeDaemonConnectorException e) {
637 throw new IllegalStateException(
638 "Unable to communicate to native daemon for setting tether dns");
639 }
Robert Greenwalte5903732011-02-22 16:00:42 -0800640 } catch (IllegalArgumentException e) {
San Mehat873f2142010-01-14 10:25:07 -0800641 throw new IllegalStateException("Error resolving dns name", e);
642 }
643 }
644
645 public String[] getDnsForwarders() throws IllegalStateException {
646 mContext.enforceCallingOrSelfPermission(
647 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700648 try {
649 return mConnector.doListCommand(
650 "tether dns list", NetdResponseCode.TetherDnsFwdTgtListResult);
651 } catch (NativeDaemonConnectorException e) {
652 throw new IllegalStateException(
653 "Unable to communicate to native daemon for listing tether dns");
654 }
San Mehat873f2142010-01-14 10:25:07 -0800655 }
656
657 public void enableNat(String internalInterface, String externalInterface)
658 throws IllegalStateException {
659 mContext.enforceCallingOrSelfPermission(
660 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700661 try {
662 mConnector.doCommand(
663 String.format("nat enable %s %s", internalInterface, externalInterface));
664 } catch (NativeDaemonConnectorException e) {
665 throw new IllegalStateException(
666 "Unable to communicate to native daemon for enabling NAT interface");
667 }
San Mehat873f2142010-01-14 10:25:07 -0800668 }
669
670 public void disableNat(String internalInterface, String externalInterface)
671 throws IllegalStateException {
672 mContext.enforceCallingOrSelfPermission(
673 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700674 try {
675 mConnector.doCommand(
676 String.format("nat disable %s %s", internalInterface, externalInterface));
677 } catch (NativeDaemonConnectorException e) {
678 throw new IllegalStateException(
679 "Unable to communicate to native daemon for disabling NAT interface");
680 }
San Mehat873f2142010-01-14 10:25:07 -0800681 }
San Mehat72759df2010-01-19 13:50:37 -0800682
683 public String[] listTtys() throws IllegalStateException {
684 mContext.enforceCallingOrSelfPermission(
685 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700686 try {
687 return mConnector.doListCommand("list_ttys", NetdResponseCode.TtyListResult);
688 } catch (NativeDaemonConnectorException e) {
689 throw new IllegalStateException(
690 "Unable to communicate to native daemon for listing TTYs");
691 }
San Mehat72759df2010-01-19 13:50:37 -0800692 }
693
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800694 public void attachPppd(String tty, String localAddr, String remoteAddr, String dns1Addr,
695 String dns2Addr) throws IllegalStateException {
San Mehat72759df2010-01-19 13:50:37 -0800696 try {
697 mContext.enforceCallingOrSelfPermission(
698 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800699 mConnector.doCommand(String.format("pppd attach %s %s %s %s %s", tty,
Robert Greenwalte5903732011-02-22 16:00:42 -0800700 NetworkUtils.numericToInetAddress(localAddr).getHostAddress(),
701 NetworkUtils.numericToInetAddress(remoteAddr).getHostAddress(),
702 NetworkUtils.numericToInetAddress(dns1Addr).getHostAddress(),
703 NetworkUtils.numericToInetAddress(dns2Addr).getHostAddress()));
704 } catch (IllegalArgumentException e) {
San Mehat72759df2010-01-19 13:50:37 -0800705 throw new IllegalStateException("Error resolving addr", e);
Kenny Roota80ce062010-06-01 13:23:53 -0700706 } catch (NativeDaemonConnectorException e) {
707 throw new IllegalStateException("Error communicating to native daemon to attach pppd", e);
San Mehat72759df2010-01-19 13:50:37 -0800708 }
709 }
710
711 public void detachPppd(String tty) throws IllegalStateException {
712 mContext.enforceCallingOrSelfPermission(
713 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700714 try {
715 mConnector.doCommand(String.format("pppd detach %s", tty));
716 } catch (NativeDaemonConnectorException e) {
717 throw new IllegalStateException("Error communicating to native daemon to detach pppd", e);
718 }
San Mehat72759df2010-01-19 13:50:37 -0800719 }
Robert Greenwaltce1200d2010-02-18 11:25:54 -0800720
721 public void startUsbRNDIS() throws IllegalStateException {
722 mContext.enforceCallingOrSelfPermission(
723 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700724 try {
725 mConnector.doCommand("usb startrndis");
726 } catch (NativeDaemonConnectorException e) {
727 throw new IllegalStateException(
728 "Error communicating to native daemon for starting RNDIS", e);
729 }
Robert Greenwaltce1200d2010-02-18 11:25:54 -0800730 }
731
732 public void stopUsbRNDIS() throws IllegalStateException {
733 mContext.enforceCallingOrSelfPermission(
734 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700735 try {
736 mConnector.doCommand("usb stoprndis");
737 } catch (NativeDaemonConnectorException e) {
738 throw new IllegalStateException("Error communicating to native daemon", e);
739 }
Robert Greenwaltce1200d2010-02-18 11:25:54 -0800740 }
741
742 public boolean isUsbRNDISStarted() throws IllegalStateException {
743 mContext.enforceCallingOrSelfPermission(
744 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700745 ArrayList<String> rsp;
746 try {
747 rsp = mConnector.doCommand("usb rndisstatus");
748 } catch (NativeDaemonConnectorException e) {
749 throw new IllegalStateException(
750 "Error communicating to native daemon to check RNDIS status", e);
751 }
Robert Greenwaltce1200d2010-02-18 11:25:54 -0800752
753 for (String line : rsp) {
754 String []tok = line.split(" ");
755 int code = Integer.parseInt(tok[0]);
756 if (code == NetdResponseCode.UsbRNDISStatusResult) {
Mike Lockwood51cb9d52010-03-03 15:12:00 -0500757 if (tok[3].equals("started"))
Robert Greenwaltce1200d2010-02-18 11:25:54 -0800758 return true;
759 return false;
760 } else {
761 throw new IllegalStateException(String.format("Unexpected response code %d", code));
762 }
763 }
764 throw new IllegalStateException("Got an empty response");
765 }
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800766
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700767 public void startAccessPoint(WifiConfiguration wifiConfig, String wlanIface, String softapIface)
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800768 throws IllegalStateException {
769 mContext.enforceCallingOrSelfPermission(
770 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
771 mContext.enforceCallingOrSelfPermission(
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700772 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700773 try {
774 mConnector.doCommand(String.format("softap stop " + wlanIface));
775 mConnector.doCommand(String.format("softap fwreload " + wlanIface + " AP"));
776 mConnector.doCommand(String.format("softap start " + wlanIface));
777 if (wifiConfig == null) {
778 mConnector.doCommand(String.format("softap set " + wlanIface + " " + softapIface));
779 } else {
780 /**
781 * softap set arg1 arg2 arg3 [arg4 arg5 arg6 arg7 arg8]
782 * argv1 - wlan interface
783 * argv2 - softap interface
784 * argv3 - SSID
785 * argv4 - Security
786 * argv5 - Key
787 * argv6 - Channel
788 * argv7 - Preamble
789 * argv8 - Max SCB
790 */
Irfan Sheriffec8d23a2011-02-16 17:00:33 -0800791 String str = String.format("softap set " + wlanIface + " " + softapIface +
792 " %s %s %s", convertQuotedString(wifiConfig.SSID),
793 getSecurityType(wifiConfig),
794 convertQuotedString(wifiConfig.preSharedKey));
Kenny Roota80ce062010-06-01 13:23:53 -0700795 mConnector.doCommand(str);
796 }
797 mConnector.doCommand(String.format("softap startap"));
798 } catch (NativeDaemonConnectorException e) {
799 throw new IllegalStateException("Error communicating to native daemon to start softap", e);
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -0800800 }
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800801 }
802
Irfan Sheriffa6e559e2010-05-24 14:55:42 -0700803 private String convertQuotedString(String s) {
Irfan Sheriff7baec0f2010-05-26 17:16:47 -0700804 if (s == null) {
805 return s;
806 }
807 /* Replace \ with \\, then " with \" and add quotes at end */
808 return '"' + s.replaceAll("\\\\","\\\\\\\\").replaceAll("\"","\\\\\"") + '"';
Irfan Sheriffa6e559e2010-05-24 14:55:42 -0700809 }
810
Irfan Sheriffec8d23a2011-02-16 17:00:33 -0800811 private String getSecurityType(WifiConfiguration wifiConfig) {
812 switch (wifiConfig.getAuthType()) {
813 case KeyMgmt.WPA_PSK:
814 return "wpa-psk";
815 case KeyMgmt.WPA2_PSK:
816 return "wpa2-psk";
817 default:
818 return "open";
819 }
820 }
821
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800822 public void stopAccessPoint() throws IllegalStateException {
823 mContext.enforceCallingOrSelfPermission(
824 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
825 mContext.enforceCallingOrSelfPermission(
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700826 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700827 try {
828 mConnector.doCommand("softap stopap");
829 } catch (NativeDaemonConnectorException e) {
830 throw new IllegalStateException("Error communicating to native daemon to stop soft AP",
831 e);
832 }
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800833 }
834
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700835 public void setAccessPoint(WifiConfiguration wifiConfig, String wlanIface, String softapIface)
836 throws IllegalStateException {
837 mContext.enforceCallingOrSelfPermission(
838 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
839 mContext.enforceCallingOrSelfPermission(
840 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700841 try {
842 if (wifiConfig == null) {
843 mConnector.doCommand(String.format("softap set " + wlanIface + " " + softapIface));
844 } else {
845 String str = String.format("softap set " + wlanIface + " " + softapIface
846 + " %s %s %s", convertQuotedString(wifiConfig.SSID),
Irfan Sheriffec8d23a2011-02-16 17:00:33 -0800847 getSecurityType(wifiConfig),
Kenny Roota80ce062010-06-01 13:23:53 -0700848 convertQuotedString(wifiConfig.preSharedKey));
849 mConnector.doCommand(str);
850 }
851 } catch (NativeDaemonConnectorException e) {
852 throw new IllegalStateException("Error communicating to native daemon to set soft AP",
853 e);
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700854 }
855 }
San Mehat91cac642010-03-31 14:31:36 -0700856
857 private long getInterfaceCounter(String iface, boolean rx) {
858 mContext.enforceCallingOrSelfPermission(
859 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
860 try {
Kenny Roota80ce062010-06-01 13:23:53 -0700861 String rsp;
862 try {
863 rsp = mConnector.doCommand(
864 String.format("interface read%scounter %s", (rx ? "rx" : "tx"), iface)).get(0);
865 } catch (NativeDaemonConnectorException e1) {
866 Slog.e(TAG, "Error communicating with native daemon", e1);
867 return -1;
868 }
869
870 String[] tok = rsp.split(" ");
871 if (tok.length < 2) {
872 Slog.e(TAG, String.format("Malformed response for reading %s interface",
873 (rx ? "rx" : "tx")));
874 return -1;
875 }
876
San Mehat91cac642010-03-31 14:31:36 -0700877 int code;
878 try {
879 code = Integer.parseInt(tok[0]);
880 } catch (NumberFormatException nfe) {
881 Slog.e(TAG, String.format("Error parsing code %s", tok[0]));
882 return -1;
883 }
884 if ((rx && code != NetdResponseCode.InterfaceRxCounterResult) || (
885 !rx && code != NetdResponseCode.InterfaceTxCounterResult)) {
886 Slog.e(TAG, String.format("Unexpected response code %d", code));
887 return -1;
888 }
889 return Long.parseLong(tok[1]);
890 } catch (Exception e) {
891 Slog.e(TAG, String.format(
892 "Failed to read interface %s counters", (rx ? "rx" : "tx")), e);
893 }
894 return -1;
895 }
896
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700897 @Override
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700898 public NetworkStats getNetworkStatsSummary() {
899 mContext.enforceCallingOrSelfPermission(
900 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
901
902 final String[] ifaces = listInterfaces();
Jeff Sharkey4a971222011-06-11 22:16:55 -0700903 final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), ifaces.length);
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700904
905 for (String iface : ifaces) {
906 final long rx = getInterfaceCounter(iface, true);
907 final long tx = getInterfaceCounter(iface, false);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700908 stats.addEntry(iface, UID_ALL, TAG_NONE, rx, tx);
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700909 }
910
Jeff Sharkey4a971222011-06-11 22:16:55 -0700911 return stats;
San Mehat91cac642010-03-31 14:31:36 -0700912 }
913
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700914 @Override
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700915 public NetworkStats getNetworkStatsDetail() {
916 mContext.enforceCallingOrSelfPermission(
917 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
918
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700919 if (STATS_NETFILTER.exists()) {
920 return getNetworkStatsDetailNetfilter(UID_ALL);
921 } else {
922 return getNetworkStatsDetailUidstat(UID_ALL);
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700923 }
San Mehat91cac642010-03-31 14:31:36 -0700924 }
925
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700926 @Override
927 public NetworkStats getNetworkStatsUidDetail(int uid) {
928 if (Binder.getCallingUid() != uid) {
929 mContext.enforceCallingOrSelfPermission(
930 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
931 }
932
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700933 if (STATS_NETFILTER.exists()) {
934 return getNetworkStatsDetailNetfilter(uid);
935 } else {
936 return getNetworkStatsDetailUidstat(uid);
937 }
938 }
939
940 /**
941 * Build {@link NetworkStats} with detailed UID statistics.
942 */
943 private NetworkStats getNetworkStatsDetailNetfilter(int limitUid) {
944 final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 24);
945
946 BufferedReader reader = null;
947 try {
948 reader = new BufferedReader(new FileReader(STATS_NETFILTER));
949
950 // assumes format from kernel:
951 // idx iface acct_tag_hex uid_tag_int rx_bytes tx_bytes
952
953 // skip first line, which is legend
954 String line = reader.readLine();
955 while ((line = reader.readLine()) != null) {
956 final StringTokenizer t = new StringTokenizer(line);
957
958 final String idx = t.nextToken();
959 final String iface = t.nextToken();
960
961 try {
962 // TODO: kernel currently emits tag in upper half of long;
963 // eventually switch to directly using int.
964 final int tag = (int) (Long.parseLong(t.nextToken().substring(2), 16) >> 32);
965 final int uid = Integer.parseInt(t.nextToken());
966 final long rx = Long.parseLong(t.nextToken());
967 final long tx = Long.parseLong(t.nextToken());
968
969 if (limitUid == UID_ALL || limitUid == uid) {
970 stats.addEntry(iface, uid, tag, rx, tx);
971 if (tag != TAG_NONE) {
972 // proc also counts tagged data in generic tag, so
973 // we subtract it here to avoid double-counting.
974 stats.combineEntry(iface, uid, TAG_NONE, -rx, -tx);
975 }
976 }
977 } catch (NumberFormatException e) {
978 Slog.w(TAG, "problem parsing stats for idx " + idx + ": " + e);
979 }
980 }
981 } catch (IOException e) {
982 Slog.w(TAG, "problem parsing stats: " + e);
983 } finally {
984 IoUtils.closeQuietly(reader);
985 }
986
Jeff Sharkey4a971222011-06-11 22:16:55 -0700987 return stats;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700988 }
989
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700990 /**
991 * Build {@link NetworkStats} with detailed UID statistics.
992 *
993 * @deprecated since this uses older "uid_stat" data, and doesn't provide
994 * tag-level granularity or additional variables.
995 */
996 @Deprecated
997 private NetworkStats getNetworkStatsDetailUidstat(int limitUid) {
998 final String[] knownUids;
999 if (limitUid == UID_ALL) {
1000 knownUids = STATS_UIDSTAT.list();
1001 } else {
1002 knownUids = new String[] { String.valueOf(limitUid) };
1003 }
1004
1005 final NetworkStats stats = new NetworkStats(
1006 SystemClock.elapsedRealtime(), knownUids.length);
1007 for (String uid : knownUids) {
1008 final int uidInt = Integer.parseInt(uid);
1009 final File uidPath = new File(STATS_UIDSTAT, uid);
1010 final long rx = readSingleLongFromFile(new File(uidPath, "tcp_rcv"));
1011 final long tx = readSingleLongFromFile(new File(uidPath, "tcp_snd"));
1012 stats.addEntry(IFACE_ALL, uidInt, TAG_NONE, rx, tx);
1013 }
1014
1015 return stats;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001016 }
1017
San Mehatf0db6e12010-04-07 15:22:10 -07001018 public void setInterfaceThrottle(String iface, int rxKbps, int txKbps) {
San Mehat91cac642010-03-31 14:31:36 -07001019 mContext.enforceCallingOrSelfPermission(
1020 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -07001021 try {
1022 mConnector.doCommand(String.format(
1023 "interface setthrottle %s %d %d", iface, rxKbps, txKbps));
1024 } catch (NativeDaemonConnectorException e) {
1025 Slog.e(TAG, "Error communicating with native daemon to set throttle", e);
1026 }
San Mehat91cac642010-03-31 14:31:36 -07001027 }
1028
1029 private int getInterfaceThrottle(String iface, boolean rx) {
1030 mContext.enforceCallingOrSelfPermission(
1031 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
1032 try {
Kenny Roota80ce062010-06-01 13:23:53 -07001033 String rsp;
1034 try {
1035 rsp = mConnector.doCommand(
1036 String.format("interface getthrottle %s %s", iface,
1037 (rx ? "rx" : "tx"))).get(0);
1038 } catch (NativeDaemonConnectorException e) {
1039 Slog.e(TAG, "Error communicating with native daemon to getthrottle", e);
1040 return -1;
1041 }
1042
1043 String[] tok = rsp.split(" ");
1044 if (tok.length < 2) {
1045 Slog.e(TAG, "Malformed response to getthrottle command");
1046 return -1;
1047 }
1048
San Mehat91cac642010-03-31 14:31:36 -07001049 int code;
1050 try {
1051 code = Integer.parseInt(tok[0]);
1052 } catch (NumberFormatException nfe) {
1053 Slog.e(TAG, String.format("Error parsing code %s", tok[0]));
1054 return -1;
1055 }
1056 if ((rx && code != NetdResponseCode.InterfaceRxThrottleResult) || (
1057 !rx && code != NetdResponseCode.InterfaceTxThrottleResult)) {
1058 Slog.e(TAG, String.format("Unexpected response code %d", code));
1059 return -1;
1060 }
1061 return Integer.parseInt(tok[1]);
1062 } catch (Exception e) {
1063 Slog.e(TAG, String.format(
1064 "Failed to read interface %s throttle value", (rx ? "rx" : "tx")), e);
1065 }
1066 return -1;
1067 }
1068
1069 public int getInterfaceRxThrottle(String iface) {
1070 return getInterfaceThrottle(iface, true);
1071 }
1072
1073 public int getInterfaceTxThrottle(String iface) {
1074 return getInterfaceThrottle(iface, false);
1075 }
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001076
1077 /**
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001078 * Utility method to read a single plain-text {@link Long} from the given
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001079 * {@link File}, usually from a {@code /proc/} filesystem.
1080 */
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001081 private static long readSingleLongFromFile(File file) {
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001082 try {
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001083 final byte[] buffer = IoUtils.readFileAsByteArray(file.toString());
1084 return Long.parseLong(new String(buffer).trim());
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001085 } catch (NumberFormatException e) {
1086 return -1;
1087 } catch (IOException e) {
1088 return -1;
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001089 }
1090 }
San Mehat873f2142010-01-14 10:25:07 -08001091}