blob: b31d128037f85100e9141c2d404a82363299f6f2 [file] [log] [blame]
San Mehat873f2142010-01-14 10:25:07 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -070019import static android.net.NetworkStats.IFACE_ALL;
20import static android.net.NetworkStats.TAG_NONE;
21import static android.net.NetworkStats.UID_ALL;
Jeff Sharkey0a9ee122011-06-22 16:32:41 -070022import static android.Manifest.permission.MANAGE_NETWORK_POLICY;
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -070023
San Mehat873f2142010-01-14 10:25:07 -080024import android.content.Context;
San Mehat873f2142010-01-14 10:25:07 -080025import android.content.pm.PackageManager;
San Mehat4d02d002010-01-22 16:07:46 -080026import android.net.INetworkManagementEventObserver;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070027import android.net.InterfaceConfiguration;
Robert Greenwalted126402011-01-28 15:34:55 -080028import android.net.LinkAddress;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070029import android.net.NetworkStats;
Robert Greenwalted126402011-01-28 15:34:55 -080030import android.net.NetworkUtils;
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -070031import android.net.RouteInfo;
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -080032import android.net.wifi.WifiConfiguration;
33import android.net.wifi.WifiConfiguration.KeyMgmt;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070034import android.os.Binder;
San Mehat873f2142010-01-14 10:25:07 -080035import android.os.INetworkManagementService;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070036import android.os.SystemClock;
Marco Nelissen62dbb222010-02-18 10:56:30 -080037import android.os.SystemProperties;
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -080038import android.util.Log;
Joe Onorato8a9b2202010-02-26 18:56:32 -080039import android.util.Slog;
San Mehat873f2142010-01-14 10:25:07 -080040
Jeff Sharkey4414cea2011-06-24 17:05:24 -070041import com.google.android.collect.Lists;
42import com.google.android.collect.Maps;
43
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -070044import java.io.BufferedReader;
45import java.io.DataInputStream;
San Mehat873f2142010-01-14 10:25:07 -080046import java.io.File;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070047import java.io.FileInputStream;
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -070048import java.io.FileReader;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070049import java.io.IOException;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070050import java.io.InputStreamReader;
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -070051import java.net.Inet4Address;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070052import java.net.InetAddress;
53import java.util.ArrayList;
Jeff Sharkey4414cea2011-06-24 17:05:24 -070054import java.util.HashMap;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070055import java.util.NoSuchElementException;
56import java.util.StringTokenizer;
Robert Greenwalte5c3afb2010-09-22 14:32:35 -070057import java.util.concurrent.CountDownLatch;
San Mehat873f2142010-01-14 10:25:07 -080058
Jeff Sharkey9a13f362011-04-26 16:25:36 -070059import libcore.io.IoUtils;
60
San Mehat873f2142010-01-14 10:25:07 -080061/**
62 * @hide
63 */
64class NetworkManagementService extends INetworkManagementService.Stub {
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070065 private static final String TAG = "NetworkManagementService";
Dianne Hackborncef65ee2010-09-30 18:27:22 -070066 private static final boolean DBG = false;
Kenny Root305bcbf2010-09-03 07:56:38 -070067 private static final String NETD_TAG = "NetdConnector";
68
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -070069 private static final int ADD = 1;
70 private static final int REMOVE = 2;
71
Jeff Sharkey4414cea2011-06-24 17:05:24 -070072 /** Path to {@code /proc/uid_stat}. */
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -070073 @Deprecated
Jeff Sharkey4414cea2011-06-24 17:05:24 -070074 private final File mProcStatsUidstat;
75 /** Path to {@code /proc/net/xt_qtaguid/stats}. */
76 private final File mProcStatsNetfilter;
77
78 /** {@link #mProcStatsNetfilter} headers. */
79 private static final String KEY_IFACE = "iface";
80 private static final String KEY_TAG_HEX = "acct_tag_hex";
81 private static final String KEY_UID = "uid_tag_int";
82 private static final String KEY_RX = "rx_bytes";
83 private static final String KEY_TX = "tx_bytes";
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070084
San Mehat873f2142010-01-14 10:25:07 -080085 class NetdResponseCode {
86 public static final int InterfaceListResult = 110;
87 public static final int TetherInterfaceListResult = 111;
88 public static final int TetherDnsFwdTgtListResult = 112;
San Mehat72759df2010-01-19 13:50:37 -080089 public static final int TtyListResult = 113;
San Mehat873f2142010-01-14 10:25:07 -080090
91 public static final int TetherStatusResult = 210;
92 public static final int IpFwdStatusResult = 211;
San Mehated4fc8a2010-01-22 12:28:36 -080093 public static final int InterfaceGetCfgResult = 213;
Robert Greenwalte3253922010-02-18 09:23:25 -080094 public static final int SoftapStatusResult = 214;
San Mehat91cac642010-03-31 14:31:36 -070095 public static final int InterfaceRxCounterResult = 216;
96 public static final int InterfaceTxCounterResult = 217;
97 public static final int InterfaceRxThrottleResult = 218;
98 public static final int InterfaceTxThrottleResult = 219;
Robert Greenwalte3253922010-02-18 09:23:25 -080099
100 public static final int InterfaceChange = 600;
San Mehat873f2142010-01-14 10:25:07 -0800101 }
102
103 /**
104 * Binder context for this service
105 */
106 private Context mContext;
107
108 /**
109 * connector object for communicating with netd
110 */
111 private NativeDaemonConnector mConnector;
112
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700113 private Thread mThread;
114 private final CountDownLatch mConnectedSignal = new CountDownLatch(1);
115
San Mehat4d02d002010-01-22 16:07:46 -0800116 private ArrayList<INetworkManagementEventObserver> mObservers;
117
San Mehat873f2142010-01-14 10:25:07 -0800118 /**
119 * Constructs a new NetworkManagementService instance
120 *
121 * @param context Binder context for this service
122 */
Jeff Sharkey4414cea2011-06-24 17:05:24 -0700123 private NetworkManagementService(Context context, File procRoot) {
San Mehat873f2142010-01-14 10:25:07 -0800124 mContext = context;
San Mehat4d02d002010-01-22 16:07:46 -0800125 mObservers = new ArrayList<INetworkManagementEventObserver>();
126
Jeff Sharkey4414cea2011-06-24 17:05:24 -0700127 mProcStatsUidstat = new File(procRoot, "uid_stat");
128 mProcStatsNetfilter = new File(procRoot, "net/xt_qtaguid/stats");
129
Marco Nelissen62dbb222010-02-18 10:56:30 -0800130 if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
131 return;
132 }
133
San Mehat873f2142010-01-14 10:25:07 -0800134 mConnector = new NativeDaemonConnector(
Kenny Root305bcbf2010-09-03 07:56:38 -0700135 new NetdCallbackReceiver(), "netd", 10, NETD_TAG);
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700136 mThread = new Thread(mConnector, NETD_TAG);
137 }
138
139 public static NetworkManagementService create(Context context) throws InterruptedException {
Jeff Sharkey4414cea2011-06-24 17:05:24 -0700140 NetworkManagementService service = new NetworkManagementService(
141 context, new File("/proc/"));
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700142 if (DBG) Slog.d(TAG, "Creating NetworkManagementService");
143 service.mThread.start();
144 if (DBG) Slog.d(TAG, "Awaiting socket connection");
145 service.mConnectedSignal.await();
146 if (DBG) Slog.d(TAG, "Connected");
147 return service;
San Mehat873f2142010-01-14 10:25:07 -0800148 }
149
Jeff Sharkey4414cea2011-06-24 17:05:24 -0700150 // @VisibleForTesting
151 public static NetworkManagementService createForTest(Context context, File procRoot) {
152 // TODO: eventually connect with mock netd
153 return new NetworkManagementService(context, procRoot);
154 }
155
San Mehat4d02d002010-01-22 16:07:46 -0800156 public void registerObserver(INetworkManagementEventObserver obs) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800157 Slog.d(TAG, "Registering observer");
San Mehat4d02d002010-01-22 16:07:46 -0800158 mObservers.add(obs);
159 }
160
161 public void unregisterObserver(INetworkManagementEventObserver obs) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800162 Slog.d(TAG, "Unregistering observer");
San Mehat4d02d002010-01-22 16:07:46 -0800163 mObservers.remove(mObservers.indexOf(obs));
164 }
165
166 /**
Mike J. Chen6143f5f2011-06-23 15:17:51 -0700167 * Notify our observers of an interface status change
San Mehat4d02d002010-01-22 16:07:46 -0800168 */
Mike J. Chen6143f5f2011-06-23 15:17:51 -0700169 private void notifyInterfaceStatusChanged(String iface, boolean up) {
San Mehat4d02d002010-01-22 16:07:46 -0800170 for (INetworkManagementEventObserver obs : mObservers) {
171 try {
Mike J. Chen6143f5f2011-06-23 15:17:51 -0700172 obs.interfaceStatusChanged(iface, up);
173 } catch (Exception ex) {
174 Slog.w(TAG, "Observer notifier failed", ex);
175 }
176 }
177 }
178
179 /**
Mike J. Chenf59c7d02011-06-23 15:33:15 -0700180 * Notify our observers of an interface link state change
Mike J. Chen6143f5f2011-06-23 15:17:51 -0700181 * (typically, an Ethernet cable has been plugged-in or unplugged).
182 */
183 private void notifyInterfaceLinkStateChanged(String iface, boolean up) {
184 for (INetworkManagementEventObserver obs : mObservers) {
185 try {
186 obs.interfaceLinkStateChanged(iface, up);
San Mehat4d02d002010-01-22 16:07:46 -0800187 } catch (Exception ex) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800188 Slog.w(TAG, "Observer notifier failed", ex);
San Mehat4d02d002010-01-22 16:07:46 -0800189 }
190 }
191 }
192
193 /**
194 * Notify our observers of an interface addition.
195 */
196 private void notifyInterfaceAdded(String iface) {
197 for (INetworkManagementEventObserver obs : mObservers) {
198 try {
199 obs.interfaceAdded(iface);
200 } catch (Exception ex) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800201 Slog.w(TAG, "Observer notifier failed", ex);
San Mehat4d02d002010-01-22 16:07:46 -0800202 }
203 }
204 }
205
206 /**
207 * Notify our observers of an interface removal.
208 */
209 private void notifyInterfaceRemoved(String iface) {
210 for (INetworkManagementEventObserver obs : mObservers) {
211 try {
212 obs.interfaceRemoved(iface);
213 } catch (Exception ex) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800214 Slog.w(TAG, "Observer notifier failed", ex);
San Mehat4d02d002010-01-22 16:07:46 -0800215 }
216 }
217 }
218
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700219 /**
220 * Let us know the daemon is connected
221 */
222 protected void onConnected() {
223 if (DBG) Slog.d(TAG, "onConnected");
224 mConnectedSignal.countDown();
225 }
226
San Mehat4d02d002010-01-22 16:07:46 -0800227
San Mehat873f2142010-01-14 10:25:07 -0800228 //
229 // Netd Callback handling
230 //
231
232 class NetdCallbackReceiver implements INativeDaemonConnectorCallbacks {
233 public void onDaemonConnected() {
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700234 NetworkManagementService.this.onConnected();
San Mehat873f2142010-01-14 10:25:07 -0800235 new Thread() {
236 public void run() {
San Mehat873f2142010-01-14 10:25:07 -0800237 }
238 }.start();
239 }
240 public boolean onEvent(int code, String raw, String[] cooked) {
Robert Greenwalte3253922010-02-18 09:23:25 -0800241 if (code == NetdResponseCode.InterfaceChange) {
242 /*
243 * a network interface change occured
244 * Format: "NNN Iface added <name>"
245 * "NNN Iface removed <name>"
246 * "NNN Iface changed <name> <up/down>"
Mike J. Chen6143f5f2011-06-23 15:17:51 -0700247 * "NNN Iface linkstatus <name> <up/down>"
Robert Greenwalte3253922010-02-18 09:23:25 -0800248 */
249 if (cooked.length < 4 || !cooked[1].equals("Iface")) {
250 throw new IllegalStateException(
251 String.format("Invalid event from daemon (%s)", raw));
252 }
253 if (cooked[2].equals("added")) {
254 notifyInterfaceAdded(cooked[3]);
255 return true;
256 } else if (cooked[2].equals("removed")) {
257 notifyInterfaceRemoved(cooked[3]);
258 return true;
259 } else if (cooked[2].equals("changed") && cooked.length == 5) {
Mike J. Chen6143f5f2011-06-23 15:17:51 -0700260 notifyInterfaceStatusChanged(cooked[3], cooked[4].equals("up"));
261 return true;
Mike J. Chenf59c7d02011-06-23 15:33:15 -0700262 } else if (cooked[2].equals("linkstate") && cooked.length == 5) {
Mike J. Chen6143f5f2011-06-23 15:17:51 -0700263 notifyInterfaceLinkStateChanged(cooked[3], cooked[4].equals("up"));
Robert Greenwalte3253922010-02-18 09:23:25 -0800264 return true;
265 }
266 throw new IllegalStateException(
267 String.format("Invalid event from daemon (%s)", raw));
268 }
269 return false;
San Mehat873f2142010-01-14 10:25:07 -0800270 }
271 }
272
San Mehated4fc8a2010-01-22 12:28:36 -0800273
San Mehat873f2142010-01-14 10:25:07 -0800274 //
275 // INetworkManagementService members
276 //
277
278 public String[] listInterfaces() throws IllegalStateException {
279 mContext.enforceCallingOrSelfPermission(
280 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
281
Kenny Roota80ce062010-06-01 13:23:53 -0700282 try {
283 return mConnector.doListCommand("interface list", NetdResponseCode.InterfaceListResult);
284 } catch (NativeDaemonConnectorException e) {
285 throw new IllegalStateException(
286 "Cannot communicate with native daemon to list interfaces");
287 }
San Mehated4fc8a2010-01-22 12:28:36 -0800288 }
289
290 public InterfaceConfiguration getInterfaceConfig(String iface) throws IllegalStateException {
Kenny Roota80ce062010-06-01 13:23:53 -0700291 String rsp;
292 try {
293 rsp = mConnector.doCommand("interface getcfg " + iface).get(0);
294 } catch (NativeDaemonConnectorException e) {
295 throw new IllegalStateException(
296 "Cannot communicate with native daemon to get interface config");
297 }
Joe Onorato8a9b2202010-02-26 18:56:32 -0800298 Slog.d(TAG, String.format("rsp <%s>", rsp));
San Mehated4fc8a2010-01-22 12:28:36 -0800299
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800300 // Rsp: 213 xx:xx:xx:xx:xx:xx yyy.yyy.yyy.yyy zzz [flag1 flag2 flag3]
San Mehated4fc8a2010-01-22 12:28:36 -0800301 StringTokenizer st = new StringTokenizer(rsp);
302
Kenny Roota80ce062010-06-01 13:23:53 -0700303 InterfaceConfiguration cfg;
San Mehated4fc8a2010-01-22 12:28:36 -0800304 try {
Kenny Roota80ce062010-06-01 13:23:53 -0700305 try {
306 int code = Integer.parseInt(st.nextToken(" "));
307 if (code != NetdResponseCode.InterfaceGetCfgResult) {
308 throw new IllegalStateException(
309 String.format("Expected code %d, but got %d",
310 NetdResponseCode.InterfaceGetCfgResult, code));
311 }
312 } catch (NumberFormatException nfe) {
San Mehated4fc8a2010-01-22 12:28:36 -0800313 throw new IllegalStateException(
Kenny Roota80ce062010-06-01 13:23:53 -0700314 String.format("Invalid response from daemon (%s)", rsp));
San Mehated4fc8a2010-01-22 12:28:36 -0800315 }
Kenny Roota80ce062010-06-01 13:23:53 -0700316
317 cfg = new InterfaceConfiguration();
318 cfg.hwAddr = st.nextToken(" ");
Robert Greenwalted126402011-01-28 15:34:55 -0800319 InetAddress addr = null;
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800320 int prefixLength = 0;
Kenny Roota80ce062010-06-01 13:23:53 -0700321 try {
Robert Greenwalte5903732011-02-22 16:00:42 -0800322 addr = NetworkUtils.numericToInetAddress(st.nextToken(" "));
323 } catch (IllegalArgumentException iae) {
324 Slog.e(TAG, "Failed to parse ipaddr", iae);
Kenny Roota80ce062010-06-01 13:23:53 -0700325 }
326
327 try {
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800328 prefixLength = Integer.parseInt(st.nextToken(" "));
329 } catch (NumberFormatException nfe) {
330 Slog.e(TAG, "Failed to parse prefixLength", nfe);
Kenny Roota80ce062010-06-01 13:23:53 -0700331 }
Robert Greenwalt04808c22010-12-13 17:01:41 -0800332
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800333 cfg.addr = new LinkAddress(addr, prefixLength);
Kenny Roota80ce062010-06-01 13:23:53 -0700334 cfg.interfaceFlags = st.nextToken("]").trim() +"]";
335 } catch (NoSuchElementException nsee) {
San Mehated4fc8a2010-01-22 12:28:36 -0800336 throw new IllegalStateException(
337 String.format("Invalid response from daemon (%s)", rsp));
338 }
Joe Onorato8a9b2202010-02-26 18:56:32 -0800339 Slog.d(TAG, String.format("flags <%s>", cfg.interfaceFlags));
San Mehated4fc8a2010-01-22 12:28:36 -0800340 return cfg;
341 }
342
343 public void setInterfaceConfig(
344 String iface, InterfaceConfiguration cfg) throws IllegalStateException {
Robert Greenwalted126402011-01-28 15:34:55 -0800345 LinkAddress linkAddr = cfg.addr;
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800346 if (linkAddr == null || linkAddr.getAddress() == null) {
347 throw new IllegalStateException("Null LinkAddress given");
Robert Greenwalted126402011-01-28 15:34:55 -0800348 }
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800349 String cmd = String.format("interface setcfg %s %s %d %s", iface,
350 linkAddr.getAddress().getHostAddress(),
351 linkAddr.getNetworkPrefixLength(),
352 cfg.interfaceFlags);
Kenny Roota80ce062010-06-01 13:23:53 -0700353 try {
354 mConnector.doCommand(cmd);
355 } catch (NativeDaemonConnectorException e) {
356 throw new IllegalStateException(
Robert Greenwalt81d5ad52010-12-16 11:27:38 -0800357 "Unable to communicate with native daemon to interface setcfg - " + e);
Kenny Roota80ce062010-06-01 13:23:53 -0700358 }
San Mehat873f2142010-01-14 10:25:07 -0800359 }
360
Irfan Sherifff5600612011-06-16 10:26:28 -0700361 /* TODO: This is right now a IPv4 only function. Works for wifi which loses its
362 IPv6 addresses on interface down, but we need to do full clean up here */
363 public void clearInterfaceAddresses(String iface) throws IllegalStateException {
364 String cmd = String.format("interface clearaddrs %s", iface);
365 try {
366 mConnector.doCommand(cmd);
367 } catch (NativeDaemonConnectorException e) {
368 throw new IllegalStateException(
369 "Unable to communicate with native daemon to interface clearallips - " + e);
370 }
371 }
372
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -0700373 public void addRoute(String interfaceName, RouteInfo route) {
374 modifyRoute(interfaceName, ADD, route);
375 }
376
377 public void removeRoute(String interfaceName, RouteInfo route) {
378 modifyRoute(interfaceName, REMOVE, route);
379 }
380
381 private void modifyRoute(String interfaceName, int action, RouteInfo route) {
382 ArrayList<String> rsp;
383
384 StringBuilder cmd;
385
386 switch (action) {
387 case ADD:
388 {
389 cmd = new StringBuilder("interface route add " + interfaceName);
390 break;
391 }
392 case REMOVE:
393 {
394 cmd = new StringBuilder("interface route remove " + interfaceName);
395 break;
396 }
397 default:
398 throw new IllegalStateException("Unknown action type " + action);
399 }
400
401 // create triplet: dest-ip-addr prefixlength gateway-ip-addr
402 LinkAddress la = route.getDestination();
403 cmd.append(' ');
404 cmd.append(la.getAddress().getHostAddress());
405 cmd.append(' ');
406 cmd.append(la.getNetworkPrefixLength());
407 cmd.append(' ');
408 if (route.getGateway() == null) {
409 if (la.getAddress() instanceof Inet4Address) {
410 cmd.append("0.0.0.0");
411 } else {
412 cmd.append ("::0");
413 }
414 } else {
415 cmd.append(route.getGateway().getHostAddress());
416 }
417 try {
418 rsp = mConnector.doCommand(cmd.toString());
419 } catch (NativeDaemonConnectorException e) {
420 throw new IllegalStateException(
421 "Unable to communicate with native dameon to add routes - "
422 + e);
423 }
424
425 for (String line : rsp) {
426 Log.v(TAG, "add route response is " + line);
427 }
428 }
429
430 private ArrayList<String> readRouteList(String filename) {
431 FileInputStream fstream = null;
432 ArrayList<String> list = new ArrayList<String>();
433
434 try {
435 fstream = new FileInputStream(filename);
436 DataInputStream in = new DataInputStream(fstream);
437 BufferedReader br = new BufferedReader(new InputStreamReader(in));
438 String s;
439
440 // throw away the title line
441
442 while (((s = br.readLine()) != null) && (s.length() != 0)) {
443 list.add(s);
444 }
445 } catch (IOException ex) {
446 // return current list, possibly empty
447 } finally {
448 if (fstream != null) {
449 try {
450 fstream.close();
451 } catch (IOException ex) {}
452 }
453 }
454
455 return list;
456 }
457
458 public RouteInfo[] getRoutes(String interfaceName) {
459 ArrayList<RouteInfo> routes = new ArrayList<RouteInfo>();
460
461 // v4 routes listed as:
462 // iface dest-addr gateway-addr flags refcnt use metric netmask mtu window IRTT
463 for (String s : readRouteList("/proc/net/route")) {
464 String[] fields = s.split("\t");
465
466 if (fields.length > 7) {
467 String iface = fields[0];
468
469 if (interfaceName.equals(iface)) {
470 String dest = fields[1];
471 String gate = fields[2];
472 String flags = fields[3]; // future use?
473 String mask = fields[7];
474 try {
475 // address stored as a hex string, ex: 0014A8C0
476 InetAddress destAddr =
477 NetworkUtils.intToInetAddress((int)Long.parseLong(dest, 16));
478 int prefixLength =
479 NetworkUtils.netmaskIntToPrefixLength(
480 (int)Long.parseLong(mask, 16));
481 LinkAddress linkAddress = new LinkAddress(destAddr, prefixLength);
482
483 // address stored as a hex string, ex 0014A8C0
484 InetAddress gatewayAddr =
485 NetworkUtils.intToInetAddress((int)Long.parseLong(gate, 16));
486
487 RouteInfo route = new RouteInfo(linkAddress, gatewayAddr);
488 routes.add(route);
489 } catch (Exception e) {
490 Log.e(TAG, "Error parsing route " + s + " : " + e);
491 continue;
492 }
493 }
494 }
495 }
496
497 // v6 routes listed as:
498 // dest-addr prefixlength ?? ?? gateway-addr ?? ?? ?? ?? iface
499 for (String s : readRouteList("/proc/net/ipv6_route")) {
500 String[]fields = s.split("\\s+");
501 if (fields.length > 9) {
502 String iface = fields[9].trim();
503 if (interfaceName.equals(iface)) {
504 String dest = fields[0];
505 String prefix = fields[1];
506 String gate = fields[4];
507
508 try {
509 // prefix length stored as a hex string, ex 40
510 int prefixLength = Integer.parseInt(prefix, 16);
511
512 // address stored as a 32 char hex string
513 // ex fe800000000000000000000000000000
514 InetAddress destAddr = NetworkUtils.hexToInet6Address(dest);
515 LinkAddress linkAddress = new LinkAddress(destAddr, prefixLength);
516
517 InetAddress gateAddr = NetworkUtils.hexToInet6Address(gate);
518
519 RouteInfo route = new RouteInfo(linkAddress, gateAddr);
520 routes.add(route);
521 } catch (Exception e) {
522 Log.e(TAG, "Error parsing route " + s + " : " + e);
523 continue;
524 }
525 }
526 }
527 }
528 return (RouteInfo[]) routes.toArray(new RouteInfo[0]);
529 }
530
San Mehat873f2142010-01-14 10:25:07 -0800531 public void shutdown() {
532 if (mContext.checkCallingOrSelfPermission(
533 android.Manifest.permission.SHUTDOWN)
534 != PackageManager.PERMISSION_GRANTED) {
535 throw new SecurityException("Requires SHUTDOWN permission");
536 }
537
Joe Onorato8a9b2202010-02-26 18:56:32 -0800538 Slog.d(TAG, "Shutting down");
San Mehat873f2142010-01-14 10:25:07 -0800539 }
540
541 public boolean getIpForwardingEnabled() throws IllegalStateException{
542 mContext.enforceCallingOrSelfPermission(
543 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
544
Kenny Roota80ce062010-06-01 13:23:53 -0700545 ArrayList<String> rsp;
546 try {
547 rsp = mConnector.doCommand("ipfwd status");
548 } catch (NativeDaemonConnectorException e) {
549 throw new IllegalStateException(
550 "Unable to communicate with native daemon to ipfwd status");
551 }
San Mehat873f2142010-01-14 10:25:07 -0800552
553 for (String line : rsp) {
Kenny Roota80ce062010-06-01 13:23:53 -0700554 String[] tok = line.split(" ");
555 if (tok.length < 3) {
556 Slog.e(TAG, "Malformed response from native daemon: " + line);
557 return false;
558 }
559
San Mehat873f2142010-01-14 10:25:07 -0800560 int code = Integer.parseInt(tok[0]);
561 if (code == NetdResponseCode.IpFwdStatusResult) {
562 // 211 Forwarding <enabled/disabled>
Kenny Roota80ce062010-06-01 13:23:53 -0700563 return "enabled".equals(tok[2]);
San Mehat873f2142010-01-14 10:25:07 -0800564 } else {
565 throw new IllegalStateException(String.format("Unexpected response code %d", code));
566 }
567 }
568 throw new IllegalStateException("Got an empty response");
569 }
570
571 public void setIpForwardingEnabled(boolean enable) throws IllegalStateException {
572 mContext.enforceCallingOrSelfPermission(
573 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
574 mConnector.doCommand(String.format("ipfwd %sable", (enable ? "en" : "dis")));
575 }
576
Robert Greenwaltbfb7bfa2010-03-24 16:03:21 -0700577 public void startTethering(String[] dhcpRange)
San Mehat873f2142010-01-14 10:25:07 -0800578 throws IllegalStateException {
579 mContext.enforceCallingOrSelfPermission(
580 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Robert Greenwaltbfb7bfa2010-03-24 16:03:21 -0700581 // cmd is "tether start first_start first_stop second_start second_stop ..."
582 // an odd number of addrs will fail
583 String cmd = "tether start";
584 for (String d : dhcpRange) {
585 cmd += " " + d;
586 }
Kenny Roota80ce062010-06-01 13:23:53 -0700587
588 try {
589 mConnector.doCommand(cmd);
590 } catch (NativeDaemonConnectorException e) {
591 throw new IllegalStateException("Unable to communicate to native daemon");
592 }
San Mehat873f2142010-01-14 10:25:07 -0800593 }
594
595 public void stopTethering() throws IllegalStateException {
596 mContext.enforceCallingOrSelfPermission(
597 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700598 try {
599 mConnector.doCommand("tether stop");
600 } catch (NativeDaemonConnectorException e) {
601 throw new IllegalStateException("Unable to communicate to native daemon to stop tether");
602 }
San Mehat873f2142010-01-14 10:25:07 -0800603 }
604
605 public boolean isTetheringStarted() throws IllegalStateException {
606 mContext.enforceCallingOrSelfPermission(
607 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
608
Kenny Roota80ce062010-06-01 13:23:53 -0700609 ArrayList<String> rsp;
610 try {
611 rsp = mConnector.doCommand("tether status");
612 } catch (NativeDaemonConnectorException e) {
613 throw new IllegalStateException(
614 "Unable to communicate to native daemon to get tether status");
615 }
San Mehat873f2142010-01-14 10:25:07 -0800616
617 for (String line : rsp) {
Kenny Roota80ce062010-06-01 13:23:53 -0700618 String[] tok = line.split(" ");
619 if (tok.length < 3) {
620 throw new IllegalStateException("Malformed response for tether status: " + line);
621 }
San Mehat873f2142010-01-14 10:25:07 -0800622 int code = Integer.parseInt(tok[0]);
623 if (code == NetdResponseCode.TetherStatusResult) {
624 // XXX: Tethering services <started/stopped> <TBD>...
Kenny Roota80ce062010-06-01 13:23:53 -0700625 return "started".equals(tok[2]);
San Mehat873f2142010-01-14 10:25:07 -0800626 } else {
627 throw new IllegalStateException(String.format("Unexpected response code %d", code));
628 }
629 }
630 throw new IllegalStateException("Got an empty response");
631 }
632
633 public void tetherInterface(String iface) throws IllegalStateException {
634 mContext.enforceCallingOrSelfPermission(
635 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700636 try {
637 mConnector.doCommand("tether interface add " + iface);
638 } catch (NativeDaemonConnectorException e) {
639 throw new IllegalStateException(
640 "Unable to communicate to native daemon for adding tether interface");
641 }
San Mehat873f2142010-01-14 10:25:07 -0800642 }
643
644 public void untetherInterface(String iface) {
645 mContext.enforceCallingOrSelfPermission(
646 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700647 try {
648 mConnector.doCommand("tether interface remove " + iface);
649 } catch (NativeDaemonConnectorException e) {
650 throw new IllegalStateException(
651 "Unable to communicate to native daemon for removing tether interface");
652 }
San Mehat873f2142010-01-14 10:25:07 -0800653 }
654
655 public String[] listTetheredInterfaces() throws IllegalStateException {
656 mContext.enforceCallingOrSelfPermission(
657 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700658 try {
659 return mConnector.doListCommand(
660 "tether interface list", NetdResponseCode.TetherInterfaceListResult);
661 } catch (NativeDaemonConnectorException e) {
662 throw new IllegalStateException(
663 "Unable to communicate to native daemon for listing tether interfaces");
664 }
San Mehat873f2142010-01-14 10:25:07 -0800665 }
666
667 public void setDnsForwarders(String[] dns) throws IllegalStateException {
668 mContext.enforceCallingOrSelfPermission(
669 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
670 try {
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800671 String cmd = "tether dns set";
San Mehat873f2142010-01-14 10:25:07 -0800672 for (String s : dns) {
Robert Greenwalte5903732011-02-22 16:00:42 -0800673 cmd += " " + NetworkUtils.numericToInetAddress(s).getHostAddress();
San Mehat873f2142010-01-14 10:25:07 -0800674 }
Kenny Roota80ce062010-06-01 13:23:53 -0700675 try {
676 mConnector.doCommand(cmd);
677 } catch (NativeDaemonConnectorException e) {
678 throw new IllegalStateException(
679 "Unable to communicate to native daemon for setting tether dns");
680 }
Robert Greenwalte5903732011-02-22 16:00:42 -0800681 } catch (IllegalArgumentException e) {
San Mehat873f2142010-01-14 10:25:07 -0800682 throw new IllegalStateException("Error resolving dns name", e);
683 }
684 }
685
686 public String[] getDnsForwarders() throws IllegalStateException {
687 mContext.enforceCallingOrSelfPermission(
688 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700689 try {
690 return mConnector.doListCommand(
691 "tether dns list", NetdResponseCode.TetherDnsFwdTgtListResult);
692 } catch (NativeDaemonConnectorException e) {
693 throw new IllegalStateException(
694 "Unable to communicate to native daemon for listing tether dns");
695 }
San Mehat873f2142010-01-14 10:25:07 -0800696 }
697
698 public void enableNat(String internalInterface, String externalInterface)
699 throws IllegalStateException {
700 mContext.enforceCallingOrSelfPermission(
701 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700702 try {
703 mConnector.doCommand(
704 String.format("nat enable %s %s", internalInterface, externalInterface));
705 } catch (NativeDaemonConnectorException e) {
706 throw new IllegalStateException(
707 "Unable to communicate to native daemon for enabling NAT interface");
708 }
San Mehat873f2142010-01-14 10:25:07 -0800709 }
710
711 public void disableNat(String internalInterface, String externalInterface)
712 throws IllegalStateException {
713 mContext.enforceCallingOrSelfPermission(
714 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700715 try {
716 mConnector.doCommand(
717 String.format("nat disable %s %s", internalInterface, externalInterface));
718 } catch (NativeDaemonConnectorException e) {
719 throw new IllegalStateException(
720 "Unable to communicate to native daemon for disabling NAT interface");
721 }
San Mehat873f2142010-01-14 10:25:07 -0800722 }
San Mehat72759df2010-01-19 13:50:37 -0800723
724 public String[] listTtys() throws IllegalStateException {
725 mContext.enforceCallingOrSelfPermission(
726 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700727 try {
728 return mConnector.doListCommand("list_ttys", NetdResponseCode.TtyListResult);
729 } catch (NativeDaemonConnectorException e) {
730 throw new IllegalStateException(
731 "Unable to communicate to native daemon for listing TTYs");
732 }
San Mehat72759df2010-01-19 13:50:37 -0800733 }
734
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800735 public void attachPppd(String tty, String localAddr, String remoteAddr, String dns1Addr,
736 String dns2Addr) throws IllegalStateException {
San Mehat72759df2010-01-19 13:50:37 -0800737 try {
738 mContext.enforceCallingOrSelfPermission(
739 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800740 mConnector.doCommand(String.format("pppd attach %s %s %s %s %s", tty,
Robert Greenwalte5903732011-02-22 16:00:42 -0800741 NetworkUtils.numericToInetAddress(localAddr).getHostAddress(),
742 NetworkUtils.numericToInetAddress(remoteAddr).getHostAddress(),
743 NetworkUtils.numericToInetAddress(dns1Addr).getHostAddress(),
744 NetworkUtils.numericToInetAddress(dns2Addr).getHostAddress()));
745 } catch (IllegalArgumentException e) {
San Mehat72759df2010-01-19 13:50:37 -0800746 throw new IllegalStateException("Error resolving addr", e);
Kenny Roota80ce062010-06-01 13:23:53 -0700747 } catch (NativeDaemonConnectorException e) {
748 throw new IllegalStateException("Error communicating to native daemon to attach pppd", e);
San Mehat72759df2010-01-19 13:50:37 -0800749 }
750 }
751
752 public void detachPppd(String tty) throws IllegalStateException {
753 mContext.enforceCallingOrSelfPermission(
754 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700755 try {
756 mConnector.doCommand(String.format("pppd detach %s", tty));
757 } catch (NativeDaemonConnectorException e) {
758 throw new IllegalStateException("Error communicating to native daemon to detach pppd", e);
759 }
San Mehat72759df2010-01-19 13:50:37 -0800760 }
Robert Greenwaltce1200d2010-02-18 11:25:54 -0800761
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700762 public void startAccessPoint(WifiConfiguration wifiConfig, String wlanIface, String softapIface)
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800763 throws IllegalStateException {
764 mContext.enforceCallingOrSelfPermission(
765 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
766 mContext.enforceCallingOrSelfPermission(
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700767 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700768 try {
769 mConnector.doCommand(String.format("softap stop " + wlanIface));
770 mConnector.doCommand(String.format("softap fwreload " + wlanIface + " AP"));
771 mConnector.doCommand(String.format("softap start " + wlanIface));
772 if (wifiConfig == null) {
773 mConnector.doCommand(String.format("softap set " + wlanIface + " " + softapIface));
774 } else {
775 /**
776 * softap set arg1 arg2 arg3 [arg4 arg5 arg6 arg7 arg8]
777 * argv1 - wlan interface
778 * argv2 - softap interface
779 * argv3 - SSID
780 * argv4 - Security
781 * argv5 - Key
782 * argv6 - Channel
783 * argv7 - Preamble
784 * argv8 - Max SCB
785 */
Irfan Sheriffec8d23a2011-02-16 17:00:33 -0800786 String str = String.format("softap set " + wlanIface + " " + softapIface +
787 " %s %s %s", convertQuotedString(wifiConfig.SSID),
788 getSecurityType(wifiConfig),
789 convertQuotedString(wifiConfig.preSharedKey));
Kenny Roota80ce062010-06-01 13:23:53 -0700790 mConnector.doCommand(str);
791 }
792 mConnector.doCommand(String.format("softap startap"));
793 } catch (NativeDaemonConnectorException e) {
794 throw new IllegalStateException("Error communicating to native daemon to start softap", e);
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -0800795 }
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800796 }
797
Irfan Sheriffa6e559e2010-05-24 14:55:42 -0700798 private String convertQuotedString(String s) {
Irfan Sheriff7baec0f2010-05-26 17:16:47 -0700799 if (s == null) {
800 return s;
801 }
802 /* Replace \ with \\, then " with \" and add quotes at end */
803 return '"' + s.replaceAll("\\\\","\\\\\\\\").replaceAll("\"","\\\\\"") + '"';
Irfan Sheriffa6e559e2010-05-24 14:55:42 -0700804 }
805
Irfan Sheriffec8d23a2011-02-16 17:00:33 -0800806 private String getSecurityType(WifiConfiguration wifiConfig) {
807 switch (wifiConfig.getAuthType()) {
808 case KeyMgmt.WPA_PSK:
809 return "wpa-psk";
810 case KeyMgmt.WPA2_PSK:
811 return "wpa2-psk";
812 default:
813 return "open";
814 }
815 }
816
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800817 public void stopAccessPoint() throws IllegalStateException {
818 mContext.enforceCallingOrSelfPermission(
819 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
820 mContext.enforceCallingOrSelfPermission(
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700821 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700822 try {
823 mConnector.doCommand("softap stopap");
824 } catch (NativeDaemonConnectorException e) {
825 throw new IllegalStateException("Error communicating to native daemon to stop soft AP",
826 e);
827 }
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800828 }
829
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700830 public void setAccessPoint(WifiConfiguration wifiConfig, String wlanIface, String softapIface)
831 throws IllegalStateException {
832 mContext.enforceCallingOrSelfPermission(
833 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
834 mContext.enforceCallingOrSelfPermission(
835 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700836 try {
837 if (wifiConfig == null) {
838 mConnector.doCommand(String.format("softap set " + wlanIface + " " + softapIface));
839 } else {
840 String str = String.format("softap set " + wlanIface + " " + softapIface
841 + " %s %s %s", convertQuotedString(wifiConfig.SSID),
Irfan Sheriffec8d23a2011-02-16 17:00:33 -0800842 getSecurityType(wifiConfig),
Kenny Roota80ce062010-06-01 13:23:53 -0700843 convertQuotedString(wifiConfig.preSharedKey));
844 mConnector.doCommand(str);
845 }
846 } catch (NativeDaemonConnectorException e) {
847 throw new IllegalStateException("Error communicating to native daemon to set soft AP",
848 e);
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700849 }
850 }
San Mehat91cac642010-03-31 14:31:36 -0700851
852 private long getInterfaceCounter(String iface, boolean rx) {
853 mContext.enforceCallingOrSelfPermission(
854 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
855 try {
Kenny Roota80ce062010-06-01 13:23:53 -0700856 String rsp;
857 try {
858 rsp = mConnector.doCommand(
859 String.format("interface read%scounter %s", (rx ? "rx" : "tx"), iface)).get(0);
860 } catch (NativeDaemonConnectorException e1) {
861 Slog.e(TAG, "Error communicating with native daemon", e1);
862 return -1;
863 }
864
865 String[] tok = rsp.split(" ");
866 if (tok.length < 2) {
867 Slog.e(TAG, String.format("Malformed response for reading %s interface",
868 (rx ? "rx" : "tx")));
869 return -1;
870 }
871
San Mehat91cac642010-03-31 14:31:36 -0700872 int code;
873 try {
874 code = Integer.parseInt(tok[0]);
875 } catch (NumberFormatException nfe) {
876 Slog.e(TAG, String.format("Error parsing code %s", tok[0]));
877 return -1;
878 }
879 if ((rx && code != NetdResponseCode.InterfaceRxCounterResult) || (
880 !rx && code != NetdResponseCode.InterfaceTxCounterResult)) {
881 Slog.e(TAG, String.format("Unexpected response code %d", code));
882 return -1;
883 }
884 return Long.parseLong(tok[1]);
885 } catch (Exception e) {
886 Slog.e(TAG, String.format(
887 "Failed to read interface %s counters", (rx ? "rx" : "tx")), e);
888 }
889 return -1;
890 }
891
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700892 @Override
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700893 public NetworkStats getNetworkStatsSummary() {
894 mContext.enforceCallingOrSelfPermission(
895 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
896
897 final String[] ifaces = listInterfaces();
Jeff Sharkey4a971222011-06-11 22:16:55 -0700898 final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), ifaces.length);
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700899
900 for (String iface : ifaces) {
901 final long rx = getInterfaceCounter(iface, true);
902 final long tx = getInterfaceCounter(iface, false);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700903 stats.addEntry(iface, UID_ALL, TAG_NONE, rx, tx);
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700904 }
905
Jeff Sharkey4a971222011-06-11 22:16:55 -0700906 return stats;
San Mehat91cac642010-03-31 14:31:36 -0700907 }
908
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700909 @Override
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700910 public NetworkStats getNetworkStatsDetail() {
911 mContext.enforceCallingOrSelfPermission(
912 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
913
Jeff Sharkey4414cea2011-06-24 17:05:24 -0700914 if (mProcStatsNetfilter.exists()) {
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700915 return getNetworkStatsDetailNetfilter(UID_ALL);
916 } else {
917 return getNetworkStatsDetailUidstat(UID_ALL);
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700918 }
San Mehat91cac642010-03-31 14:31:36 -0700919 }
920
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700921 @Override
922 public NetworkStats getNetworkStatsUidDetail(int uid) {
923 if (Binder.getCallingUid() != uid) {
924 mContext.enforceCallingOrSelfPermission(
925 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
926 }
927
Jeff Sharkey4414cea2011-06-24 17:05:24 -0700928 if (mProcStatsNetfilter.exists()) {
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700929 return getNetworkStatsDetailNetfilter(uid);
930 } else {
931 return getNetworkStatsDetailUidstat(uid);
932 }
933 }
934
935 /**
936 * Build {@link NetworkStats} with detailed UID statistics.
937 */
938 private NetworkStats getNetworkStatsDetailNetfilter(int limitUid) {
939 final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 24);
Jeff Sharkey4414cea2011-06-24 17:05:24 -0700940 final ArrayList<String> keys = Lists.newArrayList();
941 final ArrayList<String> values = Lists.newArrayList();
942 final HashMap<String, String> parsed = Maps.newHashMap();
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700943
944 BufferedReader reader = null;
945 try {
Jeff Sharkey4414cea2011-06-24 17:05:24 -0700946 reader = new BufferedReader(new FileReader(mProcStatsNetfilter));
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700947
Jeff Sharkey4414cea2011-06-24 17:05:24 -0700948 // parse first line as header
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700949 String line = reader.readLine();
Jeff Sharkey4414cea2011-06-24 17:05:24 -0700950 splitLine(line, keys);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700951
Jeff Sharkey4414cea2011-06-24 17:05:24 -0700952 // parse remaining lines
953 while ((line = reader.readLine()) != null) {
954 splitLine(line, values);
955 parseLine(keys, values, parsed);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700956
957 try {
Jeff Sharkey4414cea2011-06-24 17:05:24 -0700958 final String iface = parsed.get(KEY_IFACE);
Jesse Wilson8568db52011-06-28 19:06:31 -0700959 final int tag = NetworkManagementSocketTagger.kernelToTag(
960 parsed.get(KEY_TAG_HEX));
Jeff Sharkey4414cea2011-06-24 17:05:24 -0700961 final int uid = Integer.parseInt(parsed.get(KEY_UID));
962 final long rx = Long.parseLong(parsed.get(KEY_RX));
963 final long tx = Long.parseLong(parsed.get(KEY_TX));
Jeff Sharkeyd03fd3f2011-06-19 20:55:09 -0700964
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700965 if (limitUid == UID_ALL || limitUid == uid) {
966 stats.addEntry(iface, uid, tag, rx, tx);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700967 }
968 } catch (NumberFormatException e) {
Jeff Sharkey4414cea2011-06-24 17:05:24 -0700969 Slog.w(TAG, "problem parsing stats row '" + line + "': " + e);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700970 }
971 }
972 } catch (IOException e) {
973 Slog.w(TAG, "problem parsing stats: " + e);
974 } finally {
975 IoUtils.closeQuietly(reader);
976 }
977
Jeff Sharkey4a971222011-06-11 22:16:55 -0700978 return stats;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700979 }
980
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700981 /**
982 * Build {@link NetworkStats} with detailed UID statistics.
983 *
984 * @deprecated since this uses older "uid_stat" data, and doesn't provide
985 * tag-level granularity or additional variables.
986 */
987 @Deprecated
988 private NetworkStats getNetworkStatsDetailUidstat(int limitUid) {
989 final String[] knownUids;
990 if (limitUid == UID_ALL) {
Jeff Sharkey4414cea2011-06-24 17:05:24 -0700991 knownUids = mProcStatsUidstat.list();
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -0700992 } else {
993 knownUids = new String[] { String.valueOf(limitUid) };
994 }
995
996 final NetworkStats stats = new NetworkStats(
997 SystemClock.elapsedRealtime(), knownUids.length);
998 for (String uid : knownUids) {
999 final int uidInt = Integer.parseInt(uid);
Jeff Sharkey4414cea2011-06-24 17:05:24 -07001000 final File uidPath = new File(mProcStatsUidstat, uid);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001001 final long rx = readSingleLongFromFile(new File(uidPath, "tcp_rcv"));
1002 final long tx = readSingleLongFromFile(new File(uidPath, "tcp_snd"));
1003 stats.addEntry(IFACE_ALL, uidInt, TAG_NONE, rx, tx);
1004 }
1005
1006 return stats;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001007 }
1008
San Mehatf0db6e12010-04-07 15:22:10 -07001009 public void setInterfaceThrottle(String iface, int rxKbps, int txKbps) {
San Mehat91cac642010-03-31 14:31:36 -07001010 mContext.enforceCallingOrSelfPermission(
1011 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -07001012 try {
1013 mConnector.doCommand(String.format(
1014 "interface setthrottle %s %d %d", iface, rxKbps, txKbps));
1015 } catch (NativeDaemonConnectorException e) {
1016 Slog.e(TAG, "Error communicating with native daemon to set throttle", e);
1017 }
San Mehat91cac642010-03-31 14:31:36 -07001018 }
1019
1020 private int getInterfaceThrottle(String iface, boolean rx) {
1021 mContext.enforceCallingOrSelfPermission(
1022 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
1023 try {
Kenny Roota80ce062010-06-01 13:23:53 -07001024 String rsp;
1025 try {
1026 rsp = mConnector.doCommand(
1027 String.format("interface getthrottle %s %s", iface,
1028 (rx ? "rx" : "tx"))).get(0);
1029 } catch (NativeDaemonConnectorException e) {
1030 Slog.e(TAG, "Error communicating with native daemon to getthrottle", e);
1031 return -1;
1032 }
1033
1034 String[] tok = rsp.split(" ");
1035 if (tok.length < 2) {
1036 Slog.e(TAG, "Malformed response to getthrottle command");
1037 return -1;
1038 }
1039
San Mehat91cac642010-03-31 14:31:36 -07001040 int code;
1041 try {
1042 code = Integer.parseInt(tok[0]);
1043 } catch (NumberFormatException nfe) {
1044 Slog.e(TAG, String.format("Error parsing code %s", tok[0]));
1045 return -1;
1046 }
1047 if ((rx && code != NetdResponseCode.InterfaceRxThrottleResult) || (
1048 !rx && code != NetdResponseCode.InterfaceTxThrottleResult)) {
1049 Slog.e(TAG, String.format("Unexpected response code %d", code));
1050 return -1;
1051 }
1052 return Integer.parseInt(tok[1]);
1053 } catch (Exception e) {
1054 Slog.e(TAG, String.format(
1055 "Failed to read interface %s throttle value", (rx ? "rx" : "tx")), e);
1056 }
1057 return -1;
1058 }
1059
1060 public int getInterfaceRxThrottle(String iface) {
1061 return getInterfaceThrottle(iface, true);
1062 }
1063
1064 public int getInterfaceTxThrottle(String iface) {
1065 return getInterfaceThrottle(iface, false);
1066 }
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001067
Jeff Sharkey0a9ee122011-06-22 16:32:41 -07001068 @Override
1069 public void setBandwidthControlEnabled(boolean enabled) {
1070 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1071 mConnector.doCommand(String.format("bandwidth %s", (enabled ? "enable" : "disable")));
1072 }
1073
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001074 /**
Jeff Sharkey4414cea2011-06-24 17:05:24 -07001075 * Split given line into {@link ArrayList}.
1076 */
1077 private static void splitLine(String line, ArrayList<String> outSplit) {
1078 outSplit.clear();
1079
1080 final StringTokenizer t = new StringTokenizer(line);
1081 while (t.hasMoreTokens()) {
1082 outSplit.add(t.nextToken());
1083 }
1084 }
1085
1086 /**
1087 * Zip the two given {@link ArrayList} as key and value pairs into
1088 * {@link HashMap}.
1089 */
1090 private static void parseLine(
1091 ArrayList<String> keys, ArrayList<String> values, HashMap<String, String> outParsed) {
1092 outParsed.clear();
1093
1094 final int size = Math.min(keys.size(), values.size());
1095 for (int i = 0; i < size; i++) {
1096 outParsed.put(keys.get(i), values.get(i));
1097 }
1098 }
1099
1100 /**
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001101 * Utility method to read a single plain-text {@link Long} from the given
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001102 * {@link File}, usually from a {@code /proc/} filesystem.
1103 */
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001104 private static long readSingleLongFromFile(File file) {
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001105 try {
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001106 final byte[] buffer = IoUtils.readFileAsByteArray(file.toString());
1107 return Long.parseLong(new String(buffer).trim());
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001108 } catch (NumberFormatException e) {
1109 return -1;
1110 } catch (IOException e) {
1111 return -1;
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001112 }
1113 }
San Mehat873f2142010-01-14 10:25:07 -08001114}