blob: 782e7d7acdd554cbf3b373b5276193f169a61004 [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 Sharkey350083e2011-06-29 10:45:16 -070019import static android.Manifest.permission.MANAGE_NETWORK_POLICY;
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -070020import static android.net.NetworkStats.IFACE_ALL;
21import static android.net.NetworkStats.TAG_NONE;
22import static android.net.NetworkStats.UID_ALL;
Jeff Sharkey350083e2011-06-29 10:45:16 -070023import static android.provider.Settings.Secure.NETSTATS_ENABLED;
Jeff Sharkeya63ba592011-07-19 23:47:12 -070024import static com.android.server.NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED;
25import static com.android.server.NetworkManagementSocketTagger.kernelToTag;
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -070026
San Mehat873f2142010-01-14 10:25:07 -080027import android.content.Context;
San Mehat873f2142010-01-14 10:25:07 -080028import android.content.pm.PackageManager;
San Mehat4d02d002010-01-22 16:07:46 -080029import android.net.INetworkManagementEventObserver;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070030import android.net.InterfaceConfiguration;
Robert Greenwalted126402011-01-28 15:34:55 -080031import android.net.LinkAddress;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070032import android.net.NetworkStats;
Robert Greenwalted126402011-01-28 15:34:55 -080033import android.net.NetworkUtils;
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -070034import android.net.RouteInfo;
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -080035import android.net.wifi.WifiConfiguration;
36import android.net.wifi.WifiConfiguration.KeyMgmt;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070037import android.os.Binder;
San Mehat873f2142010-01-14 10:25:07 -080038import android.os.INetworkManagementService;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070039import android.os.SystemClock;
Marco Nelissen62dbb222010-02-18 10:56:30 -080040import android.os.SystemProperties;
Jeff Sharkey350083e2011-06-29 10:45:16 -070041import android.provider.Settings;
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -080042import android.util.Log;
Joe Onorato8a9b2202010-02-26 18:56:32 -080043import android.util.Slog;
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -070044import android.util.SparseBooleanArray;
San Mehat873f2142010-01-14 10:25:07 -080045
Jeff Sharkey4414cea2011-06-24 17:05:24 -070046import com.google.android.collect.Lists;
47import com.google.android.collect.Maps;
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -070048import com.google.android.collect.Sets;
Jeff Sharkey4414cea2011-06-24 17:05:24 -070049
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -070050import java.io.BufferedReader;
51import java.io.DataInputStream;
San Mehat873f2142010-01-14 10:25:07 -080052import java.io.File;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070053import java.io.FileInputStream;
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -070054import java.io.FileReader;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070055import java.io.IOException;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070056import java.io.InputStreamReader;
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -070057import java.net.Inet4Address;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070058import java.net.InetAddress;
59import java.util.ArrayList;
Jeff Sharkey4414cea2011-06-24 17:05:24 -070060import java.util.HashMap;
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -070061import java.util.HashSet;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070062import java.util.NoSuchElementException;
63import java.util.StringTokenizer;
Robert Greenwalte5c3afb2010-09-22 14:32:35 -070064import java.util.concurrent.CountDownLatch;
San Mehat873f2142010-01-14 10:25:07 -080065
Jeff Sharkey9a13f362011-04-26 16:25:36 -070066import libcore.io.IoUtils;
67
San Mehat873f2142010-01-14 10:25:07 -080068/**
69 * @hide
70 */
71class NetworkManagementService extends INetworkManagementService.Stub {
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070072 private static final String TAG = "NetworkManagementService";
Dianne Hackborncef65ee2010-09-30 18:27:22 -070073 private static final boolean DBG = false;
Kenny Root305bcbf2010-09-03 07:56:38 -070074 private static final String NETD_TAG = "NetdConnector";
75
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -070076 private static final int ADD = 1;
77 private static final int REMOVE = 2;
78
Jeff Sharkey4414cea2011-06-24 17:05:24 -070079 /** Path to {@code /proc/uid_stat}. */
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -070080 @Deprecated
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -070081 private final File mStatsUid;
82 /** Path to {@code /proc/net/dev}. */
83 private final File mStatsIface;
Jeff Sharkey4414cea2011-06-24 17:05:24 -070084 /** Path to {@code /proc/net/xt_qtaguid/stats}. */
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -070085 private final File mStatsXtUid;
86 /** Path to {@code /proc/net/xt_qtaguid/iface_stat}. */
87 private final File mStatsXtIface;
Jeff Sharkey4414cea2011-06-24 17:05:24 -070088
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -070089 /** {@link #mStatsXtUid} headers. */
Jeff Sharkey4414cea2011-06-24 17:05:24 -070090 private static final String KEY_IFACE = "iface";
91 private static final String KEY_TAG_HEX = "acct_tag_hex";
92 private static final String KEY_UID = "uid_tag_int";
Jeff Sharkeya63ba592011-07-19 23:47:12 -070093 private static final String KEY_RX_BYTES = "rx_bytes";
94 private static final String KEY_RX_PACKETS = "rx_packets";
95 private static final String KEY_TX_BYTES = "tx_bytes";
96 private static final String KEY_TX_PACKETS = "tx_packets";
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070097
San Mehat873f2142010-01-14 10:25:07 -080098 class NetdResponseCode {
JP Abgrall12b933d2011-07-14 18:09:22 -070099 /* Keep in sync with system/netd/ResponseCode.h */
San Mehat873f2142010-01-14 10:25:07 -0800100 public static final int InterfaceListResult = 110;
101 public static final int TetherInterfaceListResult = 111;
102 public static final int TetherDnsFwdTgtListResult = 112;
San Mehat72759df2010-01-19 13:50:37 -0800103 public static final int TtyListResult = 113;
San Mehat873f2142010-01-14 10:25:07 -0800104
105 public static final int TetherStatusResult = 210;
106 public static final int IpFwdStatusResult = 211;
San Mehated4fc8a2010-01-22 12:28:36 -0800107 public static final int InterfaceGetCfgResult = 213;
Robert Greenwalte3253922010-02-18 09:23:25 -0800108 public static final int SoftapStatusResult = 214;
San Mehat91cac642010-03-31 14:31:36 -0700109 public static final int InterfaceRxCounterResult = 216;
110 public static final int InterfaceTxCounterResult = 217;
111 public static final int InterfaceRxThrottleResult = 218;
112 public static final int InterfaceTxThrottleResult = 219;
Robert Greenwalte3253922010-02-18 09:23:25 -0800113
114 public static final int InterfaceChange = 600;
JP Abgrall12b933d2011-07-14 18:09:22 -0700115 public static final int BandwidthControl = 601;
San Mehat873f2142010-01-14 10:25:07 -0800116 }
117
118 /**
119 * Binder context for this service
120 */
121 private Context mContext;
122
123 /**
124 * connector object for communicating with netd
125 */
126 private NativeDaemonConnector mConnector;
127
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700128 private Thread mThread;
129 private final CountDownLatch mConnectedSignal = new CountDownLatch(1);
130
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -0700131 // TODO: replace with RemoteCallbackList
San Mehat4d02d002010-01-22 16:07:46 -0800132 private ArrayList<INetworkManagementEventObserver> mObservers;
133
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -0700134 private Object mQuotaLock = new Object();
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -0700135 /** Set of interfaces with active quotas. */
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -0700136 private HashSet<String> mActiveQuotaIfaces = Sets.newHashSet();
137 /** Set of interfaces with active alerts. */
138 private HashSet<String> mActiveAlertIfaces = Sets.newHashSet();
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -0700139 /** Set of UIDs with active reject rules. */
140 private SparseBooleanArray mUidRejectOnQuota = new SparseBooleanArray();
141
Jeff Sharkey350083e2011-06-29 10:45:16 -0700142 private boolean mBandwidthControlEnabled;
143
San Mehat873f2142010-01-14 10:25:07 -0800144 /**
145 * Constructs a new NetworkManagementService instance
146 *
147 * @param context Binder context for this service
148 */
Jeff Sharkey4414cea2011-06-24 17:05:24 -0700149 private NetworkManagementService(Context context, File procRoot) {
San Mehat873f2142010-01-14 10:25:07 -0800150 mContext = context;
San Mehat4d02d002010-01-22 16:07:46 -0800151 mObservers = new ArrayList<INetworkManagementEventObserver>();
152
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700153 mStatsUid = new File(procRoot, "uid_stat");
154 mStatsIface = new File(procRoot, "net/dev");
155 mStatsXtUid = new File(procRoot, "net/xt_qtaguid/stats");
156 mStatsXtIface = new File(procRoot, "net/xt_qtaguid/iface_stat");
Jeff Sharkey4414cea2011-06-24 17:05:24 -0700157
Marco Nelissen62dbb222010-02-18 10:56:30 -0800158 if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
159 return;
160 }
161
San Mehat873f2142010-01-14 10:25:07 -0800162 mConnector = new NativeDaemonConnector(
Kenny Root305bcbf2010-09-03 07:56:38 -0700163 new NetdCallbackReceiver(), "netd", 10, NETD_TAG);
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700164 mThread = new Thread(mConnector, NETD_TAG);
165 }
166
167 public static NetworkManagementService create(Context context) throws InterruptedException {
Jeff Sharkey4414cea2011-06-24 17:05:24 -0700168 NetworkManagementService service = new NetworkManagementService(
169 context, new File("/proc/"));
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700170 if (DBG) Slog.d(TAG, "Creating NetworkManagementService");
171 service.mThread.start();
172 if (DBG) Slog.d(TAG, "Awaiting socket connection");
173 service.mConnectedSignal.await();
174 if (DBG) Slog.d(TAG, "Connected");
175 return service;
San Mehat873f2142010-01-14 10:25:07 -0800176 }
177
Jeff Sharkey4414cea2011-06-24 17:05:24 -0700178 // @VisibleForTesting
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700179 public static NetworkManagementService createForTest(
180 Context context, File procRoot, boolean bandwidthControlEnabled) {
Jeff Sharkey4414cea2011-06-24 17:05:24 -0700181 // TODO: eventually connect with mock netd
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700182 final NetworkManagementService service = new NetworkManagementService(context, procRoot);
183 service.mBandwidthControlEnabled = bandwidthControlEnabled;
184 return service;
Jeff Sharkey4414cea2011-06-24 17:05:24 -0700185 }
186
Jeff Sharkey350083e2011-06-29 10:45:16 -0700187 public void systemReady() {
188
189 // only enable bandwidth control when support exists, and requested by
190 // system setting.
Jeff Sharkey350083e2011-06-29 10:45:16 -0700191 final boolean hasKernelSupport = new File("/proc/net/xt_qtaguid/ctrl").exists();
192 final boolean shouldEnable =
Jeff Sharkey05355c32011-08-09 14:44:19 -0700193 Settings.Secure.getInt(mContext.getContentResolver(), NETSTATS_ENABLED, 1) != 0;
Jeff Sharkey350083e2011-06-29 10:45:16 -0700194
195 mBandwidthControlEnabled = false;
196 if (hasKernelSupport && shouldEnable) {
197 Slog.d(TAG, "enabling bandwidth control");
198 try {
199 mConnector.doCommand("bandwidth enable");
200 mBandwidthControlEnabled = true;
201 } catch (NativeDaemonConnectorException e) {
202 Slog.e(TAG, "problem enabling bandwidth controls", e);
203 }
204 } else {
205 Slog.d(TAG, "not enabling bandwidth control");
206 }
Jeff Sharkey62a2c8f2011-07-13 15:24:02 -0700207
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700208 SystemProperties.set(PROP_QTAGUID_ENABLED, mBandwidthControlEnabled ? "1" : "0");
Jeff Sharkey350083e2011-06-29 10:45:16 -0700209 }
210
San Mehat4d02d002010-01-22 16:07:46 -0800211 public void registerObserver(INetworkManagementEventObserver obs) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800212 Slog.d(TAG, "Registering observer");
San Mehat4d02d002010-01-22 16:07:46 -0800213 mObservers.add(obs);
214 }
215
216 public void unregisterObserver(INetworkManagementEventObserver obs) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800217 Slog.d(TAG, "Unregistering observer");
San Mehat4d02d002010-01-22 16:07:46 -0800218 mObservers.remove(mObservers.indexOf(obs));
219 }
220
221 /**
Mike J. Chen6143f5f2011-06-23 15:17:51 -0700222 * Notify our observers of an interface status change
San Mehat4d02d002010-01-22 16:07:46 -0800223 */
Mike J. Chen6143f5f2011-06-23 15:17:51 -0700224 private void notifyInterfaceStatusChanged(String iface, boolean up) {
San Mehat4d02d002010-01-22 16:07:46 -0800225 for (INetworkManagementEventObserver obs : mObservers) {
226 try {
Mike J. Chen6143f5f2011-06-23 15:17:51 -0700227 obs.interfaceStatusChanged(iface, up);
228 } catch (Exception ex) {
229 Slog.w(TAG, "Observer notifier failed", ex);
230 }
231 }
232 }
233
234 /**
Mike J. Chenf59c7d02011-06-23 15:33:15 -0700235 * Notify our observers of an interface link state change
Mike J. Chen6143f5f2011-06-23 15:17:51 -0700236 * (typically, an Ethernet cable has been plugged-in or unplugged).
237 */
238 private void notifyInterfaceLinkStateChanged(String iface, boolean up) {
239 for (INetworkManagementEventObserver obs : mObservers) {
240 try {
241 obs.interfaceLinkStateChanged(iface, up);
San Mehat4d02d002010-01-22 16:07:46 -0800242 } catch (Exception ex) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800243 Slog.w(TAG, "Observer notifier failed", ex);
San Mehat4d02d002010-01-22 16:07:46 -0800244 }
245 }
246 }
247
248 /**
249 * Notify our observers of an interface addition.
250 */
251 private void notifyInterfaceAdded(String iface) {
252 for (INetworkManagementEventObserver obs : mObservers) {
253 try {
254 obs.interfaceAdded(iface);
255 } catch (Exception ex) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800256 Slog.w(TAG, "Observer notifier failed", ex);
San Mehat4d02d002010-01-22 16:07:46 -0800257 }
258 }
259 }
260
261 /**
262 * Notify our observers of an interface removal.
263 */
264 private void notifyInterfaceRemoved(String iface) {
265 for (INetworkManagementEventObserver obs : mObservers) {
266 try {
267 obs.interfaceRemoved(iface);
268 } catch (Exception ex) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800269 Slog.w(TAG, "Observer notifier failed", ex);
San Mehat4d02d002010-01-22 16:07:46 -0800270 }
271 }
272 }
273
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700274 /**
JP Abgrall12b933d2011-07-14 18:09:22 -0700275 * Notify our observers of a limit reached.
276 */
277 private void notifyLimitReached(String limitName, String iface) {
278 for (INetworkManagementEventObserver obs : mObservers) {
279 try {
280 obs.limitReached(limitName, iface);
281 Slog.d(TAG, "Observer notified limit reached for " + limitName + " " + iface);
282 } catch (Exception ex) {
283 Slog.w(TAG, "Observer notifier failed", ex);
284 }
285 }
286 }
287
288 /**
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700289 * Let us know the daemon is connected
290 */
291 protected void onConnected() {
292 if (DBG) Slog.d(TAG, "onConnected");
293 mConnectedSignal.countDown();
294 }
295
San Mehat4d02d002010-01-22 16:07:46 -0800296
San Mehat873f2142010-01-14 10:25:07 -0800297 //
298 // Netd Callback handling
299 //
300
301 class NetdCallbackReceiver implements INativeDaemonConnectorCallbacks {
302 public void onDaemonConnected() {
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700303 NetworkManagementService.this.onConnected();
San Mehat873f2142010-01-14 10:25:07 -0800304 new Thread() {
305 public void run() {
San Mehat873f2142010-01-14 10:25:07 -0800306 }
307 }.start();
308 }
309 public boolean onEvent(int code, String raw, String[] cooked) {
JP Abgrall12b933d2011-07-14 18:09:22 -0700310 switch (code) {
311 case NetdResponseCode.InterfaceChange:
312 /*
313 * a network interface change occured
314 * Format: "NNN Iface added <name>"
315 * "NNN Iface removed <name>"
316 * "NNN Iface changed <name> <up/down>"
317 * "NNN Iface linkstatus <name> <up/down>"
318 */
319 if (cooked.length < 4 || !cooked[1].equals("Iface")) {
320 throw new IllegalStateException(
321 String.format("Invalid event from daemon (%s)", raw));
322 }
323 if (cooked[2].equals("added")) {
324 notifyInterfaceAdded(cooked[3]);
325 return true;
326 } else if (cooked[2].equals("removed")) {
327 notifyInterfaceRemoved(cooked[3]);
328 return true;
329 } else if (cooked[2].equals("changed") && cooked.length == 5) {
330 notifyInterfaceStatusChanged(cooked[3], cooked[4].equals("up"));
331 return true;
332 } else if (cooked[2].equals("linkstate") && cooked.length == 5) {
333 notifyInterfaceLinkStateChanged(cooked[3], cooked[4].equals("up"));
334 return true;
335 }
Robert Greenwalte3253922010-02-18 09:23:25 -0800336 throw new IllegalStateException(
337 String.format("Invalid event from daemon (%s)", raw));
JP Abgrall12b933d2011-07-14 18:09:22 -0700338 // break;
339 case NetdResponseCode.BandwidthControl:
340 /*
341 * Bandwidth control needs some attention
342 * Format: "NNN limit alert <alertName> <ifaceName>"
343 */
344 if (cooked.length < 5 || !cooked[1].equals("limit")) {
345 throw new IllegalStateException(
346 String.format("Invalid event from daemon (%s)", raw));
347 }
348 if (cooked[2].equals("alert")) {
349 notifyLimitReached(cooked[3], cooked[4]);
350 return true;
351 }
352 throw new IllegalStateException(
353 String.format("Invalid event from daemon (%s)", raw));
354 // break;
355 default: break;
Robert Greenwalte3253922010-02-18 09:23:25 -0800356 }
357 return false;
San Mehat873f2142010-01-14 10:25:07 -0800358 }
359 }
360
San Mehated4fc8a2010-01-22 12:28:36 -0800361
San Mehat873f2142010-01-14 10:25:07 -0800362 //
363 // INetworkManagementService members
364 //
365
366 public String[] listInterfaces() throws IllegalStateException {
367 mContext.enforceCallingOrSelfPermission(
368 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
369
Kenny Roota80ce062010-06-01 13:23:53 -0700370 try {
371 return mConnector.doListCommand("interface list", NetdResponseCode.InterfaceListResult);
372 } catch (NativeDaemonConnectorException e) {
373 throw new IllegalStateException(
374 "Cannot communicate with native daemon to list interfaces");
375 }
San Mehated4fc8a2010-01-22 12:28:36 -0800376 }
377
378 public InterfaceConfiguration getInterfaceConfig(String iface) throws IllegalStateException {
Kenny Roota80ce062010-06-01 13:23:53 -0700379 String rsp;
380 try {
381 rsp = mConnector.doCommand("interface getcfg " + iface).get(0);
382 } catch (NativeDaemonConnectorException e) {
383 throw new IllegalStateException(
384 "Cannot communicate with native daemon to get interface config");
385 }
Joe Onorato8a9b2202010-02-26 18:56:32 -0800386 Slog.d(TAG, String.format("rsp <%s>", rsp));
San Mehated4fc8a2010-01-22 12:28:36 -0800387
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800388 // Rsp: 213 xx:xx:xx:xx:xx:xx yyy.yyy.yyy.yyy zzz [flag1 flag2 flag3]
San Mehated4fc8a2010-01-22 12:28:36 -0800389 StringTokenizer st = new StringTokenizer(rsp);
390
Kenny Roota80ce062010-06-01 13:23:53 -0700391 InterfaceConfiguration cfg;
San Mehated4fc8a2010-01-22 12:28:36 -0800392 try {
Kenny Roota80ce062010-06-01 13:23:53 -0700393 try {
394 int code = Integer.parseInt(st.nextToken(" "));
395 if (code != NetdResponseCode.InterfaceGetCfgResult) {
396 throw new IllegalStateException(
397 String.format("Expected code %d, but got %d",
398 NetdResponseCode.InterfaceGetCfgResult, code));
399 }
400 } catch (NumberFormatException nfe) {
San Mehated4fc8a2010-01-22 12:28:36 -0800401 throw new IllegalStateException(
Kenny Roota80ce062010-06-01 13:23:53 -0700402 String.format("Invalid response from daemon (%s)", rsp));
San Mehated4fc8a2010-01-22 12:28:36 -0800403 }
Kenny Roota80ce062010-06-01 13:23:53 -0700404
405 cfg = new InterfaceConfiguration();
406 cfg.hwAddr = st.nextToken(" ");
Robert Greenwalted126402011-01-28 15:34:55 -0800407 InetAddress addr = null;
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800408 int prefixLength = 0;
Kenny Roota80ce062010-06-01 13:23:53 -0700409 try {
Robert Greenwalte5903732011-02-22 16:00:42 -0800410 addr = NetworkUtils.numericToInetAddress(st.nextToken(" "));
411 } catch (IllegalArgumentException iae) {
412 Slog.e(TAG, "Failed to parse ipaddr", iae);
Kenny Roota80ce062010-06-01 13:23:53 -0700413 }
414
415 try {
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800416 prefixLength = Integer.parseInt(st.nextToken(" "));
417 } catch (NumberFormatException nfe) {
418 Slog.e(TAG, "Failed to parse prefixLength", nfe);
Kenny Roota80ce062010-06-01 13:23:53 -0700419 }
Robert Greenwalt04808c22010-12-13 17:01:41 -0800420
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800421 cfg.addr = new LinkAddress(addr, prefixLength);
Kenny Roota80ce062010-06-01 13:23:53 -0700422 cfg.interfaceFlags = st.nextToken("]").trim() +"]";
423 } catch (NoSuchElementException nsee) {
San Mehated4fc8a2010-01-22 12:28:36 -0800424 throw new IllegalStateException(
425 String.format("Invalid response from daemon (%s)", rsp));
426 }
Joe Onorato8a9b2202010-02-26 18:56:32 -0800427 Slog.d(TAG, String.format("flags <%s>", cfg.interfaceFlags));
San Mehated4fc8a2010-01-22 12:28:36 -0800428 return cfg;
429 }
430
431 public void setInterfaceConfig(
432 String iface, InterfaceConfiguration cfg) throws IllegalStateException {
Robert Greenwalted126402011-01-28 15:34:55 -0800433 LinkAddress linkAddr = cfg.addr;
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800434 if (linkAddr == null || linkAddr.getAddress() == null) {
435 throw new IllegalStateException("Null LinkAddress given");
Robert Greenwalted126402011-01-28 15:34:55 -0800436 }
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800437 String cmd = String.format("interface setcfg %s %s %d %s", iface,
438 linkAddr.getAddress().getHostAddress(),
439 linkAddr.getNetworkPrefixLength(),
440 cfg.interfaceFlags);
Kenny Roota80ce062010-06-01 13:23:53 -0700441 try {
442 mConnector.doCommand(cmd);
443 } catch (NativeDaemonConnectorException e) {
444 throw new IllegalStateException(
Robert Greenwalt81d5ad52010-12-16 11:27:38 -0800445 "Unable to communicate with native daemon to interface setcfg - " + e);
Kenny Roota80ce062010-06-01 13:23:53 -0700446 }
San Mehat873f2142010-01-14 10:25:07 -0800447 }
448
Irfan Sheriff7244c972011-08-05 20:40:45 -0700449 public void setInterfaceDown(String iface) throws IllegalStateException {
450 try {
451 InterfaceConfiguration ifcg = getInterfaceConfig(iface);
452 ifcg.interfaceFlags = ifcg.interfaceFlags.replace("up", "down");
453 setInterfaceConfig(iface, ifcg);
454 } catch (NativeDaemonConnectorException e) {
455 throw new IllegalStateException(
456 "Unable to communicate with native daemon for interface down - " + e);
457 }
458 }
459
460 public void setInterfaceUp(String iface) throws IllegalStateException {
461 try {
462 InterfaceConfiguration ifcg = getInterfaceConfig(iface);
463 ifcg.interfaceFlags = ifcg.interfaceFlags.replace("down", "up");
464 setInterfaceConfig(iface, ifcg);
465 } catch (NativeDaemonConnectorException e) {
466 throw new IllegalStateException(
467 "Unable to communicate with native daemon for interface up - " + e);
468 }
469 }
470
Irfan Sherifff5600612011-06-16 10:26:28 -0700471 /* TODO: This is right now a IPv4 only function. Works for wifi which loses its
472 IPv6 addresses on interface down, but we need to do full clean up here */
473 public void clearInterfaceAddresses(String iface) throws IllegalStateException {
474 String cmd = String.format("interface clearaddrs %s", iface);
475 try {
476 mConnector.doCommand(cmd);
477 } catch (NativeDaemonConnectorException e) {
478 throw new IllegalStateException(
479 "Unable to communicate with native daemon to interface clearallips - " + e);
480 }
481 }
482
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -0700483 public void addRoute(String interfaceName, RouteInfo route) {
484 modifyRoute(interfaceName, ADD, route);
485 }
486
487 public void removeRoute(String interfaceName, RouteInfo route) {
488 modifyRoute(interfaceName, REMOVE, route);
489 }
490
491 private void modifyRoute(String interfaceName, int action, RouteInfo route) {
492 ArrayList<String> rsp;
493
494 StringBuilder cmd;
495
496 switch (action) {
497 case ADD:
498 {
499 cmd = new StringBuilder("interface route add " + interfaceName);
500 break;
501 }
502 case REMOVE:
503 {
504 cmd = new StringBuilder("interface route remove " + interfaceName);
505 break;
506 }
507 default:
508 throw new IllegalStateException("Unknown action type " + action);
509 }
510
511 // create triplet: dest-ip-addr prefixlength gateway-ip-addr
512 LinkAddress la = route.getDestination();
513 cmd.append(' ');
514 cmd.append(la.getAddress().getHostAddress());
515 cmd.append(' ');
516 cmd.append(la.getNetworkPrefixLength());
517 cmd.append(' ');
518 if (route.getGateway() == null) {
519 if (la.getAddress() instanceof Inet4Address) {
520 cmd.append("0.0.0.0");
521 } else {
522 cmd.append ("::0");
523 }
524 } else {
525 cmd.append(route.getGateway().getHostAddress());
526 }
527 try {
528 rsp = mConnector.doCommand(cmd.toString());
529 } catch (NativeDaemonConnectorException e) {
530 throw new IllegalStateException(
531 "Unable to communicate with native dameon to add routes - "
532 + e);
533 }
534
535 for (String line : rsp) {
536 Log.v(TAG, "add route response is " + line);
537 }
538 }
539
540 private ArrayList<String> readRouteList(String filename) {
541 FileInputStream fstream = null;
542 ArrayList<String> list = new ArrayList<String>();
543
544 try {
545 fstream = new FileInputStream(filename);
546 DataInputStream in = new DataInputStream(fstream);
547 BufferedReader br = new BufferedReader(new InputStreamReader(in));
548 String s;
549
550 // throw away the title line
551
552 while (((s = br.readLine()) != null) && (s.length() != 0)) {
553 list.add(s);
554 }
555 } catch (IOException ex) {
556 // return current list, possibly empty
557 } finally {
558 if (fstream != null) {
559 try {
560 fstream.close();
561 } catch (IOException ex) {}
562 }
563 }
564
565 return list;
566 }
567
568 public RouteInfo[] getRoutes(String interfaceName) {
569 ArrayList<RouteInfo> routes = new ArrayList<RouteInfo>();
570
571 // v4 routes listed as:
572 // iface dest-addr gateway-addr flags refcnt use metric netmask mtu window IRTT
573 for (String s : readRouteList("/proc/net/route")) {
574 String[] fields = s.split("\t");
575
576 if (fields.length > 7) {
577 String iface = fields[0];
578
579 if (interfaceName.equals(iface)) {
580 String dest = fields[1];
581 String gate = fields[2];
582 String flags = fields[3]; // future use?
583 String mask = fields[7];
584 try {
585 // address stored as a hex string, ex: 0014A8C0
586 InetAddress destAddr =
587 NetworkUtils.intToInetAddress((int)Long.parseLong(dest, 16));
588 int prefixLength =
589 NetworkUtils.netmaskIntToPrefixLength(
590 (int)Long.parseLong(mask, 16));
591 LinkAddress linkAddress = new LinkAddress(destAddr, prefixLength);
592
593 // address stored as a hex string, ex 0014A8C0
594 InetAddress gatewayAddr =
595 NetworkUtils.intToInetAddress((int)Long.parseLong(gate, 16));
596
597 RouteInfo route = new RouteInfo(linkAddress, gatewayAddr);
598 routes.add(route);
599 } catch (Exception e) {
600 Log.e(TAG, "Error parsing route " + s + " : " + e);
601 continue;
602 }
603 }
604 }
605 }
606
607 // v6 routes listed as:
608 // dest-addr prefixlength ?? ?? gateway-addr ?? ?? ?? ?? iface
609 for (String s : readRouteList("/proc/net/ipv6_route")) {
610 String[]fields = s.split("\\s+");
611 if (fields.length > 9) {
612 String iface = fields[9].trim();
613 if (interfaceName.equals(iface)) {
614 String dest = fields[0];
615 String prefix = fields[1];
616 String gate = fields[4];
617
618 try {
619 // prefix length stored as a hex string, ex 40
620 int prefixLength = Integer.parseInt(prefix, 16);
621
622 // address stored as a 32 char hex string
623 // ex fe800000000000000000000000000000
624 InetAddress destAddr = NetworkUtils.hexToInet6Address(dest);
625 LinkAddress linkAddress = new LinkAddress(destAddr, prefixLength);
626
627 InetAddress gateAddr = NetworkUtils.hexToInet6Address(gate);
628
629 RouteInfo route = new RouteInfo(linkAddress, gateAddr);
630 routes.add(route);
631 } catch (Exception e) {
632 Log.e(TAG, "Error parsing route " + s + " : " + e);
633 continue;
634 }
635 }
636 }
637 }
638 return (RouteInfo[]) routes.toArray(new RouteInfo[0]);
639 }
640
San Mehat873f2142010-01-14 10:25:07 -0800641 public void shutdown() {
642 if (mContext.checkCallingOrSelfPermission(
643 android.Manifest.permission.SHUTDOWN)
644 != PackageManager.PERMISSION_GRANTED) {
645 throw new SecurityException("Requires SHUTDOWN permission");
646 }
647
Joe Onorato8a9b2202010-02-26 18:56:32 -0800648 Slog.d(TAG, "Shutting down");
San Mehat873f2142010-01-14 10:25:07 -0800649 }
650
651 public boolean getIpForwardingEnabled() throws IllegalStateException{
652 mContext.enforceCallingOrSelfPermission(
653 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
654
Kenny Roota80ce062010-06-01 13:23:53 -0700655 ArrayList<String> rsp;
656 try {
657 rsp = mConnector.doCommand("ipfwd status");
658 } catch (NativeDaemonConnectorException e) {
659 throw new IllegalStateException(
660 "Unable to communicate with native daemon to ipfwd status");
661 }
San Mehat873f2142010-01-14 10:25:07 -0800662
663 for (String line : rsp) {
Kenny Roota80ce062010-06-01 13:23:53 -0700664 String[] tok = line.split(" ");
665 if (tok.length < 3) {
666 Slog.e(TAG, "Malformed response from native daemon: " + line);
667 return false;
668 }
669
San Mehat873f2142010-01-14 10:25:07 -0800670 int code = Integer.parseInt(tok[0]);
671 if (code == NetdResponseCode.IpFwdStatusResult) {
672 // 211 Forwarding <enabled/disabled>
Kenny Roota80ce062010-06-01 13:23:53 -0700673 return "enabled".equals(tok[2]);
San Mehat873f2142010-01-14 10:25:07 -0800674 } else {
675 throw new IllegalStateException(String.format("Unexpected response code %d", code));
676 }
677 }
678 throw new IllegalStateException("Got an empty response");
679 }
680
681 public void setIpForwardingEnabled(boolean enable) throws IllegalStateException {
682 mContext.enforceCallingOrSelfPermission(
683 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
684 mConnector.doCommand(String.format("ipfwd %sable", (enable ? "en" : "dis")));
685 }
686
Robert Greenwaltbfb7bfa2010-03-24 16:03:21 -0700687 public void startTethering(String[] dhcpRange)
San Mehat873f2142010-01-14 10:25:07 -0800688 throws IllegalStateException {
689 mContext.enforceCallingOrSelfPermission(
690 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Robert Greenwaltbfb7bfa2010-03-24 16:03:21 -0700691 // cmd is "tether start first_start first_stop second_start second_stop ..."
692 // an odd number of addrs will fail
693 String cmd = "tether start";
694 for (String d : dhcpRange) {
695 cmd += " " + d;
696 }
Kenny Roota80ce062010-06-01 13:23:53 -0700697
698 try {
699 mConnector.doCommand(cmd);
700 } catch (NativeDaemonConnectorException e) {
701 throw new IllegalStateException("Unable to communicate to native daemon");
702 }
San Mehat873f2142010-01-14 10:25:07 -0800703 }
704
705 public void stopTethering() 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("tether stop");
710 } catch (NativeDaemonConnectorException e) {
711 throw new IllegalStateException("Unable to communicate to native daemon to stop tether");
712 }
San Mehat873f2142010-01-14 10:25:07 -0800713 }
714
715 public boolean isTetheringStarted() throws IllegalStateException {
716 mContext.enforceCallingOrSelfPermission(
717 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
718
Kenny Roota80ce062010-06-01 13:23:53 -0700719 ArrayList<String> rsp;
720 try {
721 rsp = mConnector.doCommand("tether status");
722 } catch (NativeDaemonConnectorException e) {
723 throw new IllegalStateException(
724 "Unable to communicate to native daemon to get tether status");
725 }
San Mehat873f2142010-01-14 10:25:07 -0800726
727 for (String line : rsp) {
Kenny Roota80ce062010-06-01 13:23:53 -0700728 String[] tok = line.split(" ");
729 if (tok.length < 3) {
730 throw new IllegalStateException("Malformed response for tether status: " + line);
731 }
San Mehat873f2142010-01-14 10:25:07 -0800732 int code = Integer.parseInt(tok[0]);
733 if (code == NetdResponseCode.TetherStatusResult) {
734 // XXX: Tethering services <started/stopped> <TBD>...
Kenny Roota80ce062010-06-01 13:23:53 -0700735 return "started".equals(tok[2]);
San Mehat873f2142010-01-14 10:25:07 -0800736 } else {
737 throw new IllegalStateException(String.format("Unexpected response code %d", code));
738 }
739 }
740 throw new IllegalStateException("Got an empty response");
741 }
742
743 public void tetherInterface(String iface) throws IllegalStateException {
744 mContext.enforceCallingOrSelfPermission(
745 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700746 try {
747 mConnector.doCommand("tether interface add " + iface);
748 } catch (NativeDaemonConnectorException e) {
749 throw new IllegalStateException(
750 "Unable to communicate to native daemon for adding tether interface");
751 }
San Mehat873f2142010-01-14 10:25:07 -0800752 }
753
754 public void untetherInterface(String iface) {
755 mContext.enforceCallingOrSelfPermission(
756 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700757 try {
758 mConnector.doCommand("tether interface remove " + iface);
759 } catch (NativeDaemonConnectorException e) {
760 throw new IllegalStateException(
761 "Unable to communicate to native daemon for removing tether interface");
762 }
San Mehat873f2142010-01-14 10:25:07 -0800763 }
764
765 public String[] listTetheredInterfaces() throws IllegalStateException {
766 mContext.enforceCallingOrSelfPermission(
767 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700768 try {
769 return mConnector.doListCommand(
770 "tether interface list", NetdResponseCode.TetherInterfaceListResult);
771 } catch (NativeDaemonConnectorException e) {
772 throw new IllegalStateException(
773 "Unable to communicate to native daemon for listing tether interfaces");
774 }
San Mehat873f2142010-01-14 10:25:07 -0800775 }
776
777 public void setDnsForwarders(String[] dns) throws IllegalStateException {
778 mContext.enforceCallingOrSelfPermission(
779 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
780 try {
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800781 String cmd = "tether dns set";
San Mehat873f2142010-01-14 10:25:07 -0800782 for (String s : dns) {
Robert Greenwalte5903732011-02-22 16:00:42 -0800783 cmd += " " + NetworkUtils.numericToInetAddress(s).getHostAddress();
San Mehat873f2142010-01-14 10:25:07 -0800784 }
Kenny Roota80ce062010-06-01 13:23:53 -0700785 try {
786 mConnector.doCommand(cmd);
787 } catch (NativeDaemonConnectorException e) {
788 throw new IllegalStateException(
789 "Unable to communicate to native daemon for setting tether dns");
790 }
Robert Greenwalte5903732011-02-22 16:00:42 -0800791 } catch (IllegalArgumentException e) {
San Mehat873f2142010-01-14 10:25:07 -0800792 throw new IllegalStateException("Error resolving dns name", e);
793 }
794 }
795
796 public String[] getDnsForwarders() throws IllegalStateException {
797 mContext.enforceCallingOrSelfPermission(
798 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700799 try {
800 return mConnector.doListCommand(
801 "tether dns list", NetdResponseCode.TetherDnsFwdTgtListResult);
802 } catch (NativeDaemonConnectorException e) {
803 throw new IllegalStateException(
804 "Unable to communicate to native daemon for listing tether dns");
805 }
San Mehat873f2142010-01-14 10:25:07 -0800806 }
807
808 public void enableNat(String internalInterface, String externalInterface)
809 throws IllegalStateException {
810 mContext.enforceCallingOrSelfPermission(
811 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700812 try {
813 mConnector.doCommand(
814 String.format("nat enable %s %s", internalInterface, externalInterface));
815 } catch (NativeDaemonConnectorException e) {
816 throw new IllegalStateException(
817 "Unable to communicate to native daemon for enabling NAT interface");
818 }
San Mehat873f2142010-01-14 10:25:07 -0800819 }
820
821 public void disableNat(String internalInterface, String externalInterface)
822 throws IllegalStateException {
823 mContext.enforceCallingOrSelfPermission(
824 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700825 try {
826 mConnector.doCommand(
827 String.format("nat disable %s %s", internalInterface, externalInterface));
828 } catch (NativeDaemonConnectorException e) {
829 throw new IllegalStateException(
830 "Unable to communicate to native daemon for disabling NAT interface");
831 }
San Mehat873f2142010-01-14 10:25:07 -0800832 }
San Mehat72759df2010-01-19 13:50:37 -0800833
834 public String[] listTtys() throws IllegalStateException {
835 mContext.enforceCallingOrSelfPermission(
836 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700837 try {
838 return mConnector.doListCommand("list_ttys", NetdResponseCode.TtyListResult);
839 } catch (NativeDaemonConnectorException e) {
840 throw new IllegalStateException(
841 "Unable to communicate to native daemon for listing TTYs");
842 }
San Mehat72759df2010-01-19 13:50:37 -0800843 }
844
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800845 public void attachPppd(String tty, String localAddr, String remoteAddr, String dns1Addr,
846 String dns2Addr) throws IllegalStateException {
San Mehat72759df2010-01-19 13:50:37 -0800847 try {
848 mContext.enforceCallingOrSelfPermission(
849 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800850 mConnector.doCommand(String.format("pppd attach %s %s %s %s %s", tty,
Robert Greenwalte5903732011-02-22 16:00:42 -0800851 NetworkUtils.numericToInetAddress(localAddr).getHostAddress(),
852 NetworkUtils.numericToInetAddress(remoteAddr).getHostAddress(),
853 NetworkUtils.numericToInetAddress(dns1Addr).getHostAddress(),
854 NetworkUtils.numericToInetAddress(dns2Addr).getHostAddress()));
855 } catch (IllegalArgumentException e) {
San Mehat72759df2010-01-19 13:50:37 -0800856 throw new IllegalStateException("Error resolving addr", e);
Kenny Roota80ce062010-06-01 13:23:53 -0700857 } catch (NativeDaemonConnectorException e) {
858 throw new IllegalStateException("Error communicating to native daemon to attach pppd", e);
San Mehat72759df2010-01-19 13:50:37 -0800859 }
860 }
861
862 public void detachPppd(String tty) throws IllegalStateException {
863 mContext.enforceCallingOrSelfPermission(
864 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700865 try {
866 mConnector.doCommand(String.format("pppd detach %s", tty));
867 } catch (NativeDaemonConnectorException e) {
868 throw new IllegalStateException("Error communicating to native daemon to detach pppd", e);
869 }
San Mehat72759df2010-01-19 13:50:37 -0800870 }
Robert Greenwaltce1200d2010-02-18 11:25:54 -0800871
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700872 public void startAccessPoint(WifiConfiguration wifiConfig, String wlanIface, String softapIface)
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800873 throws IllegalStateException {
874 mContext.enforceCallingOrSelfPermission(
875 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
876 mContext.enforceCallingOrSelfPermission(
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700877 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700878 try {
Irfan Sheriffcb30b222011-07-29 20:54:52 -0700879 wifiFirmwareReload(wlanIface, "AP");
Kenny Roota80ce062010-06-01 13:23:53 -0700880 mConnector.doCommand(String.format("softap start " + wlanIface));
881 if (wifiConfig == null) {
882 mConnector.doCommand(String.format("softap set " + wlanIface + " " + softapIface));
883 } else {
884 /**
885 * softap set arg1 arg2 arg3 [arg4 arg5 arg6 arg7 arg8]
886 * argv1 - wlan interface
887 * argv2 - softap interface
888 * argv3 - SSID
889 * argv4 - Security
890 * argv5 - Key
891 * argv6 - Channel
892 * argv7 - Preamble
893 * argv8 - Max SCB
894 */
Irfan Sheriffec8d23a2011-02-16 17:00:33 -0800895 String str = String.format("softap set " + wlanIface + " " + softapIface +
896 " %s %s %s", convertQuotedString(wifiConfig.SSID),
897 getSecurityType(wifiConfig),
898 convertQuotedString(wifiConfig.preSharedKey));
Kenny Roota80ce062010-06-01 13:23:53 -0700899 mConnector.doCommand(str);
900 }
901 mConnector.doCommand(String.format("softap startap"));
902 } catch (NativeDaemonConnectorException e) {
903 throw new IllegalStateException("Error communicating to native daemon to start softap", e);
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -0800904 }
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800905 }
906
Irfan Sheriffa6e559e2010-05-24 14:55:42 -0700907 private String convertQuotedString(String s) {
Irfan Sheriff7baec0f2010-05-26 17:16:47 -0700908 if (s == null) {
909 return s;
910 }
911 /* Replace \ with \\, then " with \" and add quotes at end */
912 return '"' + s.replaceAll("\\\\","\\\\\\\\").replaceAll("\"","\\\\\"") + '"';
Irfan Sheriffa6e559e2010-05-24 14:55:42 -0700913 }
914
Irfan Sheriffec8d23a2011-02-16 17:00:33 -0800915 private String getSecurityType(WifiConfiguration wifiConfig) {
916 switch (wifiConfig.getAuthType()) {
917 case KeyMgmt.WPA_PSK:
918 return "wpa-psk";
919 case KeyMgmt.WPA2_PSK:
920 return "wpa2-psk";
921 default:
922 return "open";
923 }
924 }
925
Irfan Sheriffcb30b222011-07-29 20:54:52 -0700926 /* @param mode can be "AP", "STA" or "P2P" */
927 public void wifiFirmwareReload(String wlanIface, String mode) throws IllegalStateException {
928 mContext.enforceCallingOrSelfPermission(
929 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
930 mContext.enforceCallingOrSelfPermission(
931 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
932
933 try {
934 mConnector.doCommand(String.format("softap fwreload " + wlanIface + " " + mode));
935 } catch (NativeDaemonConnectorException e) {
936 throw new IllegalStateException("Error communicating to native daemon ", e);
937 }
938 }
939
Irfan Sheriff23eb2972011-07-22 15:21:10 -0700940 public void stopAccessPoint(String wlanIface) throws IllegalStateException {
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800941 mContext.enforceCallingOrSelfPermission(
942 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
943 mContext.enforceCallingOrSelfPermission(
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700944 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700945 try {
946 mConnector.doCommand("softap stopap");
Irfan Sheriff23eb2972011-07-22 15:21:10 -0700947 mConnector.doCommand("softap stop " + wlanIface);
Irfan Sheriffcb30b222011-07-29 20:54:52 -0700948 wifiFirmwareReload(wlanIface, "STA");
Kenny Roota80ce062010-06-01 13:23:53 -0700949 } catch (NativeDaemonConnectorException e) {
950 throw new IllegalStateException("Error communicating to native daemon to stop soft AP",
951 e);
952 }
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800953 }
954
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700955 public void setAccessPoint(WifiConfiguration wifiConfig, String wlanIface, String softapIface)
956 throws IllegalStateException {
957 mContext.enforceCallingOrSelfPermission(
958 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
959 mContext.enforceCallingOrSelfPermission(
960 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700961 try {
962 if (wifiConfig == null) {
963 mConnector.doCommand(String.format("softap set " + wlanIface + " " + softapIface));
964 } else {
965 String str = String.format("softap set " + wlanIface + " " + softapIface
966 + " %s %s %s", convertQuotedString(wifiConfig.SSID),
Irfan Sheriffec8d23a2011-02-16 17:00:33 -0800967 getSecurityType(wifiConfig),
Kenny Roota80ce062010-06-01 13:23:53 -0700968 convertQuotedString(wifiConfig.preSharedKey));
969 mConnector.doCommand(str);
970 }
971 } catch (NativeDaemonConnectorException e) {
972 throw new IllegalStateException("Error communicating to native daemon to set soft AP",
973 e);
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700974 }
975 }
San Mehat91cac642010-03-31 14:31:36 -0700976
977 private long getInterfaceCounter(String iface, boolean rx) {
978 mContext.enforceCallingOrSelfPermission(
979 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
980 try {
Kenny Roota80ce062010-06-01 13:23:53 -0700981 String rsp;
982 try {
983 rsp = mConnector.doCommand(
984 String.format("interface read%scounter %s", (rx ? "rx" : "tx"), iface)).get(0);
985 } catch (NativeDaemonConnectorException e1) {
986 Slog.e(TAG, "Error communicating with native daemon", e1);
987 return -1;
988 }
989
990 String[] tok = rsp.split(" ");
991 if (tok.length < 2) {
992 Slog.e(TAG, String.format("Malformed response for reading %s interface",
993 (rx ? "rx" : "tx")));
994 return -1;
995 }
996
San Mehat91cac642010-03-31 14:31:36 -0700997 int code;
998 try {
999 code = Integer.parseInt(tok[0]);
1000 } catch (NumberFormatException nfe) {
1001 Slog.e(TAG, String.format("Error parsing code %s", tok[0]));
1002 return -1;
1003 }
1004 if ((rx && code != NetdResponseCode.InterfaceRxCounterResult) || (
1005 !rx && code != NetdResponseCode.InterfaceTxCounterResult)) {
1006 Slog.e(TAG, String.format("Unexpected response code %d", code));
1007 return -1;
1008 }
1009 return Long.parseLong(tok[1]);
1010 } catch (Exception e) {
1011 Slog.e(TAG, String.format(
1012 "Failed to read interface %s counters", (rx ? "rx" : "tx")), e);
1013 }
1014 return -1;
1015 }
1016
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001017 @Override
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001018 public NetworkStats getNetworkStatsSummary() {
1019 mContext.enforceCallingOrSelfPermission(
1020 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
1021
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001022 final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6);
1023 final NetworkStats.Entry entry = new NetworkStats.Entry();
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001024
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001025 final HashSet<String> activeIfaces = Sets.newHashSet();
1026 final ArrayList<String> values = Lists.newArrayList();
1027
1028 BufferedReader reader = null;
1029 try {
1030 reader = new BufferedReader(new FileReader(mStatsIface));
1031
1032 // skip first two header lines
1033 reader.readLine();
1034 reader.readLine();
1035
1036 // parse remaining lines
1037 String line;
1038 while ((line = reader.readLine()) != null) {
1039 splitLine(line, values);
1040
1041 try {
1042 entry.iface = values.get(0);
1043 entry.uid = UID_ALL;
1044 entry.tag = TAG_NONE;
1045 entry.rxBytes = Long.parseLong(values.get(1));
1046 entry.rxPackets = Long.parseLong(values.get(2));
1047 entry.txBytes = Long.parseLong(values.get(9));
1048 entry.txPackets = Long.parseLong(values.get(10));
1049
1050 activeIfaces.add(entry.iface);
1051 stats.addValues(entry);
1052 } catch (NumberFormatException e) {
1053 Slog.w(TAG, "problem parsing stats row '" + line + "': " + e);
1054 }
1055 }
1056 } catch (IOException e) {
1057 Slog.w(TAG, "problem parsing stats: " + e);
1058 } finally {
1059 IoUtils.closeQuietly(reader);
1060 }
1061
1062 if (DBG) Slog.d(TAG, "recorded active stats from " + activeIfaces);
1063
1064 // splice in stats from any disabled ifaces
1065 if (mBandwidthControlEnabled) {
1066 final HashSet<String> xtIfaces = Sets.newHashSet(fileListWithoutNull(mStatsXtIface));
1067 xtIfaces.removeAll(activeIfaces);
1068
1069 for (String iface : xtIfaces) {
1070 final File ifacePath = new File(mStatsXtIface, iface);
1071
1072 entry.iface = iface;
1073 entry.uid = UID_ALL;
1074 entry.tag = TAG_NONE;
1075 entry.rxBytes = readSingleLongFromFile(new File(ifacePath, "rx_bytes"));
1076 entry.rxPackets = readSingleLongFromFile(new File(ifacePath, "rx_packets"));
1077 entry.txBytes = readSingleLongFromFile(new File(ifacePath, "tx_bytes"));
1078 entry.txPackets = readSingleLongFromFile(new File(ifacePath, "tx_packets"));
1079
1080 stats.addValues(entry);
1081 }
1082
1083 if (DBG) Slog.d(TAG, "recorded stale stats from " + xtIfaces);
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001084 }
1085
Jeff Sharkey4a971222011-06-11 22:16:55 -07001086 return stats;
San Mehat91cac642010-03-31 14:31:36 -07001087 }
1088
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001089 @Override
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001090 public NetworkStats getNetworkStatsDetail() {
1091 mContext.enforceCallingOrSelfPermission(
1092 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
1093
Jeff Sharkey350083e2011-06-29 10:45:16 -07001094 if (mBandwidthControlEnabled) {
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001095 return getNetworkStatsDetailNetfilter(UID_ALL);
1096 } else {
1097 return getNetworkStatsDetailUidstat(UID_ALL);
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001098 }
San Mehat91cac642010-03-31 14:31:36 -07001099 }
1100
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001101 @Override
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001102 public void setInterfaceQuota(String iface, long quotaBytes) {
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001103 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1104
Jeff Sharkey350083e2011-06-29 10:45:16 -07001105 // silently discard when control disabled
1106 // TODO: eventually migrate to be always enabled
1107 if (!mBandwidthControlEnabled) return;
1108
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001109 synchronized (mQuotaLock) {
1110 if (mActiveQuotaIfaces.contains(iface)) {
1111 throw new IllegalStateException("iface " + iface + " already has quota");
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001112 }
1113
1114 final StringBuilder command = new StringBuilder();
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001115 command.append("bandwidth setiquota ").append(iface).append(" ").append(quotaBytes);
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001116
1117 try {
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001118 // TODO: support quota shared across interfaces
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001119 mConnector.doCommand(command.toString());
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001120 mActiveQuotaIfaces.add(iface);
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001121 } catch (NativeDaemonConnectorException e) {
1122 throw new IllegalStateException("Error communicating to native daemon", e);
1123 }
Ashish Sharma50fd36d2011-06-15 19:34:53 -07001124 }
1125 }
1126
1127 @Override
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001128 public void removeInterfaceQuota(String iface) {
1129 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1130
Jeff Sharkey350083e2011-06-29 10:45:16 -07001131 // silently discard when control disabled
1132 // TODO: eventually migrate to be always enabled
1133 if (!mBandwidthControlEnabled) return;
1134
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001135 synchronized (mQuotaLock) {
1136 if (!mActiveQuotaIfaces.contains(iface)) {
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001137 // TODO: eventually consider throwing
1138 return;
1139 }
1140
1141 final StringBuilder command = new StringBuilder();
1142 command.append("bandwidth removeiquota ").append(iface);
1143
1144 try {
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001145 // TODO: support quota shared across interfaces
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001146 mConnector.doCommand(command.toString());
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001147 mActiveQuotaIfaces.remove(iface);
1148 mActiveAlertIfaces.remove(iface);
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001149 } catch (NativeDaemonConnectorException e) {
1150 throw new IllegalStateException("Error communicating to native daemon", e);
1151 }
1152 }
1153 }
1154
1155 @Override
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001156 public void setInterfaceAlert(String iface, long alertBytes) {
1157 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1158
1159 // silently discard when control disabled
1160 // TODO: eventually migrate to be always enabled
1161 if (!mBandwidthControlEnabled) return;
1162
1163 // quick sanity check
1164 if (!mActiveQuotaIfaces.contains(iface)) {
1165 throw new IllegalStateException("setting alert requires existing quota on iface");
1166 }
1167
1168 synchronized (mQuotaLock) {
1169 if (mActiveAlertIfaces.contains(iface)) {
1170 throw new IllegalStateException("iface " + iface + " already has alert");
1171 }
1172
1173 final StringBuilder command = new StringBuilder();
1174 command.append("bandwidth setinterfacealert ").append(iface).append(" ").append(
1175 alertBytes);
1176
1177 try {
1178 // TODO: support alert shared across interfaces
1179 mConnector.doCommand(command.toString());
1180 mActiveAlertIfaces.add(iface);
1181 } catch (NativeDaemonConnectorException e) {
1182 throw new IllegalStateException("Error communicating to native daemon", e);
1183 }
1184 }
1185 }
1186
1187 @Override
1188 public void removeInterfaceAlert(String iface) {
1189 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1190
1191 // silently discard when control disabled
1192 // TODO: eventually migrate to be always enabled
1193 if (!mBandwidthControlEnabled) return;
1194
1195 synchronized (mQuotaLock) {
1196 if (!mActiveAlertIfaces.contains(iface)) {
1197 // TODO: eventually consider throwing
1198 return;
1199 }
1200
1201 final StringBuilder command = new StringBuilder();
1202 command.append("bandwidth removeinterfacealert ").append(iface);
1203
1204 try {
1205 // TODO: support alert shared across interfaces
1206 mConnector.doCommand(command.toString());
1207 mActiveAlertIfaces.remove(iface);
1208 } catch (NativeDaemonConnectorException e) {
1209 throw new IllegalStateException("Error communicating to native daemon", e);
1210 }
1211 }
1212 }
1213
1214 @Override
1215 public void setGlobalAlert(long alertBytes) {
1216 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1217
1218 // silently discard when control disabled
1219 // TODO: eventually migrate to be always enabled
1220 if (!mBandwidthControlEnabled) return;
1221
1222 final StringBuilder command = new StringBuilder();
1223 command.append("bandwidth setglobalalert ").append(alertBytes);
1224
1225 try {
1226 mConnector.doCommand(command.toString());
1227 } catch (NativeDaemonConnectorException e) {
1228 throw new IllegalStateException("Error communicating to native daemon", e);
1229 }
1230 }
1231
1232 @Override
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001233 public void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces) {
1234 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1235
Jeff Sharkey350083e2011-06-29 10:45:16 -07001236 // silently discard when control disabled
1237 // TODO: eventually migrate to be always enabled
1238 if (!mBandwidthControlEnabled) return;
1239
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001240 synchronized (mUidRejectOnQuota) {
1241 final boolean oldRejectOnQuota = mUidRejectOnQuota.get(uid, false);
1242 if (oldRejectOnQuota == rejectOnQuotaInterfaces) {
1243 // TODO: eventually consider throwing
1244 return;
1245 }
1246
1247 final StringBuilder command = new StringBuilder();
1248 command.append("bandwidth");
1249 if (rejectOnQuotaInterfaces) {
1250 command.append(" addnaughtyapps");
1251 } else {
1252 command.append(" removenaughtyapps");
1253 }
1254 command.append(" ").append(uid);
1255
1256 try {
1257 mConnector.doCommand(command.toString());
1258 if (rejectOnQuotaInterfaces) {
1259 mUidRejectOnQuota.put(uid, true);
1260 } else {
1261 mUidRejectOnQuota.delete(uid);
1262 }
1263 } catch (NativeDaemonConnectorException e) {
1264 throw new IllegalStateException("Error communicating to native daemon", e);
1265 }
Ashish Sharma50fd36d2011-06-15 19:34:53 -07001266 }
1267 }
1268
Jeff Sharkey63d27a92011-08-03 17:04:22 -07001269 @Override
1270 public boolean isBandwidthControlEnabled() {
1271 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1272 return mBandwidthControlEnabled;
1273 }
1274
1275 @Override
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001276 public NetworkStats getNetworkStatsUidDetail(int uid) {
1277 if (Binder.getCallingUid() != uid) {
1278 mContext.enforceCallingOrSelfPermission(
1279 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
1280 }
1281
Jeff Sharkey350083e2011-06-29 10:45:16 -07001282 if (mBandwidthControlEnabled) {
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001283 return getNetworkStatsDetailNetfilter(uid);
1284 } else {
1285 return getNetworkStatsDetailUidstat(uid);
1286 }
1287 }
1288
1289 /**
1290 * Build {@link NetworkStats} with detailed UID statistics.
1291 */
1292 private NetworkStats getNetworkStatsDetailNetfilter(int limitUid) {
1293 final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 24);
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001294 final NetworkStats.Entry entry = new NetworkStats.Entry();
1295
Jeff Sharkeya63ba592011-07-19 23:47:12 -07001296 // TODO: remove knownLines check once 5087722 verified
1297 final HashSet<String> knownLines = Sets.newHashSet();
1298
Jeff Sharkey4414cea2011-06-24 17:05:24 -07001299 final ArrayList<String> keys = Lists.newArrayList();
1300 final ArrayList<String> values = Lists.newArrayList();
1301 final HashMap<String, String> parsed = Maps.newHashMap();
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001302
1303 BufferedReader reader = null;
1304 try {
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001305 reader = new BufferedReader(new FileReader(mStatsXtUid));
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001306
Jeff Sharkey4414cea2011-06-24 17:05:24 -07001307 // parse first line as header
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001308 String line = reader.readLine();
Jeff Sharkey4414cea2011-06-24 17:05:24 -07001309 splitLine(line, keys);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001310
Jeff Sharkey4414cea2011-06-24 17:05:24 -07001311 // parse remaining lines
1312 while ((line = reader.readLine()) != null) {
1313 splitLine(line, values);
1314 parseLine(keys, values, parsed);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001315
Jeff Sharkeya63ba592011-07-19 23:47:12 -07001316 if (!knownLines.add(line)) {
1317 throw new IllegalStateException("encountered duplicate proc entry");
1318 }
1319
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001320 try {
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001321 entry.iface = parsed.get(KEY_IFACE);
Jeff Sharkeya63ba592011-07-19 23:47:12 -07001322 entry.tag = kernelToTag(parsed.get(KEY_TAG_HEX));
1323 entry.uid = getParsedInt(parsed, KEY_UID);
1324 entry.rxBytes = getParsedLong(parsed, KEY_RX_BYTES);
1325 entry.rxPackets = getParsedLong(parsed, KEY_RX_PACKETS);
1326 entry.txBytes = getParsedLong(parsed, KEY_TX_BYTES);
1327 entry.txPackets = getParsedLong(parsed, KEY_TX_PACKETS);
Jeff Sharkeyd03fd3f2011-06-19 20:55:09 -07001328
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001329 if (limitUid == UID_ALL || limitUid == entry.uid) {
1330 stats.addValues(entry);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001331 }
1332 } catch (NumberFormatException e) {
Jeff Sharkey4414cea2011-06-24 17:05:24 -07001333 Slog.w(TAG, "problem parsing stats row '" + line + "': " + e);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001334 }
1335 }
1336 } catch (IOException e) {
1337 Slog.w(TAG, "problem parsing stats: " + e);
1338 } finally {
1339 IoUtils.closeQuietly(reader);
1340 }
1341
Jeff Sharkey4a971222011-06-11 22:16:55 -07001342 return stats;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001343 }
1344
Jeff Sharkeya63ba592011-07-19 23:47:12 -07001345 private static int getParsedInt(HashMap<String, String> parsed, String key) {
1346 final String value = parsed.get(key);
1347 return value != null ? Integer.parseInt(value) : 0;
1348 }
1349
1350 private static long getParsedLong(HashMap<String, String> parsed, String key) {
1351 final String value = parsed.get(key);
1352 return value != null ? Long.parseLong(value) : 0;
1353 }
1354
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001355 /**
1356 * Build {@link NetworkStats} with detailed UID statistics.
1357 *
1358 * @deprecated since this uses older "uid_stat" data, and doesn't provide
1359 * tag-level granularity or additional variables.
1360 */
1361 @Deprecated
1362 private NetworkStats getNetworkStatsDetailUidstat(int limitUid) {
1363 final String[] knownUids;
1364 if (limitUid == UID_ALL) {
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001365 knownUids = fileListWithoutNull(mStatsUid);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001366 } else {
1367 knownUids = new String[] { String.valueOf(limitUid) };
1368 }
1369
1370 final NetworkStats stats = new NetworkStats(
1371 SystemClock.elapsedRealtime(), knownUids.length);
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001372 final NetworkStats.Entry entry = new NetworkStats.Entry();
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001373 for (String uid : knownUids) {
1374 final int uidInt = Integer.parseInt(uid);
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001375 final File uidPath = new File(mStatsUid, uid);
1376
1377 entry.iface = IFACE_ALL;
1378 entry.uid = uidInt;
1379 entry.tag = TAG_NONE;
1380 entry.rxBytes = readSingleLongFromFile(new File(uidPath, "tcp_rcv"));
1381 entry.rxPackets = readSingleLongFromFile(new File(uidPath, "tcp_rcv_pkt"));
1382 entry.txBytes = readSingleLongFromFile(new File(uidPath, "tcp_snd"));
1383 entry.txPackets = readSingleLongFromFile(new File(uidPath, "tcp_snd_pkt"));
1384
1385 stats.addValues(entry);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001386 }
1387
1388 return stats;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001389 }
1390
San Mehatf0db6e12010-04-07 15:22:10 -07001391 public void setInterfaceThrottle(String iface, int rxKbps, int txKbps) {
San Mehat91cac642010-03-31 14:31:36 -07001392 mContext.enforceCallingOrSelfPermission(
1393 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -07001394 try {
1395 mConnector.doCommand(String.format(
1396 "interface setthrottle %s %d %d", iface, rxKbps, txKbps));
1397 } catch (NativeDaemonConnectorException e) {
1398 Slog.e(TAG, "Error communicating with native daemon to set throttle", e);
1399 }
San Mehat91cac642010-03-31 14:31:36 -07001400 }
1401
1402 private int getInterfaceThrottle(String iface, boolean rx) {
1403 mContext.enforceCallingOrSelfPermission(
1404 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
1405 try {
Kenny Roota80ce062010-06-01 13:23:53 -07001406 String rsp;
1407 try {
1408 rsp = mConnector.doCommand(
1409 String.format("interface getthrottle %s %s", iface,
1410 (rx ? "rx" : "tx"))).get(0);
1411 } catch (NativeDaemonConnectorException e) {
1412 Slog.e(TAG, "Error communicating with native daemon to getthrottle", e);
1413 return -1;
1414 }
1415
1416 String[] tok = rsp.split(" ");
1417 if (tok.length < 2) {
1418 Slog.e(TAG, "Malformed response to getthrottle command");
1419 return -1;
1420 }
1421
San Mehat91cac642010-03-31 14:31:36 -07001422 int code;
1423 try {
1424 code = Integer.parseInt(tok[0]);
1425 } catch (NumberFormatException nfe) {
1426 Slog.e(TAG, String.format("Error parsing code %s", tok[0]));
1427 return -1;
1428 }
1429 if ((rx && code != NetdResponseCode.InterfaceRxThrottleResult) || (
1430 !rx && code != NetdResponseCode.InterfaceTxThrottleResult)) {
1431 Slog.e(TAG, String.format("Unexpected response code %d", code));
1432 return -1;
1433 }
1434 return Integer.parseInt(tok[1]);
1435 } catch (Exception e) {
1436 Slog.e(TAG, String.format(
1437 "Failed to read interface %s throttle value", (rx ? "rx" : "tx")), e);
1438 }
1439 return -1;
1440 }
1441
1442 public int getInterfaceRxThrottle(String iface) {
1443 return getInterfaceThrottle(iface, true);
1444 }
1445
1446 public int getInterfaceTxThrottle(String iface) {
1447 return getInterfaceThrottle(iface, false);
1448 }
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001449
1450 /**
Jeff Sharkey4414cea2011-06-24 17:05:24 -07001451 * Split given line into {@link ArrayList}.
1452 */
1453 private static void splitLine(String line, ArrayList<String> outSplit) {
1454 outSplit.clear();
1455
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001456 final StringTokenizer t = new StringTokenizer(line, " \t\n\r\f:");
Jeff Sharkey4414cea2011-06-24 17:05:24 -07001457 while (t.hasMoreTokens()) {
1458 outSplit.add(t.nextToken());
1459 }
1460 }
1461
1462 /**
1463 * Zip the two given {@link ArrayList} as key and value pairs into
1464 * {@link HashMap}.
1465 */
1466 private static void parseLine(
1467 ArrayList<String> keys, ArrayList<String> values, HashMap<String, String> outParsed) {
1468 outParsed.clear();
1469
1470 final int size = Math.min(keys.size(), values.size());
1471 for (int i = 0; i < size; i++) {
1472 outParsed.put(keys.get(i), values.get(i));
1473 }
1474 }
1475
1476 /**
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001477 * Utility method to read a single plain-text {@link Long} from the given
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001478 * {@link File}, usually from a {@code /proc/} filesystem.
1479 */
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001480 private static long readSingleLongFromFile(File file) {
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001481 try {
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001482 final byte[] buffer = IoUtils.readFileAsByteArray(file.toString());
1483 return Long.parseLong(new String(buffer).trim());
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001484 } catch (NumberFormatException e) {
1485 return -1;
1486 } catch (IOException e) {
1487 return -1;
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001488 }
1489 }
Jean-Baptiste Querud5299ff2011-07-07 08:46:09 -07001490
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001491 /**
1492 * Wrapper for {@link File#list()} that returns empty array instead of
1493 * {@code null}.
1494 */
1495 private static String[] fileListWithoutNull(File file) {
1496 final String[] list = file.list();
1497 return list != null ? list : new String[0];
1498 }
1499
Mattias Falk7475c0c2011-04-04 16:10:36 +02001500 public void setDefaultInterfaceForDns(String iface) throws IllegalStateException {
1501 mContext.enforceCallingOrSelfPermission(
1502 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
1503 try {
1504 String cmd = "resolver setdefaultif " + iface;
1505
1506 mConnector.doCommand(cmd);
1507 } catch (NativeDaemonConnectorException e) {
1508 throw new IllegalStateException(
1509 "Error communicating with native daemon to set default interface", e);
1510 }
1511 }
1512
1513 public void setDnsServersForInterface(String iface, String[] servers)
1514 throws IllegalStateException {
1515 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_NETWORK_STATE,
1516 "NetworkManagementService");
1517 try {
1518 String cmd = "resolver setifdns " + iface;
1519 for (String s : servers) {
Robert Greenwalt572b7042011-07-25 17:00:13 -07001520 InetAddress a = NetworkUtils.numericToInetAddress(s);
1521 if (a.isAnyLocalAddress() == false) {
1522 cmd += " " + a.getHostAddress();
Mattias Falk7475c0c2011-04-04 16:10:36 +02001523 }
1524 }
Mattias Falk7475c0c2011-04-04 16:10:36 +02001525 mConnector.doCommand(cmd);
Robert Greenwalt572b7042011-07-25 17:00:13 -07001526 } catch (IllegalArgumentException e) {
1527 throw new IllegalStateException("Error setting dnsn for interface", e);
Mattias Falk7475c0c2011-04-04 16:10:36 +02001528 } catch (NativeDaemonConnectorException e) {
1529 throw new IllegalStateException(
Robert Greenwalt572b7042011-07-25 17:00:13 -07001530 "Error communicating with native daemon to set dns for interface", e);
Mattias Falk7475c0c2011-04-04 16:10:36 +02001531 }
1532 }
1533
1534 public void flushDefaultDnsCache() throws IllegalStateException {
1535 mContext.enforceCallingOrSelfPermission(
1536 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
1537 try {
1538 String cmd = "resolver flushdefaultif";
1539
1540 mConnector.doCommand(cmd);
1541 } catch (NativeDaemonConnectorException e) {
1542 throw new IllegalStateException(
1543 "Error communicating with native deamon to flush default interface", e);
1544 }
1545 }
1546
1547 public void flushInterfaceDnsCache(String iface) throws IllegalStateException {
1548 mContext.enforceCallingOrSelfPermission(
1549 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
1550 try {
1551 String cmd = "resolver flushif " + iface;
1552
1553 mConnector.doCommand(cmd);
1554 } catch (NativeDaemonConnectorException e) {
1555 throw new IllegalStateException(
Robert Greenwalt572b7042011-07-25 17:00:13 -07001556 "Error communicating with native daemon to flush interface " + iface, e);
Mattias Falk7475c0c2011-04-04 16:10:36 +02001557 }
1558 }
San Mehat873f2142010-01-14 10:25:07 -08001559}