blob: bb0c6714b20d26199fec25b5409395ed22ec2f71 [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
San Mehat873f2142010-01-14 10:25:07 -080019import android.content.Context;
San Mehat873f2142010-01-14 10:25:07 -080020import android.content.pm.PackageManager;
San Mehat4d02d002010-01-22 16:07:46 -080021import android.net.INetworkManagementEventObserver;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070022import android.net.InterfaceConfiguration;
Robert Greenwalted126402011-01-28 15:34:55 -080023import android.net.LinkAddress;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070024import android.net.NetworkStats;
Robert Greenwalted126402011-01-28 15:34:55 -080025import android.net.NetworkUtils;
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -070026import android.net.RouteInfo;
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -080027import android.net.wifi.WifiConfiguration;
28import android.net.wifi.WifiConfiguration.KeyMgmt;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070029import android.os.Binder;
San Mehat873f2142010-01-14 10:25:07 -080030import android.os.INetworkManagementService;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070031import android.os.SystemClock;
Marco Nelissen62dbb222010-02-18 10:56:30 -080032import android.os.SystemProperties;
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -080033import android.util.Log;
Joe Onorato8a9b2202010-02-26 18:56:32 -080034import android.util.Slog;
San Mehat873f2142010-01-14 10:25:07 -080035
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -070036import java.io.BufferedReader;
37import java.io.DataInputStream;
San Mehat873f2142010-01-14 10:25:07 -080038import java.io.File;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070039import java.io.FileInputStream;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070040import java.io.IOException;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070041import java.io.InputStreamReader;
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -070042import java.net.Inet4Address;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070043import java.net.InetAddress;
44import java.util.ArrayList;
45import java.util.NoSuchElementException;
46import java.util.StringTokenizer;
Robert Greenwalte5c3afb2010-09-22 14:32:35 -070047import java.util.concurrent.CountDownLatch;
San Mehat873f2142010-01-14 10:25:07 -080048
Jeff Sharkey9a13f362011-04-26 16:25:36 -070049import libcore.io.IoUtils;
50
San Mehat873f2142010-01-14 10:25:07 -080051/**
52 * @hide
53 */
54class NetworkManagementService extends INetworkManagementService.Stub {
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070055 private static final String TAG = "NetworkManagementService";
Dianne Hackborncef65ee2010-09-30 18:27:22 -070056 private static final boolean DBG = false;
Kenny Root305bcbf2010-09-03 07:56:38 -070057 private static final String NETD_TAG = "NetdConnector";
58
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -070059 private static final int ADD = 1;
60 private static final int REMOVE = 2;
61
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070062 /** Base path to UID-granularity network statistics. */
63 private static final File PATH_PROC_UID_STAT = new File("/proc/uid_stat");
64
San Mehat873f2142010-01-14 10:25:07 -080065 class NetdResponseCode {
66 public static final int InterfaceListResult = 110;
67 public static final int TetherInterfaceListResult = 111;
68 public static final int TetherDnsFwdTgtListResult = 112;
San Mehat72759df2010-01-19 13:50:37 -080069 public static final int TtyListResult = 113;
San Mehat873f2142010-01-14 10:25:07 -080070
71 public static final int TetherStatusResult = 210;
72 public static final int IpFwdStatusResult = 211;
San Mehated4fc8a2010-01-22 12:28:36 -080073 public static final int InterfaceGetCfgResult = 213;
Robert Greenwalte3253922010-02-18 09:23:25 -080074 public static final int SoftapStatusResult = 214;
75 public static final int UsbRNDISStatusResult = 215;
San Mehat91cac642010-03-31 14:31:36 -070076 public static final int InterfaceRxCounterResult = 216;
77 public static final int InterfaceTxCounterResult = 217;
78 public static final int InterfaceRxThrottleResult = 218;
79 public static final int InterfaceTxThrottleResult = 219;
Robert Greenwalte3253922010-02-18 09:23:25 -080080
81 public static final int InterfaceChange = 600;
San Mehat873f2142010-01-14 10:25:07 -080082 }
83
84 /**
85 * Binder context for this service
86 */
87 private Context mContext;
88
89 /**
90 * connector object for communicating with netd
91 */
92 private NativeDaemonConnector mConnector;
93
Robert Greenwalte5c3afb2010-09-22 14:32:35 -070094 private Thread mThread;
95 private final CountDownLatch mConnectedSignal = new CountDownLatch(1);
96
San Mehat4d02d002010-01-22 16:07:46 -080097 private ArrayList<INetworkManagementEventObserver> mObservers;
98
San Mehat873f2142010-01-14 10:25:07 -080099 /**
100 * Constructs a new NetworkManagementService instance
101 *
102 * @param context Binder context for this service
103 */
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700104 private NetworkManagementService(Context context) {
San Mehat873f2142010-01-14 10:25:07 -0800105 mContext = context;
San Mehat4d02d002010-01-22 16:07:46 -0800106 mObservers = new ArrayList<INetworkManagementEventObserver>();
107
Marco Nelissen62dbb222010-02-18 10:56:30 -0800108 if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
109 return;
110 }
111
San Mehat873f2142010-01-14 10:25:07 -0800112 mConnector = new NativeDaemonConnector(
Kenny Root305bcbf2010-09-03 07:56:38 -0700113 new NetdCallbackReceiver(), "netd", 10, NETD_TAG);
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700114 mThread = new Thread(mConnector, NETD_TAG);
115 }
116
117 public static NetworkManagementService create(Context context) throws InterruptedException {
118 NetworkManagementService service = new NetworkManagementService(context);
119 if (DBG) Slog.d(TAG, "Creating NetworkManagementService");
120 service.mThread.start();
121 if (DBG) Slog.d(TAG, "Awaiting socket connection");
122 service.mConnectedSignal.await();
123 if (DBG) Slog.d(TAG, "Connected");
124 return service;
San Mehat873f2142010-01-14 10:25:07 -0800125 }
126
San Mehat4d02d002010-01-22 16:07:46 -0800127 public void registerObserver(INetworkManagementEventObserver obs) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800128 Slog.d(TAG, "Registering observer");
San Mehat4d02d002010-01-22 16:07:46 -0800129 mObservers.add(obs);
130 }
131
132 public void unregisterObserver(INetworkManagementEventObserver obs) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800133 Slog.d(TAG, "Unregistering observer");
San Mehat4d02d002010-01-22 16:07:46 -0800134 mObservers.remove(mObservers.indexOf(obs));
135 }
136
137 /**
Wink Saville1a7e6712011-01-09 12:16:38 -0800138 * Notify our observers of an interface link status change
San Mehat4d02d002010-01-22 16:07:46 -0800139 */
Wink Saville1a7e6712011-01-09 12:16:38 -0800140 private void notifyInterfaceLinkStatusChanged(String iface, boolean link) {
San Mehat4d02d002010-01-22 16:07:46 -0800141 for (INetworkManagementEventObserver obs : mObservers) {
142 try {
Wink Saville1a7e6712011-01-09 12:16:38 -0800143 obs.interfaceLinkStatusChanged(iface, link);
San Mehat4d02d002010-01-22 16:07:46 -0800144 } catch (Exception ex) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800145 Slog.w(TAG, "Observer notifier failed", ex);
San Mehat4d02d002010-01-22 16:07:46 -0800146 }
147 }
148 }
149
150 /**
151 * Notify our observers of an interface addition.
152 */
153 private void notifyInterfaceAdded(String iface) {
154 for (INetworkManagementEventObserver obs : mObservers) {
155 try {
156 obs.interfaceAdded(iface);
157 } catch (Exception ex) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800158 Slog.w(TAG, "Observer notifier failed", ex);
San Mehat4d02d002010-01-22 16:07:46 -0800159 }
160 }
161 }
162
163 /**
164 * Notify our observers of an interface removal.
165 */
166 private void notifyInterfaceRemoved(String iface) {
167 for (INetworkManagementEventObserver obs : mObservers) {
168 try {
169 obs.interfaceRemoved(iface);
170 } catch (Exception ex) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800171 Slog.w(TAG, "Observer notifier failed", ex);
San Mehat4d02d002010-01-22 16:07:46 -0800172 }
173 }
174 }
175
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700176 /**
177 * Let us know the daemon is connected
178 */
179 protected void onConnected() {
180 if (DBG) Slog.d(TAG, "onConnected");
181 mConnectedSignal.countDown();
182 }
183
San Mehat4d02d002010-01-22 16:07:46 -0800184
San Mehat873f2142010-01-14 10:25:07 -0800185 //
186 // Netd Callback handling
187 //
188
189 class NetdCallbackReceiver implements INativeDaemonConnectorCallbacks {
190 public void onDaemonConnected() {
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700191 NetworkManagementService.this.onConnected();
San Mehat873f2142010-01-14 10:25:07 -0800192 new Thread() {
193 public void run() {
San Mehat873f2142010-01-14 10:25:07 -0800194 }
195 }.start();
196 }
197 public boolean onEvent(int code, String raw, String[] cooked) {
Robert Greenwalte3253922010-02-18 09:23:25 -0800198 if (code == NetdResponseCode.InterfaceChange) {
199 /*
200 * a network interface change occured
201 * Format: "NNN Iface added <name>"
202 * "NNN Iface removed <name>"
203 * "NNN Iface changed <name> <up/down>"
204 */
205 if (cooked.length < 4 || !cooked[1].equals("Iface")) {
206 throw new IllegalStateException(
207 String.format("Invalid event from daemon (%s)", raw));
208 }
209 if (cooked[2].equals("added")) {
210 notifyInterfaceAdded(cooked[3]);
211 return true;
212 } else if (cooked[2].equals("removed")) {
213 notifyInterfaceRemoved(cooked[3]);
214 return true;
215 } else if (cooked[2].equals("changed") && cooked.length == 5) {
Wink Saville1a7e6712011-01-09 12:16:38 -0800216 notifyInterfaceLinkStatusChanged(cooked[3], cooked[4].equals("up"));
Robert Greenwalte3253922010-02-18 09:23:25 -0800217 return true;
218 }
219 throw new IllegalStateException(
220 String.format("Invalid event from daemon (%s)", raw));
221 }
222 return false;
San Mehat873f2142010-01-14 10:25:07 -0800223 }
224 }
225
San Mehated4fc8a2010-01-22 12:28:36 -0800226
San Mehat873f2142010-01-14 10:25:07 -0800227 //
228 // INetworkManagementService members
229 //
230
231 public String[] listInterfaces() throws IllegalStateException {
232 mContext.enforceCallingOrSelfPermission(
233 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
234
Kenny Roota80ce062010-06-01 13:23:53 -0700235 try {
236 return mConnector.doListCommand("interface list", NetdResponseCode.InterfaceListResult);
237 } catch (NativeDaemonConnectorException e) {
238 throw new IllegalStateException(
239 "Cannot communicate with native daemon to list interfaces");
240 }
San Mehated4fc8a2010-01-22 12:28:36 -0800241 }
242
243 public InterfaceConfiguration getInterfaceConfig(String iface) throws IllegalStateException {
Kenny Roota80ce062010-06-01 13:23:53 -0700244 String rsp;
245 try {
246 rsp = mConnector.doCommand("interface getcfg " + iface).get(0);
247 } catch (NativeDaemonConnectorException e) {
248 throw new IllegalStateException(
249 "Cannot communicate with native daemon to get interface config");
250 }
Joe Onorato8a9b2202010-02-26 18:56:32 -0800251 Slog.d(TAG, String.format("rsp <%s>", rsp));
San Mehated4fc8a2010-01-22 12:28:36 -0800252
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800253 // Rsp: 213 xx:xx:xx:xx:xx:xx yyy.yyy.yyy.yyy zzz [flag1 flag2 flag3]
San Mehated4fc8a2010-01-22 12:28:36 -0800254 StringTokenizer st = new StringTokenizer(rsp);
255
Kenny Roota80ce062010-06-01 13:23:53 -0700256 InterfaceConfiguration cfg;
San Mehated4fc8a2010-01-22 12:28:36 -0800257 try {
Kenny Roota80ce062010-06-01 13:23:53 -0700258 try {
259 int code = Integer.parseInt(st.nextToken(" "));
260 if (code != NetdResponseCode.InterfaceGetCfgResult) {
261 throw new IllegalStateException(
262 String.format("Expected code %d, but got %d",
263 NetdResponseCode.InterfaceGetCfgResult, code));
264 }
265 } catch (NumberFormatException nfe) {
San Mehated4fc8a2010-01-22 12:28:36 -0800266 throw new IllegalStateException(
Kenny Roota80ce062010-06-01 13:23:53 -0700267 String.format("Invalid response from daemon (%s)", rsp));
San Mehated4fc8a2010-01-22 12:28:36 -0800268 }
Kenny Roota80ce062010-06-01 13:23:53 -0700269
270 cfg = new InterfaceConfiguration();
271 cfg.hwAddr = st.nextToken(" ");
Robert Greenwalted126402011-01-28 15:34:55 -0800272 InetAddress addr = null;
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800273 int prefixLength = 0;
Kenny Roota80ce062010-06-01 13:23:53 -0700274 try {
Robert Greenwalte5903732011-02-22 16:00:42 -0800275 addr = NetworkUtils.numericToInetAddress(st.nextToken(" "));
276 } catch (IllegalArgumentException iae) {
277 Slog.e(TAG, "Failed to parse ipaddr", iae);
Kenny Roota80ce062010-06-01 13:23:53 -0700278 }
279
280 try {
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800281 prefixLength = Integer.parseInt(st.nextToken(" "));
282 } catch (NumberFormatException nfe) {
283 Slog.e(TAG, "Failed to parse prefixLength", nfe);
Kenny Roota80ce062010-06-01 13:23:53 -0700284 }
Robert Greenwalt04808c22010-12-13 17:01:41 -0800285
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800286 cfg.addr = new LinkAddress(addr, prefixLength);
Kenny Roota80ce062010-06-01 13:23:53 -0700287 cfg.interfaceFlags = st.nextToken("]").trim() +"]";
288 } catch (NoSuchElementException nsee) {
San Mehated4fc8a2010-01-22 12:28:36 -0800289 throw new IllegalStateException(
290 String.format("Invalid response from daemon (%s)", rsp));
291 }
Joe Onorato8a9b2202010-02-26 18:56:32 -0800292 Slog.d(TAG, String.format("flags <%s>", cfg.interfaceFlags));
San Mehated4fc8a2010-01-22 12:28:36 -0800293 return cfg;
294 }
295
296 public void setInterfaceConfig(
297 String iface, InterfaceConfiguration cfg) throws IllegalStateException {
Robert Greenwalted126402011-01-28 15:34:55 -0800298 LinkAddress linkAddr = cfg.addr;
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800299 if (linkAddr == null || linkAddr.getAddress() == null) {
300 throw new IllegalStateException("Null LinkAddress given");
Robert Greenwalted126402011-01-28 15:34:55 -0800301 }
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800302 String cmd = String.format("interface setcfg %s %s %d %s", iface,
303 linkAddr.getAddress().getHostAddress(),
304 linkAddr.getNetworkPrefixLength(),
305 cfg.interfaceFlags);
Kenny Roota80ce062010-06-01 13:23:53 -0700306 try {
307 mConnector.doCommand(cmd);
308 } catch (NativeDaemonConnectorException e) {
309 throw new IllegalStateException(
Robert Greenwalt81d5ad52010-12-16 11:27:38 -0800310 "Unable to communicate with native daemon to interface setcfg - " + e);
Kenny Roota80ce062010-06-01 13:23:53 -0700311 }
San Mehat873f2142010-01-14 10:25:07 -0800312 }
313
Irfan Sherifff5600612011-06-16 10:26:28 -0700314 /* TODO: This is right now a IPv4 only function. Works for wifi which loses its
315 IPv6 addresses on interface down, but we need to do full clean up here */
316 public void clearInterfaceAddresses(String iface) throws IllegalStateException {
317 String cmd = String.format("interface clearaddrs %s", iface);
318 try {
319 mConnector.doCommand(cmd);
320 } catch (NativeDaemonConnectorException e) {
321 throw new IllegalStateException(
322 "Unable to communicate with native daemon to interface clearallips - " + e);
323 }
324 }
325
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -0700326 public void addRoute(String interfaceName, RouteInfo route) {
327 modifyRoute(interfaceName, ADD, route);
328 }
329
330 public void removeRoute(String interfaceName, RouteInfo route) {
331 modifyRoute(interfaceName, REMOVE, route);
332 }
333
334 private void modifyRoute(String interfaceName, int action, RouteInfo route) {
335 ArrayList<String> rsp;
336
337 StringBuilder cmd;
338
339 switch (action) {
340 case ADD:
341 {
342 cmd = new StringBuilder("interface route add " + interfaceName);
343 break;
344 }
345 case REMOVE:
346 {
347 cmd = new StringBuilder("interface route remove " + interfaceName);
348 break;
349 }
350 default:
351 throw new IllegalStateException("Unknown action type " + action);
352 }
353
354 // create triplet: dest-ip-addr prefixlength gateway-ip-addr
355 LinkAddress la = route.getDestination();
356 cmd.append(' ');
357 cmd.append(la.getAddress().getHostAddress());
358 cmd.append(' ');
359 cmd.append(la.getNetworkPrefixLength());
360 cmd.append(' ');
361 if (route.getGateway() == null) {
362 if (la.getAddress() instanceof Inet4Address) {
363 cmd.append("0.0.0.0");
364 } else {
365 cmd.append ("::0");
366 }
367 } else {
368 cmd.append(route.getGateway().getHostAddress());
369 }
370 try {
371 rsp = mConnector.doCommand(cmd.toString());
372 } catch (NativeDaemonConnectorException e) {
373 throw new IllegalStateException(
374 "Unable to communicate with native dameon to add routes - "
375 + e);
376 }
377
378 for (String line : rsp) {
379 Log.v(TAG, "add route response is " + line);
380 }
381 }
382
383 private ArrayList<String> readRouteList(String filename) {
384 FileInputStream fstream = null;
385 ArrayList<String> list = new ArrayList<String>();
386
387 try {
388 fstream = new FileInputStream(filename);
389 DataInputStream in = new DataInputStream(fstream);
390 BufferedReader br = new BufferedReader(new InputStreamReader(in));
391 String s;
392
393 // throw away the title line
394
395 while (((s = br.readLine()) != null) && (s.length() != 0)) {
396 list.add(s);
397 }
398 } catch (IOException ex) {
399 // return current list, possibly empty
400 } finally {
401 if (fstream != null) {
402 try {
403 fstream.close();
404 } catch (IOException ex) {}
405 }
406 }
407
408 return list;
409 }
410
411 public RouteInfo[] getRoutes(String interfaceName) {
412 ArrayList<RouteInfo> routes = new ArrayList<RouteInfo>();
413
414 // v4 routes listed as:
415 // iface dest-addr gateway-addr flags refcnt use metric netmask mtu window IRTT
416 for (String s : readRouteList("/proc/net/route")) {
417 String[] fields = s.split("\t");
418
419 if (fields.length > 7) {
420 String iface = fields[0];
421
422 if (interfaceName.equals(iface)) {
423 String dest = fields[1];
424 String gate = fields[2];
425 String flags = fields[3]; // future use?
426 String mask = fields[7];
427 try {
428 // address stored as a hex string, ex: 0014A8C0
429 InetAddress destAddr =
430 NetworkUtils.intToInetAddress((int)Long.parseLong(dest, 16));
431 int prefixLength =
432 NetworkUtils.netmaskIntToPrefixLength(
433 (int)Long.parseLong(mask, 16));
434 LinkAddress linkAddress = new LinkAddress(destAddr, prefixLength);
435
436 // address stored as a hex string, ex 0014A8C0
437 InetAddress gatewayAddr =
438 NetworkUtils.intToInetAddress((int)Long.parseLong(gate, 16));
439
440 RouteInfo route = new RouteInfo(linkAddress, gatewayAddr);
441 routes.add(route);
442 } catch (Exception e) {
443 Log.e(TAG, "Error parsing route " + s + " : " + e);
444 continue;
445 }
446 }
447 }
448 }
449
450 // v6 routes listed as:
451 // dest-addr prefixlength ?? ?? gateway-addr ?? ?? ?? ?? iface
452 for (String s : readRouteList("/proc/net/ipv6_route")) {
453 String[]fields = s.split("\\s+");
454 if (fields.length > 9) {
455 String iface = fields[9].trim();
456 if (interfaceName.equals(iface)) {
457 String dest = fields[0];
458 String prefix = fields[1];
459 String gate = fields[4];
460
461 try {
462 // prefix length stored as a hex string, ex 40
463 int prefixLength = Integer.parseInt(prefix, 16);
464
465 // address stored as a 32 char hex string
466 // ex fe800000000000000000000000000000
467 InetAddress destAddr = NetworkUtils.hexToInet6Address(dest);
468 LinkAddress linkAddress = new LinkAddress(destAddr, prefixLength);
469
470 InetAddress gateAddr = NetworkUtils.hexToInet6Address(gate);
471
472 RouteInfo route = new RouteInfo(linkAddress, gateAddr);
473 routes.add(route);
474 } catch (Exception e) {
475 Log.e(TAG, "Error parsing route " + s + " : " + e);
476 continue;
477 }
478 }
479 }
480 }
481 return (RouteInfo[]) routes.toArray(new RouteInfo[0]);
482 }
483
San Mehat873f2142010-01-14 10:25:07 -0800484 public void shutdown() {
485 if (mContext.checkCallingOrSelfPermission(
486 android.Manifest.permission.SHUTDOWN)
487 != PackageManager.PERMISSION_GRANTED) {
488 throw new SecurityException("Requires SHUTDOWN permission");
489 }
490
Joe Onorato8a9b2202010-02-26 18:56:32 -0800491 Slog.d(TAG, "Shutting down");
San Mehat873f2142010-01-14 10:25:07 -0800492 }
493
494 public boolean getIpForwardingEnabled() throws IllegalStateException{
495 mContext.enforceCallingOrSelfPermission(
496 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
497
Kenny Roota80ce062010-06-01 13:23:53 -0700498 ArrayList<String> rsp;
499 try {
500 rsp = mConnector.doCommand("ipfwd status");
501 } catch (NativeDaemonConnectorException e) {
502 throw new IllegalStateException(
503 "Unable to communicate with native daemon to ipfwd status");
504 }
San Mehat873f2142010-01-14 10:25:07 -0800505
506 for (String line : rsp) {
Kenny Roota80ce062010-06-01 13:23:53 -0700507 String[] tok = line.split(" ");
508 if (tok.length < 3) {
509 Slog.e(TAG, "Malformed response from native daemon: " + line);
510 return false;
511 }
512
San Mehat873f2142010-01-14 10:25:07 -0800513 int code = Integer.parseInt(tok[0]);
514 if (code == NetdResponseCode.IpFwdStatusResult) {
515 // 211 Forwarding <enabled/disabled>
Kenny Roota80ce062010-06-01 13:23:53 -0700516 return "enabled".equals(tok[2]);
San Mehat873f2142010-01-14 10:25:07 -0800517 } else {
518 throw new IllegalStateException(String.format("Unexpected response code %d", code));
519 }
520 }
521 throw new IllegalStateException("Got an empty response");
522 }
523
524 public void setIpForwardingEnabled(boolean enable) throws IllegalStateException {
525 mContext.enforceCallingOrSelfPermission(
526 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
527 mConnector.doCommand(String.format("ipfwd %sable", (enable ? "en" : "dis")));
528 }
529
Robert Greenwaltbfb7bfa2010-03-24 16:03:21 -0700530 public void startTethering(String[] dhcpRange)
San Mehat873f2142010-01-14 10:25:07 -0800531 throws IllegalStateException {
532 mContext.enforceCallingOrSelfPermission(
533 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Robert Greenwaltbfb7bfa2010-03-24 16:03:21 -0700534 // cmd is "tether start first_start first_stop second_start second_stop ..."
535 // an odd number of addrs will fail
536 String cmd = "tether start";
537 for (String d : dhcpRange) {
538 cmd += " " + d;
539 }
Kenny Roota80ce062010-06-01 13:23:53 -0700540
541 try {
542 mConnector.doCommand(cmd);
543 } catch (NativeDaemonConnectorException e) {
544 throw new IllegalStateException("Unable to communicate to native daemon");
545 }
San Mehat873f2142010-01-14 10:25:07 -0800546 }
547
548 public void stopTethering() throws IllegalStateException {
549 mContext.enforceCallingOrSelfPermission(
550 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700551 try {
552 mConnector.doCommand("tether stop");
553 } catch (NativeDaemonConnectorException e) {
554 throw new IllegalStateException("Unable to communicate to native daemon to stop tether");
555 }
San Mehat873f2142010-01-14 10:25:07 -0800556 }
557
558 public boolean isTetheringStarted() throws IllegalStateException {
559 mContext.enforceCallingOrSelfPermission(
560 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
561
Kenny Roota80ce062010-06-01 13:23:53 -0700562 ArrayList<String> rsp;
563 try {
564 rsp = mConnector.doCommand("tether status");
565 } catch (NativeDaemonConnectorException e) {
566 throw new IllegalStateException(
567 "Unable to communicate to native daemon to get tether status");
568 }
San Mehat873f2142010-01-14 10:25:07 -0800569
570 for (String line : rsp) {
Kenny Roota80ce062010-06-01 13:23:53 -0700571 String[] tok = line.split(" ");
572 if (tok.length < 3) {
573 throw new IllegalStateException("Malformed response for tether status: " + line);
574 }
San Mehat873f2142010-01-14 10:25:07 -0800575 int code = Integer.parseInt(tok[0]);
576 if (code == NetdResponseCode.TetherStatusResult) {
577 // XXX: Tethering services <started/stopped> <TBD>...
Kenny Roota80ce062010-06-01 13:23:53 -0700578 return "started".equals(tok[2]);
San Mehat873f2142010-01-14 10:25:07 -0800579 } else {
580 throw new IllegalStateException(String.format("Unexpected response code %d", code));
581 }
582 }
583 throw new IllegalStateException("Got an empty response");
584 }
585
586 public void tetherInterface(String iface) throws IllegalStateException {
587 mContext.enforceCallingOrSelfPermission(
588 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700589 try {
590 mConnector.doCommand("tether interface add " + iface);
591 } catch (NativeDaemonConnectorException e) {
592 throw new IllegalStateException(
593 "Unable to communicate to native daemon for adding tether interface");
594 }
San Mehat873f2142010-01-14 10:25:07 -0800595 }
596
597 public void untetherInterface(String iface) {
598 mContext.enforceCallingOrSelfPermission(
599 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700600 try {
601 mConnector.doCommand("tether interface remove " + iface);
602 } catch (NativeDaemonConnectorException e) {
603 throw new IllegalStateException(
604 "Unable to communicate to native daemon for removing tether interface");
605 }
San Mehat873f2142010-01-14 10:25:07 -0800606 }
607
608 public String[] listTetheredInterfaces() throws IllegalStateException {
609 mContext.enforceCallingOrSelfPermission(
610 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700611 try {
612 return mConnector.doListCommand(
613 "tether interface list", NetdResponseCode.TetherInterfaceListResult);
614 } catch (NativeDaemonConnectorException e) {
615 throw new IllegalStateException(
616 "Unable to communicate to native daemon for listing tether interfaces");
617 }
San Mehat873f2142010-01-14 10:25:07 -0800618 }
619
620 public void setDnsForwarders(String[] dns) throws IllegalStateException {
621 mContext.enforceCallingOrSelfPermission(
622 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
623 try {
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800624 String cmd = "tether dns set";
San Mehat873f2142010-01-14 10:25:07 -0800625 for (String s : dns) {
Robert Greenwalte5903732011-02-22 16:00:42 -0800626 cmd += " " + NetworkUtils.numericToInetAddress(s).getHostAddress();
San Mehat873f2142010-01-14 10:25:07 -0800627 }
Kenny Roota80ce062010-06-01 13:23:53 -0700628 try {
629 mConnector.doCommand(cmd);
630 } catch (NativeDaemonConnectorException e) {
631 throw new IllegalStateException(
632 "Unable to communicate to native daemon for setting tether dns");
633 }
Robert Greenwalte5903732011-02-22 16:00:42 -0800634 } catch (IllegalArgumentException e) {
San Mehat873f2142010-01-14 10:25:07 -0800635 throw new IllegalStateException("Error resolving dns name", e);
636 }
637 }
638
639 public String[] getDnsForwarders() throws IllegalStateException {
640 mContext.enforceCallingOrSelfPermission(
641 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700642 try {
643 return mConnector.doListCommand(
644 "tether dns list", NetdResponseCode.TetherDnsFwdTgtListResult);
645 } catch (NativeDaemonConnectorException e) {
646 throw new IllegalStateException(
647 "Unable to communicate to native daemon for listing tether dns");
648 }
San Mehat873f2142010-01-14 10:25:07 -0800649 }
650
651 public void enableNat(String internalInterface, String externalInterface)
652 throws IllegalStateException {
653 mContext.enforceCallingOrSelfPermission(
654 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700655 try {
656 mConnector.doCommand(
657 String.format("nat enable %s %s", internalInterface, externalInterface));
658 } catch (NativeDaemonConnectorException e) {
659 throw new IllegalStateException(
660 "Unable to communicate to native daemon for enabling NAT interface");
661 }
San Mehat873f2142010-01-14 10:25:07 -0800662 }
663
664 public void disableNat(String internalInterface, String externalInterface)
665 throws IllegalStateException {
666 mContext.enforceCallingOrSelfPermission(
667 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700668 try {
669 mConnector.doCommand(
670 String.format("nat disable %s %s", internalInterface, externalInterface));
671 } catch (NativeDaemonConnectorException e) {
672 throw new IllegalStateException(
673 "Unable to communicate to native daemon for disabling NAT interface");
674 }
San Mehat873f2142010-01-14 10:25:07 -0800675 }
San Mehat72759df2010-01-19 13:50:37 -0800676
677 public String[] listTtys() throws IllegalStateException {
678 mContext.enforceCallingOrSelfPermission(
679 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700680 try {
681 return mConnector.doListCommand("list_ttys", NetdResponseCode.TtyListResult);
682 } catch (NativeDaemonConnectorException e) {
683 throw new IllegalStateException(
684 "Unable to communicate to native daemon for listing TTYs");
685 }
San Mehat72759df2010-01-19 13:50:37 -0800686 }
687
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800688 public void attachPppd(String tty, String localAddr, String remoteAddr, String dns1Addr,
689 String dns2Addr) throws IllegalStateException {
San Mehat72759df2010-01-19 13:50:37 -0800690 try {
691 mContext.enforceCallingOrSelfPermission(
692 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800693 mConnector.doCommand(String.format("pppd attach %s %s %s %s %s", tty,
Robert Greenwalte5903732011-02-22 16:00:42 -0800694 NetworkUtils.numericToInetAddress(localAddr).getHostAddress(),
695 NetworkUtils.numericToInetAddress(remoteAddr).getHostAddress(),
696 NetworkUtils.numericToInetAddress(dns1Addr).getHostAddress(),
697 NetworkUtils.numericToInetAddress(dns2Addr).getHostAddress()));
698 } catch (IllegalArgumentException e) {
San Mehat72759df2010-01-19 13:50:37 -0800699 throw new IllegalStateException("Error resolving addr", e);
Kenny Roota80ce062010-06-01 13:23:53 -0700700 } catch (NativeDaemonConnectorException e) {
701 throw new IllegalStateException("Error communicating to native daemon to attach pppd", e);
San Mehat72759df2010-01-19 13:50:37 -0800702 }
703 }
704
705 public void detachPppd(String tty) throws IllegalStateException {
706 mContext.enforceCallingOrSelfPermission(
707 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700708 try {
709 mConnector.doCommand(String.format("pppd detach %s", tty));
710 } catch (NativeDaemonConnectorException e) {
711 throw new IllegalStateException("Error communicating to native daemon to detach pppd", e);
712 }
San Mehat72759df2010-01-19 13:50:37 -0800713 }
Robert Greenwaltce1200d2010-02-18 11:25:54 -0800714
715 public void startUsbRNDIS() throws IllegalStateException {
716 mContext.enforceCallingOrSelfPermission(
717 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700718 try {
719 mConnector.doCommand("usb startrndis");
720 } catch (NativeDaemonConnectorException e) {
721 throw new IllegalStateException(
722 "Error communicating to native daemon for starting RNDIS", e);
723 }
Robert Greenwaltce1200d2010-02-18 11:25:54 -0800724 }
725
726 public void stopUsbRNDIS() throws IllegalStateException {
727 mContext.enforceCallingOrSelfPermission(
728 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700729 try {
730 mConnector.doCommand("usb stoprndis");
731 } catch (NativeDaemonConnectorException e) {
732 throw new IllegalStateException("Error communicating to native daemon", e);
733 }
Robert Greenwaltce1200d2010-02-18 11:25:54 -0800734 }
735
736 public boolean isUsbRNDISStarted() throws IllegalStateException {
737 mContext.enforceCallingOrSelfPermission(
738 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700739 ArrayList<String> rsp;
740 try {
741 rsp = mConnector.doCommand("usb rndisstatus");
742 } catch (NativeDaemonConnectorException e) {
743 throw new IllegalStateException(
744 "Error communicating to native daemon to check RNDIS status", e);
745 }
Robert Greenwaltce1200d2010-02-18 11:25:54 -0800746
747 for (String line : rsp) {
748 String []tok = line.split(" ");
749 int code = Integer.parseInt(tok[0]);
750 if (code == NetdResponseCode.UsbRNDISStatusResult) {
Mike Lockwood51cb9d52010-03-03 15:12:00 -0500751 if (tok[3].equals("started"))
Robert Greenwaltce1200d2010-02-18 11:25:54 -0800752 return true;
753 return false;
754 } else {
755 throw new IllegalStateException(String.format("Unexpected response code %d", code));
756 }
757 }
758 throw new IllegalStateException("Got an empty response");
759 }
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800760
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700761 public void startAccessPoint(WifiConfiguration wifiConfig, String wlanIface, String softapIface)
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800762 throws IllegalStateException {
763 mContext.enforceCallingOrSelfPermission(
764 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
765 mContext.enforceCallingOrSelfPermission(
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700766 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700767 try {
768 mConnector.doCommand(String.format("softap stop " + wlanIface));
769 mConnector.doCommand(String.format("softap fwreload " + wlanIface + " AP"));
770 mConnector.doCommand(String.format("softap start " + wlanIface));
771 if (wifiConfig == null) {
772 mConnector.doCommand(String.format("softap set " + wlanIface + " " + softapIface));
773 } else {
774 /**
775 * softap set arg1 arg2 arg3 [arg4 arg5 arg6 arg7 arg8]
776 * argv1 - wlan interface
777 * argv2 - softap interface
778 * argv3 - SSID
779 * argv4 - Security
780 * argv5 - Key
781 * argv6 - Channel
782 * argv7 - Preamble
783 * argv8 - Max SCB
784 */
Irfan Sheriffec8d23a2011-02-16 17:00:33 -0800785 String str = String.format("softap set " + wlanIface + " " + softapIface +
786 " %s %s %s", convertQuotedString(wifiConfig.SSID),
787 getSecurityType(wifiConfig),
788 convertQuotedString(wifiConfig.preSharedKey));
Kenny Roota80ce062010-06-01 13:23:53 -0700789 mConnector.doCommand(str);
790 }
791 mConnector.doCommand(String.format("softap startap"));
792 } catch (NativeDaemonConnectorException e) {
793 throw new IllegalStateException("Error communicating to native daemon to start softap", e);
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -0800794 }
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800795 }
796
Irfan Sheriffa6e559e2010-05-24 14:55:42 -0700797 private String convertQuotedString(String s) {
Irfan Sheriff7baec0f2010-05-26 17:16:47 -0700798 if (s == null) {
799 return s;
800 }
801 /* Replace \ with \\, then " with \" and add quotes at end */
802 return '"' + s.replaceAll("\\\\","\\\\\\\\").replaceAll("\"","\\\\\"") + '"';
Irfan Sheriffa6e559e2010-05-24 14:55:42 -0700803 }
804
Irfan Sheriffec8d23a2011-02-16 17:00:33 -0800805 private String getSecurityType(WifiConfiguration wifiConfig) {
806 switch (wifiConfig.getAuthType()) {
807 case KeyMgmt.WPA_PSK:
808 return "wpa-psk";
809 case KeyMgmt.WPA2_PSK:
810 return "wpa2-psk";
811 default:
812 return "open";
813 }
814 }
815
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800816 public void stopAccessPoint() throws IllegalStateException {
817 mContext.enforceCallingOrSelfPermission(
818 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
819 mContext.enforceCallingOrSelfPermission(
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700820 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700821 try {
822 mConnector.doCommand("softap stopap");
823 } catch (NativeDaemonConnectorException e) {
824 throw new IllegalStateException("Error communicating to native daemon to stop soft AP",
825 e);
826 }
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800827 }
828
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700829 public void setAccessPoint(WifiConfiguration wifiConfig, String wlanIface, String softapIface)
830 throws IllegalStateException {
831 mContext.enforceCallingOrSelfPermission(
832 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
833 mContext.enforceCallingOrSelfPermission(
834 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700835 try {
836 if (wifiConfig == null) {
837 mConnector.doCommand(String.format("softap set " + wlanIface + " " + softapIface));
838 } else {
839 String str = String.format("softap set " + wlanIface + " " + softapIface
840 + " %s %s %s", convertQuotedString(wifiConfig.SSID),
Irfan Sheriffec8d23a2011-02-16 17:00:33 -0800841 getSecurityType(wifiConfig),
Kenny Roota80ce062010-06-01 13:23:53 -0700842 convertQuotedString(wifiConfig.preSharedKey));
843 mConnector.doCommand(str);
844 }
845 } catch (NativeDaemonConnectorException e) {
846 throw new IllegalStateException("Error communicating to native daemon to set soft AP",
847 e);
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700848 }
849 }
San Mehat91cac642010-03-31 14:31:36 -0700850
851 private long getInterfaceCounter(String iface, boolean rx) {
852 mContext.enforceCallingOrSelfPermission(
853 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
854 try {
Kenny Roota80ce062010-06-01 13:23:53 -0700855 String rsp;
856 try {
857 rsp = mConnector.doCommand(
858 String.format("interface read%scounter %s", (rx ? "rx" : "tx"), iface)).get(0);
859 } catch (NativeDaemonConnectorException e1) {
860 Slog.e(TAG, "Error communicating with native daemon", e1);
861 return -1;
862 }
863
864 String[] tok = rsp.split(" ");
865 if (tok.length < 2) {
866 Slog.e(TAG, String.format("Malformed response for reading %s interface",
867 (rx ? "rx" : "tx")));
868 return -1;
869 }
870
San Mehat91cac642010-03-31 14:31:36 -0700871 int code;
872 try {
873 code = Integer.parseInt(tok[0]);
874 } catch (NumberFormatException nfe) {
875 Slog.e(TAG, String.format("Error parsing code %s", tok[0]));
876 return -1;
877 }
878 if ((rx && code != NetdResponseCode.InterfaceRxCounterResult) || (
879 !rx && code != NetdResponseCode.InterfaceTxCounterResult)) {
880 Slog.e(TAG, String.format("Unexpected response code %d", code));
881 return -1;
882 }
883 return Long.parseLong(tok[1]);
884 } catch (Exception e) {
885 Slog.e(TAG, String.format(
886 "Failed to read interface %s counters", (rx ? "rx" : "tx")), e);
887 }
888 return -1;
889 }
890
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700891 @Override
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700892 public NetworkStats getNetworkStatsSummary() {
893 mContext.enforceCallingOrSelfPermission(
894 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
895
896 final String[] ifaces = listInterfaces();
Jeff Sharkey4a971222011-06-11 22:16:55 -0700897 final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), ifaces.length);
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700898
899 for (String iface : ifaces) {
900 final long rx = getInterfaceCounter(iface, true);
901 final long tx = getInterfaceCounter(iface, false);
902 stats.addEntry(iface, NetworkStats.UID_ALL, rx, tx);
903 }
904
Jeff Sharkey4a971222011-06-11 22:16:55 -0700905 return stats;
San Mehat91cac642010-03-31 14:31:36 -0700906 }
907
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700908 @Override
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700909 public NetworkStats getNetworkStatsDetail() {
910 mContext.enforceCallingOrSelfPermission(
911 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
912
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700913 final String[] knownUids = PATH_PROC_UID_STAT.list();
Jeff Sharkey4a971222011-06-11 22:16:55 -0700914 final NetworkStats stats = new NetworkStats(
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700915 SystemClock.elapsedRealtime(), knownUids.length);
916
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700917 for (String uid : knownUids) {
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700918 final int uidInt = Integer.parseInt(uid);
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700919 collectNetworkStatsDetail(stats, uidInt);
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700920 }
921
Jeff Sharkey4a971222011-06-11 22:16:55 -0700922 return stats;
San Mehat91cac642010-03-31 14:31:36 -0700923 }
924
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700925 @Override
926 public NetworkStats getNetworkStatsUidDetail(int uid) {
927 if (Binder.getCallingUid() != uid) {
928 mContext.enforceCallingOrSelfPermission(
929 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
930 }
931
Jeff Sharkey4a971222011-06-11 22:16:55 -0700932 final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1);
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700933 collectNetworkStatsDetail(stats, uid);
Jeff Sharkey4a971222011-06-11 22:16:55 -0700934 return stats;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700935 }
936
Jeff Sharkey4a971222011-06-11 22:16:55 -0700937 private void collectNetworkStatsDetail(NetworkStats stats, int uid) {
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700938 // TODO: kernel module will provide interface-level stats in future
939 // TODO: migrate these stats to come across netd in bulk, instead of all
940 // these individual file reads.
941 final File uidPath = new File(PATH_PROC_UID_STAT, Integer.toString(uid));
942 final long rx = readSingleLongFromFile(new File(uidPath, "tcp_rcv"));
943 final long tx = readSingleLongFromFile(new File(uidPath, "tcp_snd"));
944 stats.addEntry(NetworkStats.IFACE_ALL, uid, rx, tx);
945 }
946
San Mehatf0db6e12010-04-07 15:22:10 -0700947 public void setInterfaceThrottle(String iface, int rxKbps, int txKbps) {
San Mehat91cac642010-03-31 14:31:36 -0700948 mContext.enforceCallingOrSelfPermission(
949 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700950 try {
951 mConnector.doCommand(String.format(
952 "interface setthrottle %s %d %d", iface, rxKbps, txKbps));
953 } catch (NativeDaemonConnectorException e) {
954 Slog.e(TAG, "Error communicating with native daemon to set throttle", e);
955 }
San Mehat91cac642010-03-31 14:31:36 -0700956 }
957
958 private int getInterfaceThrottle(String iface, boolean rx) {
959 mContext.enforceCallingOrSelfPermission(
960 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
961 try {
Kenny Roota80ce062010-06-01 13:23:53 -0700962 String rsp;
963 try {
964 rsp = mConnector.doCommand(
965 String.format("interface getthrottle %s %s", iface,
966 (rx ? "rx" : "tx"))).get(0);
967 } catch (NativeDaemonConnectorException e) {
968 Slog.e(TAG, "Error communicating with native daemon to getthrottle", e);
969 return -1;
970 }
971
972 String[] tok = rsp.split(" ");
973 if (tok.length < 2) {
974 Slog.e(TAG, "Malformed response to getthrottle command");
975 return -1;
976 }
977
San Mehat91cac642010-03-31 14:31:36 -0700978 int code;
979 try {
980 code = Integer.parseInt(tok[0]);
981 } catch (NumberFormatException nfe) {
982 Slog.e(TAG, String.format("Error parsing code %s", tok[0]));
983 return -1;
984 }
985 if ((rx && code != NetdResponseCode.InterfaceRxThrottleResult) || (
986 !rx && code != NetdResponseCode.InterfaceTxThrottleResult)) {
987 Slog.e(TAG, String.format("Unexpected response code %d", code));
988 return -1;
989 }
990 return Integer.parseInt(tok[1]);
991 } catch (Exception e) {
992 Slog.e(TAG, String.format(
993 "Failed to read interface %s throttle value", (rx ? "rx" : "tx")), e);
994 }
995 return -1;
996 }
997
998 public int getInterfaceRxThrottle(String iface) {
999 return getInterfaceThrottle(iface, true);
1000 }
1001
1002 public int getInterfaceTxThrottle(String iface) {
1003 return getInterfaceThrottle(iface, false);
1004 }
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001005
1006 /**
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001007 * Utility method to read a single plain-text {@link Long} from the given
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001008 * {@link File}, usually from a {@code /proc/} filesystem.
1009 */
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001010 private static long readSingleLongFromFile(File file) {
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001011 try {
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001012 final byte[] buffer = IoUtils.readFileAsByteArray(file.toString());
1013 return Long.parseLong(new String(buffer).trim());
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001014 } catch (NumberFormatException e) {
1015 return -1;
1016 } catch (IOException e) {
1017 return -1;
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001018 }
1019 }
San Mehat873f2142010-01-14 10:25:07 -08001020}