blob: f1a404a21f63d6f87f50c6af2e0255921f0d0a8e [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 Sharkey47eb1022011-08-25 17:48:52 -070019import static android.Manifest.permission.DUMP;
Jeff Sharkey350083e2011-06-29 10:45:16 -070020import static android.Manifest.permission.MANAGE_NETWORK_POLICY;
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -070021import static android.net.NetworkStats.IFACE_ALL;
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -070022import static android.net.NetworkStats.SET_DEFAULT;
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -070023import static android.net.NetworkStats.TAG_NONE;
24import static android.net.NetworkStats.UID_ALL;
Jeff Sharkeyae2c1812011-10-04 13:11:40 -070025import static android.net.TrafficStats.UID_TETHERING;
Jeff Sharkey350083e2011-06-29 10:45:16 -070026import static android.provider.Settings.Secure.NETSTATS_ENABLED;
Jeff Sharkeya63ba592011-07-19 23:47:12 -070027import static com.android.server.NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED;
28import static com.android.server.NetworkManagementSocketTagger.kernelToTag;
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -070029
San Mehat873f2142010-01-14 10:25:07 -080030import android.content.Context;
San Mehat873f2142010-01-14 10:25:07 -080031import android.content.pm.PackageManager;
San Mehat4d02d002010-01-22 16:07:46 -080032import android.net.INetworkManagementEventObserver;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070033import android.net.InterfaceConfiguration;
Robert Greenwalted126402011-01-28 15:34:55 -080034import android.net.LinkAddress;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070035import android.net.NetworkStats;
Robert Greenwalted126402011-01-28 15:34:55 -080036import android.net.NetworkUtils;
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -070037import android.net.RouteInfo;
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -080038import android.net.wifi.WifiConfiguration;
39import android.net.wifi.WifiConfiguration.KeyMgmt;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070040import android.os.Binder;
San Mehat873f2142010-01-14 10:25:07 -080041import android.os.INetworkManagementService;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070042import android.os.SystemClock;
Marco Nelissen62dbb222010-02-18 10:56:30 -080043import android.os.SystemProperties;
Jeff Sharkey350083e2011-06-29 10:45:16 -070044import android.provider.Settings;
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -080045import android.util.Log;
Joe Onorato8a9b2202010-02-26 18:56:32 -080046import android.util.Slog;
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -070047import android.util.SparseBooleanArray;
San Mehat873f2142010-01-14 10:25:07 -080048
Jeff Sharkey4414cea2011-06-24 17:05:24 -070049import com.google.android.collect.Lists;
50import com.google.android.collect.Maps;
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -070051import com.google.android.collect.Sets;
Jeff Sharkey4414cea2011-06-24 17:05:24 -070052
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -070053import java.io.BufferedReader;
54import java.io.DataInputStream;
San Mehat873f2142010-01-14 10:25:07 -080055import java.io.File;
Jeff Sharkey47eb1022011-08-25 17:48:52 -070056import java.io.FileDescriptor;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070057import java.io.FileInputStream;
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -070058import java.io.FileReader;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070059import java.io.IOException;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070060import java.io.InputStreamReader;
Jeff Sharkey47eb1022011-08-25 17:48:52 -070061import java.io.PrintWriter;
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -070062import java.net.Inet4Address;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070063import java.net.InetAddress;
64import java.util.ArrayList;
Jeff Sharkey4414cea2011-06-24 17:05:24 -070065import java.util.HashMap;
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -070066import java.util.HashSet;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070067import java.util.NoSuchElementException;
68import java.util.StringTokenizer;
Robert Greenwalte5c3afb2010-09-22 14:32:35 -070069import java.util.concurrent.CountDownLatch;
San Mehat873f2142010-01-14 10:25:07 -080070
Jeff Sharkey9a13f362011-04-26 16:25:36 -070071import libcore.io.IoUtils;
72
San Mehat873f2142010-01-14 10:25:07 -080073/**
74 * @hide
75 */
Jeff Sharkey8e9992a2011-08-23 18:37:23 -070076public class NetworkManagementService extends INetworkManagementService.Stub
77 implements Watchdog.Monitor {
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070078 private static final String TAG = "NetworkManagementService";
Dianne Hackborncef65ee2010-09-30 18:27:22 -070079 private static final boolean DBG = false;
Kenny Root305bcbf2010-09-03 07:56:38 -070080 private static final String NETD_TAG = "NetdConnector";
81
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -070082 private static final int ADD = 1;
83 private static final int REMOVE = 2;
84
Jeff Sharkey4414cea2011-06-24 17:05:24 -070085 /** Path to {@code /proc/uid_stat}. */
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -070086 @Deprecated
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -070087 private final File mStatsUid;
88 /** Path to {@code /proc/net/dev}. */
Jeff Sharkeyae2c1812011-10-04 13:11:40 -070089 @Deprecated
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -070090 private final File mStatsIface;
Jeff Sharkeyae2c1812011-10-04 13:11:40 -070091 /** Path to {@code /proc/net/xt_qtaguid/iface_stat}. */
92 @Deprecated
93 private final File mStatsXtIface;
94 /** Path to {@code /proc/net/xt_qtaguid/iface_stat_all}. */
95 private final File mStatsXtIfaceAll;
Jeff Sharkey4414cea2011-06-24 17:05:24 -070096 /** Path to {@code /proc/net/xt_qtaguid/stats}. */
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -070097 private final File mStatsXtUid;
Jeff Sharkey4414cea2011-06-24 17:05:24 -070098
Jeff Sharkey8e9992a2011-08-23 18:37:23 -070099 /**
100 * Name representing {@link #setGlobalAlert(long)} limit when delivered to
101 * {@link INetworkManagementEventObserver#limitReached(String, String)}.
102 */
103 public static final String LIMIT_GLOBAL_ALERT = "globalAlert";
104
Jeff Sharkeyae2c1812011-10-04 13:11:40 -0700105 /** {@link #mStatsXtUid} and {@link #mStatsXtIfaceAll} headers. */
Jeff Sharkeyb3d59572011-09-07 17:20:27 -0700106 private static final String KEY_IDX = "idx";
Jeff Sharkey4414cea2011-06-24 17:05:24 -0700107 private static final String KEY_IFACE = "iface";
Jeff Sharkeyae2c1812011-10-04 13:11:40 -0700108 private static final String KEY_ACTIVE = "active";
Jeff Sharkey4414cea2011-06-24 17:05:24 -0700109 private static final String KEY_UID = "uid_tag_int";
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -0700110 private static final String KEY_COUNTER_SET = "cnt_set";
111 private static final String KEY_TAG_HEX = "acct_tag_hex";
Jeff Sharkeyae2c1812011-10-04 13:11:40 -0700112 private static final String KEY_SNAP_RX_BYTES = "snap_rx_bytes";
113 private static final String KEY_SNAP_RX_PACKETS = "snap_rx_packets";
114 private static final String KEY_SNAP_TX_BYTES = "snap_tx_bytes";
115 private static final String KEY_SNAP_TX_PACKETS = "snap_tx_packets";
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700116 private static final String KEY_RX_BYTES = "rx_bytes";
117 private static final String KEY_RX_PACKETS = "rx_packets";
118 private static final String KEY_TX_BYTES = "tx_bytes";
119 private static final String KEY_TX_PACKETS = "tx_packets";
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700120
San Mehat873f2142010-01-14 10:25:07 -0800121 class NetdResponseCode {
JP Abgrall12b933d2011-07-14 18:09:22 -0700122 /* Keep in sync with system/netd/ResponseCode.h */
San Mehat873f2142010-01-14 10:25:07 -0800123 public static final int InterfaceListResult = 110;
124 public static final int TetherInterfaceListResult = 111;
125 public static final int TetherDnsFwdTgtListResult = 112;
San Mehat72759df2010-01-19 13:50:37 -0800126 public static final int TtyListResult = 113;
San Mehat873f2142010-01-14 10:25:07 -0800127
128 public static final int TetherStatusResult = 210;
129 public static final int IpFwdStatusResult = 211;
San Mehated4fc8a2010-01-22 12:28:36 -0800130 public static final int InterfaceGetCfgResult = 213;
Robert Greenwalte3253922010-02-18 09:23:25 -0800131 public static final int SoftapStatusResult = 214;
San Mehat91cac642010-03-31 14:31:36 -0700132 public static final int InterfaceRxCounterResult = 216;
133 public static final int InterfaceTxCounterResult = 217;
134 public static final int InterfaceRxThrottleResult = 218;
135 public static final int InterfaceTxThrottleResult = 219;
Jeff Sharkeycdd02c5d2011-09-16 01:52:49 -0700136 public static final int QuotaCounterResult = 220;
137 public static final int TetheringStatsResult = 221;
Robert Greenwalte3253922010-02-18 09:23:25 -0800138
139 public static final int InterfaceChange = 600;
JP Abgrall12b933d2011-07-14 18:09:22 -0700140 public static final int BandwidthControl = 601;
San Mehat873f2142010-01-14 10:25:07 -0800141 }
142
143 /**
144 * Binder context for this service
145 */
146 private Context mContext;
147
148 /**
149 * connector object for communicating with netd
150 */
151 private NativeDaemonConnector mConnector;
152
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700153 private Thread mThread;
154 private final CountDownLatch mConnectedSignal = new CountDownLatch(1);
155
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -0700156 // TODO: replace with RemoteCallbackList
San Mehat4d02d002010-01-22 16:07:46 -0800157 private ArrayList<INetworkManagementEventObserver> mObservers;
158
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -0700159 private Object mQuotaLock = new Object();
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -0700160 /** Set of interfaces with active quotas. */
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -0700161 private HashSet<String> mActiveQuotaIfaces = Sets.newHashSet();
162 /** Set of interfaces with active alerts. */
163 private HashSet<String> mActiveAlertIfaces = Sets.newHashSet();
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -0700164 /** Set of UIDs with active reject rules. */
165 private SparseBooleanArray mUidRejectOnQuota = new SparseBooleanArray();
166
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -0700167 private volatile boolean mBandwidthControlEnabled;
Jeff Sharkey350083e2011-06-29 10:45:16 -0700168
San Mehat873f2142010-01-14 10:25:07 -0800169 /**
170 * Constructs a new NetworkManagementService instance
171 *
172 * @param context Binder context for this service
173 */
Jeff Sharkey4414cea2011-06-24 17:05:24 -0700174 private NetworkManagementService(Context context, File procRoot) {
San Mehat873f2142010-01-14 10:25:07 -0800175 mContext = context;
San Mehat4d02d002010-01-22 16:07:46 -0800176 mObservers = new ArrayList<INetworkManagementEventObserver>();
177
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700178 mStatsUid = new File(procRoot, "uid_stat");
179 mStatsIface = new File(procRoot, "net/dev");
180 mStatsXtUid = new File(procRoot, "net/xt_qtaguid/stats");
181 mStatsXtIface = new File(procRoot, "net/xt_qtaguid/iface_stat");
Jeff Sharkeyae2c1812011-10-04 13:11:40 -0700182 mStatsXtIfaceAll = new File(procRoot, "net/xt_qtaguid/iface_stat_all");
Jeff Sharkey4414cea2011-06-24 17:05:24 -0700183
Marco Nelissen62dbb222010-02-18 10:56:30 -0800184 if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
185 return;
186 }
187
San Mehat873f2142010-01-14 10:25:07 -0800188 mConnector = new NativeDaemonConnector(
Kenny Root305bcbf2010-09-03 07:56:38 -0700189 new NetdCallbackReceiver(), "netd", 10, NETD_TAG);
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700190 mThread = new Thread(mConnector, NETD_TAG);
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -0700191
192 // Add ourself to the Watchdog monitors.
193 Watchdog.getInstance().addMonitor(this);
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700194 }
195
196 public static NetworkManagementService create(Context context) throws InterruptedException {
Jeff Sharkey4414cea2011-06-24 17:05:24 -0700197 NetworkManagementService service = new NetworkManagementService(
198 context, new File("/proc/"));
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700199 if (DBG) Slog.d(TAG, "Creating NetworkManagementService");
200 service.mThread.start();
201 if (DBG) Slog.d(TAG, "Awaiting socket connection");
202 service.mConnectedSignal.await();
203 if (DBG) Slog.d(TAG, "Connected");
204 return service;
San Mehat873f2142010-01-14 10:25:07 -0800205 }
206
Jeff Sharkey4414cea2011-06-24 17:05:24 -0700207 // @VisibleForTesting
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700208 public static NetworkManagementService createForTest(
209 Context context, File procRoot, boolean bandwidthControlEnabled) {
Jeff Sharkey4414cea2011-06-24 17:05:24 -0700210 // TODO: eventually connect with mock netd
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700211 final NetworkManagementService service = new NetworkManagementService(context, procRoot);
212 service.mBandwidthControlEnabled = bandwidthControlEnabled;
213 return service;
Jeff Sharkey4414cea2011-06-24 17:05:24 -0700214 }
215
Jeff Sharkey350083e2011-06-29 10:45:16 -0700216 public void systemReady() {
Jeff Sharkey350083e2011-06-29 10:45:16 -0700217 // only enable bandwidth control when support exists, and requested by
218 // system setting.
Jeff Sharkey350083e2011-06-29 10:45:16 -0700219 final boolean hasKernelSupport = new File("/proc/net/xt_qtaguid/ctrl").exists();
220 final boolean shouldEnable =
Jeff Sharkey05355c32011-08-09 14:44:19 -0700221 Settings.Secure.getInt(mContext.getContentResolver(), NETSTATS_ENABLED, 1) != 0;
Jeff Sharkey350083e2011-06-29 10:45:16 -0700222
Jeff Sharkey350083e2011-06-29 10:45:16 -0700223 if (hasKernelSupport && shouldEnable) {
224 Slog.d(TAG, "enabling bandwidth control");
225 try {
226 mConnector.doCommand("bandwidth enable");
227 mBandwidthControlEnabled = true;
228 } catch (NativeDaemonConnectorException e) {
229 Slog.e(TAG, "problem enabling bandwidth controls", e);
230 }
231 } else {
232 Slog.d(TAG, "not enabling bandwidth control");
233 }
Jeff Sharkey62a2c8f2011-07-13 15:24:02 -0700234
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700235 SystemProperties.set(PROP_QTAGUID_ENABLED, mBandwidthControlEnabled ? "1" : "0");
Jeff Sharkey350083e2011-06-29 10:45:16 -0700236 }
237
San Mehat4d02d002010-01-22 16:07:46 -0800238 public void registerObserver(INetworkManagementEventObserver obs) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800239 Slog.d(TAG, "Registering observer");
San Mehat4d02d002010-01-22 16:07:46 -0800240 mObservers.add(obs);
241 }
242
243 public void unregisterObserver(INetworkManagementEventObserver obs) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800244 Slog.d(TAG, "Unregistering observer");
San Mehat4d02d002010-01-22 16:07:46 -0800245 mObservers.remove(mObservers.indexOf(obs));
246 }
247
248 /**
Mike J. Chen6143f5f2011-06-23 15:17:51 -0700249 * Notify our observers of an interface status change
San Mehat4d02d002010-01-22 16:07:46 -0800250 */
Mike J. Chen6143f5f2011-06-23 15:17:51 -0700251 private void notifyInterfaceStatusChanged(String iface, boolean up) {
San Mehat4d02d002010-01-22 16:07:46 -0800252 for (INetworkManagementEventObserver obs : mObservers) {
253 try {
Mike J. Chen6143f5f2011-06-23 15:17:51 -0700254 obs.interfaceStatusChanged(iface, up);
255 } catch (Exception ex) {
256 Slog.w(TAG, "Observer notifier failed", ex);
257 }
258 }
259 }
260
261 /**
Mike J. Chenf59c7d02011-06-23 15:33:15 -0700262 * Notify our observers of an interface link state change
Mike J. Chen6143f5f2011-06-23 15:17:51 -0700263 * (typically, an Ethernet cable has been plugged-in or unplugged).
264 */
265 private void notifyInterfaceLinkStateChanged(String iface, boolean up) {
266 for (INetworkManagementEventObserver obs : mObservers) {
267 try {
268 obs.interfaceLinkStateChanged(iface, up);
San Mehat4d02d002010-01-22 16:07:46 -0800269 } catch (Exception ex) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800270 Slog.w(TAG, "Observer notifier failed", ex);
San Mehat4d02d002010-01-22 16:07:46 -0800271 }
272 }
273 }
274
275 /**
276 * Notify our observers of an interface addition.
277 */
278 private void notifyInterfaceAdded(String iface) {
279 for (INetworkManagementEventObserver obs : mObservers) {
280 try {
281 obs.interfaceAdded(iface);
282 } catch (Exception ex) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800283 Slog.w(TAG, "Observer notifier failed", ex);
San Mehat4d02d002010-01-22 16:07:46 -0800284 }
285 }
286 }
287
288 /**
289 * Notify our observers of an interface removal.
290 */
291 private void notifyInterfaceRemoved(String iface) {
292 for (INetworkManagementEventObserver obs : mObservers) {
293 try {
294 obs.interfaceRemoved(iface);
295 } catch (Exception ex) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800296 Slog.w(TAG, "Observer notifier failed", ex);
San Mehat4d02d002010-01-22 16:07:46 -0800297 }
298 }
299 }
300
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700301 /**
JP Abgrall12b933d2011-07-14 18:09:22 -0700302 * Notify our observers of a limit reached.
303 */
304 private void notifyLimitReached(String limitName, String iface) {
305 for (INetworkManagementEventObserver obs : mObservers) {
306 try {
307 obs.limitReached(limitName, iface);
JP Abgrall12b933d2011-07-14 18:09:22 -0700308 } catch (Exception ex) {
309 Slog.w(TAG, "Observer notifier failed", ex);
310 }
311 }
312 }
313
314 /**
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700315 * Let us know the daemon is connected
316 */
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -0700317 protected void onDaemonConnected() {
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700318 if (DBG) Slog.d(TAG, "onConnected");
319 mConnectedSignal.countDown();
320 }
321
San Mehat4d02d002010-01-22 16:07:46 -0800322
San Mehat873f2142010-01-14 10:25:07 -0800323 //
324 // Netd Callback handling
325 //
326
327 class NetdCallbackReceiver implements INativeDaemonConnectorCallbacks {
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -0700328 /** {@inheritDoc} */
San Mehat873f2142010-01-14 10:25:07 -0800329 public void onDaemonConnected() {
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -0700330 NetworkManagementService.this.onDaemonConnected();
San Mehat873f2142010-01-14 10:25:07 -0800331 }
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -0700332
333 /** {@inheritDoc} */
San Mehat873f2142010-01-14 10:25:07 -0800334 public boolean onEvent(int code, String raw, String[] cooked) {
JP Abgrall12b933d2011-07-14 18:09:22 -0700335 switch (code) {
336 case NetdResponseCode.InterfaceChange:
337 /*
338 * a network interface change occured
339 * Format: "NNN Iface added <name>"
340 * "NNN Iface removed <name>"
341 * "NNN Iface changed <name> <up/down>"
342 * "NNN Iface linkstatus <name> <up/down>"
343 */
344 if (cooked.length < 4 || !cooked[1].equals("Iface")) {
345 throw new IllegalStateException(
346 String.format("Invalid event from daemon (%s)", raw));
347 }
348 if (cooked[2].equals("added")) {
349 notifyInterfaceAdded(cooked[3]);
350 return true;
351 } else if (cooked[2].equals("removed")) {
352 notifyInterfaceRemoved(cooked[3]);
353 return true;
354 } else if (cooked[2].equals("changed") && cooked.length == 5) {
355 notifyInterfaceStatusChanged(cooked[3], cooked[4].equals("up"));
356 return true;
357 } else if (cooked[2].equals("linkstate") && cooked.length == 5) {
358 notifyInterfaceLinkStateChanged(cooked[3], cooked[4].equals("up"));
359 return true;
360 }
Robert Greenwalte3253922010-02-18 09:23:25 -0800361 throw new IllegalStateException(
362 String.format("Invalid event from daemon (%s)", raw));
JP Abgrall12b933d2011-07-14 18:09:22 -0700363 // break;
364 case NetdResponseCode.BandwidthControl:
365 /*
366 * Bandwidth control needs some attention
367 * Format: "NNN limit alert <alertName> <ifaceName>"
368 */
369 if (cooked.length < 5 || !cooked[1].equals("limit")) {
370 throw new IllegalStateException(
371 String.format("Invalid event from daemon (%s)", raw));
372 }
373 if (cooked[2].equals("alert")) {
374 notifyLimitReached(cooked[3], cooked[4]);
375 return true;
376 }
377 throw new IllegalStateException(
378 String.format("Invalid event from daemon (%s)", raw));
379 // break;
380 default: break;
Robert Greenwalte3253922010-02-18 09:23:25 -0800381 }
382 return false;
San Mehat873f2142010-01-14 10:25:07 -0800383 }
384 }
385
San Mehated4fc8a2010-01-22 12:28:36 -0800386
San Mehat873f2142010-01-14 10:25:07 -0800387 //
388 // INetworkManagementService members
389 //
390
391 public String[] listInterfaces() throws IllegalStateException {
392 mContext.enforceCallingOrSelfPermission(
393 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
394
Kenny Roota80ce062010-06-01 13:23:53 -0700395 try {
396 return mConnector.doListCommand("interface list", NetdResponseCode.InterfaceListResult);
397 } catch (NativeDaemonConnectorException e) {
398 throw new IllegalStateException(
399 "Cannot communicate with native daemon to list interfaces");
400 }
San Mehated4fc8a2010-01-22 12:28:36 -0800401 }
402
403 public InterfaceConfiguration getInterfaceConfig(String iface) throws IllegalStateException {
Kenny Roota80ce062010-06-01 13:23:53 -0700404 String rsp;
405 try {
406 rsp = mConnector.doCommand("interface getcfg " + iface).get(0);
407 } catch (NativeDaemonConnectorException e) {
408 throw new IllegalStateException(
409 "Cannot communicate with native daemon to get interface config");
410 }
Joe Onorato8a9b2202010-02-26 18:56:32 -0800411 Slog.d(TAG, String.format("rsp <%s>", rsp));
San Mehated4fc8a2010-01-22 12:28:36 -0800412
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800413 // Rsp: 213 xx:xx:xx:xx:xx:xx yyy.yyy.yyy.yyy zzz [flag1 flag2 flag3]
San Mehated4fc8a2010-01-22 12:28:36 -0800414 StringTokenizer st = new StringTokenizer(rsp);
415
Kenny Roota80ce062010-06-01 13:23:53 -0700416 InterfaceConfiguration cfg;
San Mehated4fc8a2010-01-22 12:28:36 -0800417 try {
Kenny Roota80ce062010-06-01 13:23:53 -0700418 try {
419 int code = Integer.parseInt(st.nextToken(" "));
420 if (code != NetdResponseCode.InterfaceGetCfgResult) {
421 throw new IllegalStateException(
422 String.format("Expected code %d, but got %d",
423 NetdResponseCode.InterfaceGetCfgResult, code));
424 }
425 } catch (NumberFormatException nfe) {
San Mehated4fc8a2010-01-22 12:28:36 -0800426 throw new IllegalStateException(
Kenny Roota80ce062010-06-01 13:23:53 -0700427 String.format("Invalid response from daemon (%s)", rsp));
San Mehated4fc8a2010-01-22 12:28:36 -0800428 }
Kenny Roota80ce062010-06-01 13:23:53 -0700429
430 cfg = new InterfaceConfiguration();
431 cfg.hwAddr = st.nextToken(" ");
Robert Greenwalted126402011-01-28 15:34:55 -0800432 InetAddress addr = null;
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800433 int prefixLength = 0;
Kenny Roota80ce062010-06-01 13:23:53 -0700434 try {
Robert Greenwalte5903732011-02-22 16:00:42 -0800435 addr = NetworkUtils.numericToInetAddress(st.nextToken(" "));
436 } catch (IllegalArgumentException iae) {
437 Slog.e(TAG, "Failed to parse ipaddr", iae);
Kenny Roota80ce062010-06-01 13:23:53 -0700438 }
439
440 try {
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800441 prefixLength = Integer.parseInt(st.nextToken(" "));
442 } catch (NumberFormatException nfe) {
443 Slog.e(TAG, "Failed to parse prefixLength", nfe);
Kenny Roota80ce062010-06-01 13:23:53 -0700444 }
Robert Greenwalt04808c22010-12-13 17:01:41 -0800445
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800446 cfg.addr = new LinkAddress(addr, prefixLength);
Kenny Roota80ce062010-06-01 13:23:53 -0700447 cfg.interfaceFlags = st.nextToken("]").trim() +"]";
448 } catch (NoSuchElementException nsee) {
San Mehated4fc8a2010-01-22 12:28:36 -0800449 throw new IllegalStateException(
450 String.format("Invalid response from daemon (%s)", rsp));
451 }
Joe Onorato8a9b2202010-02-26 18:56:32 -0800452 Slog.d(TAG, String.format("flags <%s>", cfg.interfaceFlags));
San Mehated4fc8a2010-01-22 12:28:36 -0800453 return cfg;
454 }
455
456 public void setInterfaceConfig(
457 String iface, InterfaceConfiguration cfg) throws IllegalStateException {
Robert Greenwalted126402011-01-28 15:34:55 -0800458 LinkAddress linkAddr = cfg.addr;
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800459 if (linkAddr == null || linkAddr.getAddress() == null) {
460 throw new IllegalStateException("Null LinkAddress given");
Robert Greenwalted126402011-01-28 15:34:55 -0800461 }
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800462 String cmd = String.format("interface setcfg %s %s %d %s", iface,
463 linkAddr.getAddress().getHostAddress(),
464 linkAddr.getNetworkPrefixLength(),
465 cfg.interfaceFlags);
Kenny Roota80ce062010-06-01 13:23:53 -0700466 try {
467 mConnector.doCommand(cmd);
468 } catch (NativeDaemonConnectorException e) {
469 throw new IllegalStateException(
Robert Greenwalt81d5ad52010-12-16 11:27:38 -0800470 "Unable to communicate with native daemon to interface setcfg - " + e);
Kenny Roota80ce062010-06-01 13:23:53 -0700471 }
San Mehat873f2142010-01-14 10:25:07 -0800472 }
473
Irfan Sheriff7244c972011-08-05 20:40:45 -0700474 public void setInterfaceDown(String iface) throws IllegalStateException {
475 try {
476 InterfaceConfiguration ifcg = getInterfaceConfig(iface);
477 ifcg.interfaceFlags = ifcg.interfaceFlags.replace("up", "down");
478 setInterfaceConfig(iface, ifcg);
479 } catch (NativeDaemonConnectorException e) {
480 throw new IllegalStateException(
481 "Unable to communicate with native daemon for interface down - " + e);
482 }
483 }
484
485 public void setInterfaceUp(String iface) throws IllegalStateException {
486 try {
487 InterfaceConfiguration ifcg = getInterfaceConfig(iface);
488 ifcg.interfaceFlags = ifcg.interfaceFlags.replace("down", "up");
489 setInterfaceConfig(iface, ifcg);
490 } catch (NativeDaemonConnectorException e) {
491 throw new IllegalStateException(
492 "Unable to communicate with native daemon for interface up - " + e);
493 }
494 }
495
Irfan Sheriff73293612011-09-14 12:31:56 -0700496 public void setInterfaceIpv6PrivacyExtensions(String iface, boolean enable)
497 throws IllegalStateException {
498 String cmd = String.format("interface ipv6privacyextensions %s %s", iface,
499 enable ? "enable" : "disable");
500 try {
501 mConnector.doCommand(cmd);
502 } catch (NativeDaemonConnectorException e) {
503 throw new IllegalStateException(
504 "Unable to communicate with native daemon to set ipv6privacyextensions - " + e);
505 }
506 }
507
508
509
Irfan Sherifff5600612011-06-16 10:26:28 -0700510 /* TODO: This is right now a IPv4 only function. Works for wifi which loses its
511 IPv6 addresses on interface down, but we need to do full clean up here */
512 public void clearInterfaceAddresses(String iface) throws IllegalStateException {
513 String cmd = String.format("interface clearaddrs %s", iface);
514 try {
515 mConnector.doCommand(cmd);
516 } catch (NativeDaemonConnectorException e) {
517 throw new IllegalStateException(
518 "Unable to communicate with native daemon to interface clearallips - " + e);
519 }
520 }
521
repo sync7960d9f2011-09-29 12:40:02 -0700522 public void enableIpv6(String iface) throws IllegalStateException {
523 mContext.enforceCallingOrSelfPermission(
524 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
525 try {
526 mConnector.doCommand(String.format("interface ipv6 %s enable", iface));
527 } catch (NativeDaemonConnectorException e) {
528 throw new IllegalStateException(
529 "Unable to communicate to native daemon for enabling ipv6");
530 }
531 }
532
533 public void disableIpv6(String iface) throws IllegalStateException {
534 mContext.enforceCallingOrSelfPermission(
535 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
536 try {
537 mConnector.doCommand(String.format("interface ipv6 %s disable", iface));
538 } catch (NativeDaemonConnectorException e) {
539 throw new IllegalStateException(
540 "Unable to communicate to native daemon for disabling ipv6");
541 }
542 }
543
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -0700544 public void addRoute(String interfaceName, RouteInfo route) {
545 modifyRoute(interfaceName, ADD, route);
546 }
547
548 public void removeRoute(String interfaceName, RouteInfo route) {
549 modifyRoute(interfaceName, REMOVE, route);
550 }
551
552 private void modifyRoute(String interfaceName, int action, RouteInfo route) {
553 ArrayList<String> rsp;
554
555 StringBuilder cmd;
556
557 switch (action) {
558 case ADD:
559 {
560 cmd = new StringBuilder("interface route add " + interfaceName);
561 break;
562 }
563 case REMOVE:
564 {
565 cmd = new StringBuilder("interface route remove " + interfaceName);
566 break;
567 }
568 default:
569 throw new IllegalStateException("Unknown action type " + action);
570 }
571
572 // create triplet: dest-ip-addr prefixlength gateway-ip-addr
573 LinkAddress la = route.getDestination();
574 cmd.append(' ');
575 cmd.append(la.getAddress().getHostAddress());
576 cmd.append(' ');
577 cmd.append(la.getNetworkPrefixLength());
578 cmd.append(' ');
579 if (route.getGateway() == null) {
580 if (la.getAddress() instanceof Inet4Address) {
581 cmd.append("0.0.0.0");
582 } else {
583 cmd.append ("::0");
584 }
585 } else {
586 cmd.append(route.getGateway().getHostAddress());
587 }
588 try {
589 rsp = mConnector.doCommand(cmd.toString());
590 } catch (NativeDaemonConnectorException e) {
591 throw new IllegalStateException(
592 "Unable to communicate with native dameon to add routes - "
593 + e);
594 }
595
Wink Savillec9acde92011-09-21 11:05:43 -0700596 if (DBG) {
597 for (String line : rsp) {
598 Log.v(TAG, "add route response is " + line);
599 }
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -0700600 }
601 }
602
603 private ArrayList<String> readRouteList(String filename) {
604 FileInputStream fstream = null;
605 ArrayList<String> list = new ArrayList<String>();
606
607 try {
608 fstream = new FileInputStream(filename);
609 DataInputStream in = new DataInputStream(fstream);
610 BufferedReader br = new BufferedReader(new InputStreamReader(in));
611 String s;
612
613 // throw away the title line
614
615 while (((s = br.readLine()) != null) && (s.length() != 0)) {
616 list.add(s);
617 }
618 } catch (IOException ex) {
619 // return current list, possibly empty
620 } finally {
621 if (fstream != null) {
622 try {
623 fstream.close();
624 } catch (IOException ex) {}
625 }
626 }
627
628 return list;
629 }
630
631 public RouteInfo[] getRoutes(String interfaceName) {
632 ArrayList<RouteInfo> routes = new ArrayList<RouteInfo>();
633
634 // v4 routes listed as:
635 // iface dest-addr gateway-addr flags refcnt use metric netmask mtu window IRTT
636 for (String s : readRouteList("/proc/net/route")) {
637 String[] fields = s.split("\t");
638
639 if (fields.length > 7) {
640 String iface = fields[0];
641
642 if (interfaceName.equals(iface)) {
643 String dest = fields[1];
644 String gate = fields[2];
645 String flags = fields[3]; // future use?
646 String mask = fields[7];
647 try {
648 // address stored as a hex string, ex: 0014A8C0
649 InetAddress destAddr =
650 NetworkUtils.intToInetAddress((int)Long.parseLong(dest, 16));
651 int prefixLength =
652 NetworkUtils.netmaskIntToPrefixLength(
653 (int)Long.parseLong(mask, 16));
654 LinkAddress linkAddress = new LinkAddress(destAddr, prefixLength);
655
656 // address stored as a hex string, ex 0014A8C0
657 InetAddress gatewayAddr =
658 NetworkUtils.intToInetAddress((int)Long.parseLong(gate, 16));
659
660 RouteInfo route = new RouteInfo(linkAddress, gatewayAddr);
661 routes.add(route);
662 } catch (Exception e) {
663 Log.e(TAG, "Error parsing route " + s + " : " + e);
664 continue;
665 }
666 }
667 }
668 }
669
670 // v6 routes listed as:
671 // dest-addr prefixlength ?? ?? gateway-addr ?? ?? ?? ?? iface
672 for (String s : readRouteList("/proc/net/ipv6_route")) {
673 String[]fields = s.split("\\s+");
674 if (fields.length > 9) {
675 String iface = fields[9].trim();
676 if (interfaceName.equals(iface)) {
677 String dest = fields[0];
678 String prefix = fields[1];
679 String gate = fields[4];
680
681 try {
682 // prefix length stored as a hex string, ex 40
683 int prefixLength = Integer.parseInt(prefix, 16);
684
685 // address stored as a 32 char hex string
686 // ex fe800000000000000000000000000000
687 InetAddress destAddr = NetworkUtils.hexToInet6Address(dest);
688 LinkAddress linkAddress = new LinkAddress(destAddr, prefixLength);
689
690 InetAddress gateAddr = NetworkUtils.hexToInet6Address(gate);
691
692 RouteInfo route = new RouteInfo(linkAddress, gateAddr);
693 routes.add(route);
694 } catch (Exception e) {
695 Log.e(TAG, "Error parsing route " + s + " : " + e);
696 continue;
697 }
698 }
699 }
700 }
701 return (RouteInfo[]) routes.toArray(new RouteInfo[0]);
702 }
703
San Mehat873f2142010-01-14 10:25:07 -0800704 public void shutdown() {
705 if (mContext.checkCallingOrSelfPermission(
706 android.Manifest.permission.SHUTDOWN)
707 != PackageManager.PERMISSION_GRANTED) {
708 throw new SecurityException("Requires SHUTDOWN permission");
709 }
710
Joe Onorato8a9b2202010-02-26 18:56:32 -0800711 Slog.d(TAG, "Shutting down");
San Mehat873f2142010-01-14 10:25:07 -0800712 }
713
714 public boolean getIpForwardingEnabled() throws IllegalStateException{
715 mContext.enforceCallingOrSelfPermission(
716 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
717
Kenny Roota80ce062010-06-01 13:23:53 -0700718 ArrayList<String> rsp;
719 try {
720 rsp = mConnector.doCommand("ipfwd status");
721 } catch (NativeDaemonConnectorException e) {
722 throw new IllegalStateException(
723 "Unable to communicate with native daemon to ipfwd status");
724 }
San Mehat873f2142010-01-14 10:25:07 -0800725
726 for (String line : rsp) {
Kenny Roota80ce062010-06-01 13:23:53 -0700727 String[] tok = line.split(" ");
728 if (tok.length < 3) {
729 Slog.e(TAG, "Malformed response from native daemon: " + line);
730 return false;
731 }
732
San Mehat873f2142010-01-14 10:25:07 -0800733 int code = Integer.parseInt(tok[0]);
734 if (code == NetdResponseCode.IpFwdStatusResult) {
735 // 211 Forwarding <enabled/disabled>
Kenny Roota80ce062010-06-01 13:23:53 -0700736 return "enabled".equals(tok[2]);
San Mehat873f2142010-01-14 10:25:07 -0800737 } else {
738 throw new IllegalStateException(String.format("Unexpected response code %d", code));
739 }
740 }
741 throw new IllegalStateException("Got an empty response");
742 }
743
744 public void setIpForwardingEnabled(boolean enable) throws IllegalStateException {
745 mContext.enforceCallingOrSelfPermission(
746 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
747 mConnector.doCommand(String.format("ipfwd %sable", (enable ? "en" : "dis")));
748 }
749
Robert Greenwaltbfb7bfa2010-03-24 16:03:21 -0700750 public void startTethering(String[] dhcpRange)
San Mehat873f2142010-01-14 10:25:07 -0800751 throws IllegalStateException {
752 mContext.enforceCallingOrSelfPermission(
753 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Robert Greenwaltbfb7bfa2010-03-24 16:03:21 -0700754 // cmd is "tether start first_start first_stop second_start second_stop ..."
755 // an odd number of addrs will fail
756 String cmd = "tether start";
757 for (String d : dhcpRange) {
758 cmd += " " + d;
759 }
Kenny Roota80ce062010-06-01 13:23:53 -0700760
761 try {
762 mConnector.doCommand(cmd);
763 } catch (NativeDaemonConnectorException e) {
764 throw new IllegalStateException("Unable to communicate to native daemon");
765 }
San Mehat873f2142010-01-14 10:25:07 -0800766 }
767
768 public void stopTethering() throws IllegalStateException {
769 mContext.enforceCallingOrSelfPermission(
770 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700771 try {
772 mConnector.doCommand("tether stop");
773 } catch (NativeDaemonConnectorException e) {
774 throw new IllegalStateException("Unable to communicate to native daemon to stop tether");
775 }
San Mehat873f2142010-01-14 10:25:07 -0800776 }
777
778 public boolean isTetheringStarted() throws IllegalStateException {
779 mContext.enforceCallingOrSelfPermission(
780 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
781
Kenny Roota80ce062010-06-01 13:23:53 -0700782 ArrayList<String> rsp;
783 try {
784 rsp = mConnector.doCommand("tether status");
785 } catch (NativeDaemonConnectorException e) {
786 throw new IllegalStateException(
787 "Unable to communicate to native daemon to get tether status");
788 }
San Mehat873f2142010-01-14 10:25:07 -0800789
790 for (String line : rsp) {
Kenny Roota80ce062010-06-01 13:23:53 -0700791 String[] tok = line.split(" ");
792 if (tok.length < 3) {
793 throw new IllegalStateException("Malformed response for tether status: " + line);
794 }
San Mehat873f2142010-01-14 10:25:07 -0800795 int code = Integer.parseInt(tok[0]);
796 if (code == NetdResponseCode.TetherStatusResult) {
797 // XXX: Tethering services <started/stopped> <TBD>...
Kenny Roota80ce062010-06-01 13:23:53 -0700798 return "started".equals(tok[2]);
San Mehat873f2142010-01-14 10:25:07 -0800799 } else {
800 throw new IllegalStateException(String.format("Unexpected response code %d", code));
801 }
802 }
803 throw new IllegalStateException("Got an empty response");
804 }
805
806 public void tetherInterface(String iface) throws IllegalStateException {
807 mContext.enforceCallingOrSelfPermission(
808 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700809 try {
810 mConnector.doCommand("tether interface add " + iface);
811 } catch (NativeDaemonConnectorException e) {
812 throw new IllegalStateException(
813 "Unable to communicate to native daemon for adding tether interface");
814 }
San Mehat873f2142010-01-14 10:25:07 -0800815 }
816
817 public void untetherInterface(String iface) {
818 mContext.enforceCallingOrSelfPermission(
819 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700820 try {
821 mConnector.doCommand("tether interface remove " + iface);
822 } catch (NativeDaemonConnectorException e) {
823 throw new IllegalStateException(
824 "Unable to communicate to native daemon for removing tether interface");
825 }
San Mehat873f2142010-01-14 10:25:07 -0800826 }
827
828 public String[] listTetheredInterfaces() throws IllegalStateException {
829 mContext.enforceCallingOrSelfPermission(
830 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700831 try {
832 return mConnector.doListCommand(
833 "tether interface list", NetdResponseCode.TetherInterfaceListResult);
834 } catch (NativeDaemonConnectorException e) {
835 throw new IllegalStateException(
836 "Unable to communicate to native daemon for listing tether interfaces");
837 }
San Mehat873f2142010-01-14 10:25:07 -0800838 }
839
840 public void setDnsForwarders(String[] dns) throws IllegalStateException {
841 mContext.enforceCallingOrSelfPermission(
842 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
843 try {
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800844 String cmd = "tether dns set";
San Mehat873f2142010-01-14 10:25:07 -0800845 for (String s : dns) {
Robert Greenwalte5903732011-02-22 16:00:42 -0800846 cmd += " " + NetworkUtils.numericToInetAddress(s).getHostAddress();
San Mehat873f2142010-01-14 10:25:07 -0800847 }
Kenny Roota80ce062010-06-01 13:23:53 -0700848 try {
849 mConnector.doCommand(cmd);
850 } catch (NativeDaemonConnectorException e) {
851 throw new IllegalStateException(
852 "Unable to communicate to native daemon for setting tether dns");
853 }
Robert Greenwalte5903732011-02-22 16:00:42 -0800854 } catch (IllegalArgumentException e) {
San Mehat873f2142010-01-14 10:25:07 -0800855 throw new IllegalStateException("Error resolving dns name", e);
856 }
857 }
858
859 public String[] getDnsForwarders() throws IllegalStateException {
860 mContext.enforceCallingOrSelfPermission(
861 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700862 try {
863 return mConnector.doListCommand(
864 "tether dns list", NetdResponseCode.TetherDnsFwdTgtListResult);
865 } catch (NativeDaemonConnectorException e) {
866 throw new IllegalStateException(
867 "Unable to communicate to native daemon for listing tether dns");
868 }
San Mehat873f2142010-01-14 10:25:07 -0800869 }
870
871 public void enableNat(String internalInterface, String externalInterface)
872 throws IllegalStateException {
873 mContext.enforceCallingOrSelfPermission(
874 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700875 try {
876 mConnector.doCommand(
877 String.format("nat enable %s %s", internalInterface, externalInterface));
878 } catch (NativeDaemonConnectorException e) {
879 throw new IllegalStateException(
880 "Unable to communicate to native daemon for enabling NAT interface");
881 }
San Mehat873f2142010-01-14 10:25:07 -0800882 }
883
884 public void disableNat(String internalInterface, String externalInterface)
885 throws IllegalStateException {
886 mContext.enforceCallingOrSelfPermission(
887 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700888 try {
889 mConnector.doCommand(
890 String.format("nat disable %s %s", internalInterface, externalInterface));
891 } catch (NativeDaemonConnectorException e) {
892 throw new IllegalStateException(
893 "Unable to communicate to native daemon for disabling NAT interface");
894 }
San Mehat873f2142010-01-14 10:25:07 -0800895 }
San Mehat72759df2010-01-19 13:50:37 -0800896
897 public String[] listTtys() throws IllegalStateException {
898 mContext.enforceCallingOrSelfPermission(
899 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700900 try {
901 return mConnector.doListCommand("list_ttys", NetdResponseCode.TtyListResult);
902 } catch (NativeDaemonConnectorException e) {
903 throw new IllegalStateException(
904 "Unable to communicate to native daemon for listing TTYs");
905 }
San Mehat72759df2010-01-19 13:50:37 -0800906 }
907
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800908 public void attachPppd(String tty, String localAddr, String remoteAddr, String dns1Addr,
909 String dns2Addr) throws IllegalStateException {
San Mehat72759df2010-01-19 13:50:37 -0800910 try {
911 mContext.enforceCallingOrSelfPermission(
912 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800913 mConnector.doCommand(String.format("pppd attach %s %s %s %s %s", tty,
Robert Greenwalte5903732011-02-22 16:00:42 -0800914 NetworkUtils.numericToInetAddress(localAddr).getHostAddress(),
915 NetworkUtils.numericToInetAddress(remoteAddr).getHostAddress(),
916 NetworkUtils.numericToInetAddress(dns1Addr).getHostAddress(),
917 NetworkUtils.numericToInetAddress(dns2Addr).getHostAddress()));
918 } catch (IllegalArgumentException e) {
San Mehat72759df2010-01-19 13:50:37 -0800919 throw new IllegalStateException("Error resolving addr", e);
Kenny Roota80ce062010-06-01 13:23:53 -0700920 } catch (NativeDaemonConnectorException e) {
921 throw new IllegalStateException("Error communicating to native daemon to attach pppd", e);
San Mehat72759df2010-01-19 13:50:37 -0800922 }
923 }
924
925 public void detachPppd(String tty) throws IllegalStateException {
926 mContext.enforceCallingOrSelfPermission(
927 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700928 try {
929 mConnector.doCommand(String.format("pppd detach %s", tty));
930 } catch (NativeDaemonConnectorException e) {
931 throw new IllegalStateException("Error communicating to native daemon to detach pppd", e);
932 }
San Mehat72759df2010-01-19 13:50:37 -0800933 }
Robert Greenwaltce1200d2010-02-18 11:25:54 -0800934
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700935 public void startAccessPoint(WifiConfiguration wifiConfig, String wlanIface, String softapIface)
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800936 throws IllegalStateException {
937 mContext.enforceCallingOrSelfPermission(
938 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
939 mContext.enforceCallingOrSelfPermission(
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700940 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700941 try {
Irfan Sheriffcb30b222011-07-29 20:54:52 -0700942 wifiFirmwareReload(wlanIface, "AP");
Kenny Roota80ce062010-06-01 13:23:53 -0700943 mConnector.doCommand(String.format("softap start " + wlanIface));
944 if (wifiConfig == null) {
945 mConnector.doCommand(String.format("softap set " + wlanIface + " " + softapIface));
946 } else {
947 /**
948 * softap set arg1 arg2 arg3 [arg4 arg5 arg6 arg7 arg8]
949 * argv1 - wlan interface
950 * argv2 - softap interface
951 * argv3 - SSID
952 * argv4 - Security
953 * argv5 - Key
954 * argv6 - Channel
955 * argv7 - Preamble
956 * argv8 - Max SCB
957 */
Irfan Sheriffec8d23a2011-02-16 17:00:33 -0800958 String str = String.format("softap set " + wlanIface + " " + softapIface +
959 " %s %s %s", convertQuotedString(wifiConfig.SSID),
960 getSecurityType(wifiConfig),
961 convertQuotedString(wifiConfig.preSharedKey));
Kenny Roota80ce062010-06-01 13:23:53 -0700962 mConnector.doCommand(str);
963 }
964 mConnector.doCommand(String.format("softap startap"));
965 } catch (NativeDaemonConnectorException e) {
966 throw new IllegalStateException("Error communicating to native daemon to start softap", e);
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -0800967 }
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800968 }
969
Irfan Sheriffa6e559e2010-05-24 14:55:42 -0700970 private String convertQuotedString(String s) {
Irfan Sheriff7baec0f2010-05-26 17:16:47 -0700971 if (s == null) {
972 return s;
973 }
974 /* Replace \ with \\, then " with \" and add quotes at end */
975 return '"' + s.replaceAll("\\\\","\\\\\\\\").replaceAll("\"","\\\\\"") + '"';
Irfan Sheriffa6e559e2010-05-24 14:55:42 -0700976 }
977
Irfan Sheriffec8d23a2011-02-16 17:00:33 -0800978 private String getSecurityType(WifiConfiguration wifiConfig) {
979 switch (wifiConfig.getAuthType()) {
980 case KeyMgmt.WPA_PSK:
981 return "wpa-psk";
982 case KeyMgmt.WPA2_PSK:
983 return "wpa2-psk";
984 default:
985 return "open";
986 }
987 }
988
Irfan Sheriffcb30b222011-07-29 20:54:52 -0700989 /* @param mode can be "AP", "STA" or "P2P" */
990 public void wifiFirmwareReload(String wlanIface, String mode) throws IllegalStateException {
991 mContext.enforceCallingOrSelfPermission(
992 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
993 mContext.enforceCallingOrSelfPermission(
994 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
995
996 try {
997 mConnector.doCommand(String.format("softap fwreload " + wlanIface + " " + mode));
998 } catch (NativeDaemonConnectorException e) {
999 throw new IllegalStateException("Error communicating to native daemon ", e);
1000 }
1001 }
1002
Irfan Sheriff23eb2972011-07-22 15:21:10 -07001003 public void stopAccessPoint(String wlanIface) throws IllegalStateException {
Irfan Sheriff5321aef2010-02-12 12:35:59 -08001004 mContext.enforceCallingOrSelfPermission(
1005 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
1006 mContext.enforceCallingOrSelfPermission(
Irfan Sheriffc2f54c22010-03-18 14:02:22 -07001007 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -07001008 try {
1009 mConnector.doCommand("softap stopap");
Irfan Sheriff23eb2972011-07-22 15:21:10 -07001010 mConnector.doCommand("softap stop " + wlanIface);
Irfan Sheriffcb30b222011-07-29 20:54:52 -07001011 wifiFirmwareReload(wlanIface, "STA");
Kenny Roota80ce062010-06-01 13:23:53 -07001012 } catch (NativeDaemonConnectorException e) {
1013 throw new IllegalStateException("Error communicating to native daemon to stop soft AP",
1014 e);
1015 }
Irfan Sheriff5321aef2010-02-12 12:35:59 -08001016 }
1017
Irfan Sheriffc2f54c22010-03-18 14:02:22 -07001018 public void setAccessPoint(WifiConfiguration wifiConfig, String wlanIface, String softapIface)
1019 throws IllegalStateException {
1020 mContext.enforceCallingOrSelfPermission(
1021 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
1022 mContext.enforceCallingOrSelfPermission(
1023 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -07001024 try {
1025 if (wifiConfig == null) {
1026 mConnector.doCommand(String.format("softap set " + wlanIface + " " + softapIface));
1027 } else {
1028 String str = String.format("softap set " + wlanIface + " " + softapIface
1029 + " %s %s %s", convertQuotedString(wifiConfig.SSID),
Irfan Sheriffec8d23a2011-02-16 17:00:33 -08001030 getSecurityType(wifiConfig),
Kenny Roota80ce062010-06-01 13:23:53 -07001031 convertQuotedString(wifiConfig.preSharedKey));
1032 mConnector.doCommand(str);
1033 }
1034 } catch (NativeDaemonConnectorException e) {
1035 throw new IllegalStateException("Error communicating to native daemon to set soft AP",
1036 e);
Irfan Sheriffc2f54c22010-03-18 14:02:22 -07001037 }
1038 }
San Mehat91cac642010-03-31 14:31:36 -07001039
1040 private long getInterfaceCounter(String iface, boolean rx) {
1041 mContext.enforceCallingOrSelfPermission(
1042 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
1043 try {
Kenny Roota80ce062010-06-01 13:23:53 -07001044 String rsp;
1045 try {
1046 rsp = mConnector.doCommand(
1047 String.format("interface read%scounter %s", (rx ? "rx" : "tx"), iface)).get(0);
1048 } catch (NativeDaemonConnectorException e1) {
1049 Slog.e(TAG, "Error communicating with native daemon", e1);
1050 return -1;
1051 }
1052
1053 String[] tok = rsp.split(" ");
1054 if (tok.length < 2) {
1055 Slog.e(TAG, String.format("Malformed response for reading %s interface",
1056 (rx ? "rx" : "tx")));
1057 return -1;
1058 }
1059
San Mehat91cac642010-03-31 14:31:36 -07001060 int code;
1061 try {
1062 code = Integer.parseInt(tok[0]);
1063 } catch (NumberFormatException nfe) {
1064 Slog.e(TAG, String.format("Error parsing code %s", tok[0]));
1065 return -1;
1066 }
1067 if ((rx && code != NetdResponseCode.InterfaceRxCounterResult) || (
1068 !rx && code != NetdResponseCode.InterfaceTxCounterResult)) {
1069 Slog.e(TAG, String.format("Unexpected response code %d", code));
1070 return -1;
1071 }
1072 return Long.parseLong(tok[1]);
1073 } catch (Exception e) {
1074 Slog.e(TAG, String.format(
1075 "Failed to read interface %s counters", (rx ? "rx" : "tx")), e);
1076 }
1077 return -1;
1078 }
1079
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001080 @Override
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001081 public NetworkStats getNetworkStatsSummary() {
1082 mContext.enforceCallingOrSelfPermission(
1083 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
1084
Jeff Sharkeyae2c1812011-10-04 13:11:40 -07001085 if (mBandwidthControlEnabled && mStatsXtIfaceAll.exists()) {
1086 return getNetworkStatsSummarySingleFile();
1087 } else {
1088 return getNetworkStatsSummaryMultipleFiles();
1089 }
1090 }
1091
1092 @Deprecated
1093 private NetworkStats getNetworkStatsSummaryMultipleFiles() {
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001094 final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6);
1095 final NetworkStats.Entry entry = new NetworkStats.Entry();
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001096
Jeff Sharkey0fea8232011-09-01 01:07:31 -07001097 final HashSet<String> knownIfaces = Sets.newHashSet();
1098 final HashSet<String> activeIfaces = Sets.newHashSet();
1099
1100 // collect any historical stats and active state
1101 // TODO: migrate to reading from single file
1102 if (mBandwidthControlEnabled) {
1103 for (String iface : fileListWithoutNull(mStatsXtIface)) {
1104 final File ifacePath = new File(mStatsXtIface, iface);
1105
1106 final long active = readSingleLongFromFile(new File(ifacePath, "active"));
1107 if (active == 1) {
1108 knownIfaces.add(iface);
1109 activeIfaces.add(iface);
1110 } else if (active == 0) {
1111 knownIfaces.add(iface);
1112 } else {
1113 continue;
1114 }
1115
1116 entry.iface = iface;
1117 entry.uid = UID_ALL;
1118 entry.set = SET_DEFAULT;
1119 entry.tag = TAG_NONE;
1120 entry.rxBytes = readSingleLongFromFile(new File(ifacePath, "rx_bytes"));
1121 entry.rxPackets = readSingleLongFromFile(new File(ifacePath, "rx_packets"));
1122 entry.txBytes = readSingleLongFromFile(new File(ifacePath, "tx_bytes"));
1123 entry.txPackets = readSingleLongFromFile(new File(ifacePath, "tx_packets"));
1124
1125 stats.addValues(entry);
1126 }
1127 }
1128
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001129 final ArrayList<String> values = Lists.newArrayList();
1130
1131 BufferedReader reader = null;
1132 try {
1133 reader = new BufferedReader(new FileReader(mStatsIface));
1134
1135 // skip first two header lines
1136 reader.readLine();
1137 reader.readLine();
1138
1139 // parse remaining lines
1140 String line;
1141 while ((line = reader.readLine()) != null) {
1142 splitLine(line, values);
1143
1144 try {
1145 entry.iface = values.get(0);
1146 entry.uid = UID_ALL;
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -07001147 entry.set = SET_DEFAULT;
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001148 entry.tag = TAG_NONE;
1149 entry.rxBytes = Long.parseLong(values.get(1));
1150 entry.rxPackets = Long.parseLong(values.get(2));
1151 entry.txBytes = Long.parseLong(values.get(9));
1152 entry.txPackets = Long.parseLong(values.get(10));
1153
Jeff Sharkey0fea8232011-09-01 01:07:31 -07001154 if (activeIfaces.contains(entry.iface)) {
1155 // combine stats when iface is active
1156 stats.combineValues(entry);
1157 } else if (!knownIfaces.contains(entry.iface)) {
1158 // add stats when iface is unknown
1159 stats.addValues(entry);
1160 }
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001161 } catch (NumberFormatException e) {
1162 Slog.w(TAG, "problem parsing stats row '" + line + "': " + e);
1163 }
1164 }
Jeff Sharkey558a2322011-08-24 15:42:09 -07001165 } catch (NullPointerException e) {
1166 throw new IllegalStateException("problem parsing stats: " + e);
1167 } catch (NumberFormatException e) {
1168 throw new IllegalStateException("problem parsing stats: " + e);
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001169 } catch (IOException e) {
Jeff Sharkey558a2322011-08-24 15:42:09 -07001170 throw new IllegalStateException("problem parsing stats: " + e);
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001171 } finally {
1172 IoUtils.closeQuietly(reader);
1173 }
1174
Jeff Sharkey4a971222011-06-11 22:16:55 -07001175 return stats;
San Mehat91cac642010-03-31 14:31:36 -07001176 }
1177
Jeff Sharkeyae2c1812011-10-04 13:11:40 -07001178 private NetworkStats getNetworkStatsSummarySingleFile() {
1179 final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6);
1180 final NetworkStats.Entry entry = new NetworkStats.Entry();
1181
1182 // TODO: read directly from proc once headers are added
1183 final ArrayList<String> keys = Lists.newArrayList(KEY_IFACE, KEY_ACTIVE, KEY_SNAP_RX_BYTES,
1184 KEY_SNAP_RX_PACKETS, KEY_SNAP_TX_BYTES, KEY_SNAP_TX_PACKETS, KEY_RX_BYTES,
1185 KEY_RX_PACKETS, KEY_TX_BYTES, KEY_TX_PACKETS);
1186 final ArrayList<String> values = Lists.newArrayList();
1187 final HashMap<String, String> parsed = Maps.newHashMap();
1188
1189 BufferedReader reader = null;
1190 try {
1191 reader = new BufferedReader(new FileReader(mStatsXtIfaceAll));
1192
1193 String line;
1194 while ((line = reader.readLine()) != null) {
1195 splitLine(line, values);
1196 parseLine(keys, values, parsed);
1197
1198 entry.iface = parsed.get(KEY_IFACE);
1199 entry.uid = UID_ALL;
1200 entry.set = SET_DEFAULT;
1201 entry.tag = TAG_NONE;
1202
1203 // always include snapshot values
1204 entry.rxBytes = getParsedLong(parsed, KEY_SNAP_RX_BYTES);
1205 entry.rxPackets = getParsedLong(parsed, KEY_SNAP_RX_PACKETS);
1206 entry.txBytes = getParsedLong(parsed, KEY_SNAP_TX_BYTES);
1207 entry.txPackets = getParsedLong(parsed, KEY_SNAP_TX_PACKETS);
1208
1209 // fold in active numbers, but only when active
1210 final boolean active = getParsedInt(parsed, KEY_ACTIVE) != 0;
1211 if (active) {
1212 entry.rxBytes += getParsedLong(parsed, KEY_RX_BYTES);
1213 entry.rxPackets += getParsedLong(parsed, KEY_RX_PACKETS);
1214 entry.txBytes += getParsedLong(parsed, KEY_TX_BYTES);
1215 entry.txPackets += getParsedLong(parsed, KEY_TX_PACKETS);
1216 }
1217
1218 stats.addValues(entry);
1219 }
1220 } catch (NullPointerException e) {
1221 throw new IllegalStateException("problem parsing stats: " + e);
1222 } catch (NumberFormatException e) {
1223 throw new IllegalStateException("problem parsing stats: " + e);
1224 } catch (IOException e) {
1225 throw new IllegalStateException("problem parsing stats: " + e);
1226 } finally {
1227 IoUtils.closeQuietly(reader);
1228 }
1229
1230 return stats;
1231 }
1232
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001233 @Override
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001234 public NetworkStats getNetworkStatsDetail() {
1235 mContext.enforceCallingOrSelfPermission(
1236 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
1237
Jeff Sharkey350083e2011-06-29 10:45:16 -07001238 if (mBandwidthControlEnabled) {
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001239 return getNetworkStatsDetailNetfilter(UID_ALL);
1240 } else {
1241 return getNetworkStatsDetailUidstat(UID_ALL);
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001242 }
San Mehat91cac642010-03-31 14:31:36 -07001243 }
1244
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001245 @Override
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001246 public void setInterfaceQuota(String iface, long quotaBytes) {
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001247 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1248
Jeff Sharkey350083e2011-06-29 10:45:16 -07001249 // silently discard when control disabled
1250 // TODO: eventually migrate to be always enabled
1251 if (!mBandwidthControlEnabled) return;
1252
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001253 synchronized (mQuotaLock) {
1254 if (mActiveQuotaIfaces.contains(iface)) {
1255 throw new IllegalStateException("iface " + iface + " already has quota");
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001256 }
1257
1258 final StringBuilder command = new StringBuilder();
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001259 command.append("bandwidth setiquota ").append(iface).append(" ").append(quotaBytes);
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001260
1261 try {
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001262 // TODO: support quota shared across interfaces
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001263 mConnector.doCommand(command.toString());
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001264 mActiveQuotaIfaces.add(iface);
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001265 } catch (NativeDaemonConnectorException e) {
1266 throw new IllegalStateException("Error communicating to native daemon", e);
1267 }
Ashish Sharma50fd36d2011-06-15 19:34:53 -07001268 }
1269 }
1270
1271 @Override
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001272 public void removeInterfaceQuota(String iface) {
1273 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1274
Jeff Sharkey350083e2011-06-29 10:45:16 -07001275 // silently discard when control disabled
1276 // TODO: eventually migrate to be always enabled
1277 if (!mBandwidthControlEnabled) return;
1278
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001279 synchronized (mQuotaLock) {
1280 if (!mActiveQuotaIfaces.contains(iface)) {
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001281 // TODO: eventually consider throwing
1282 return;
1283 }
1284
1285 final StringBuilder command = new StringBuilder();
1286 command.append("bandwidth removeiquota ").append(iface);
1287
1288 try {
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001289 // TODO: support quota shared across interfaces
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001290 mConnector.doCommand(command.toString());
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001291 mActiveQuotaIfaces.remove(iface);
1292 mActiveAlertIfaces.remove(iface);
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001293 } catch (NativeDaemonConnectorException e) {
1294 throw new IllegalStateException("Error communicating to native daemon", e);
1295 }
1296 }
1297 }
1298
1299 @Override
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001300 public void setInterfaceAlert(String iface, long alertBytes) {
1301 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1302
1303 // silently discard when control disabled
1304 // TODO: eventually migrate to be always enabled
1305 if (!mBandwidthControlEnabled) return;
1306
1307 // quick sanity check
1308 if (!mActiveQuotaIfaces.contains(iface)) {
1309 throw new IllegalStateException("setting alert requires existing quota on iface");
1310 }
1311
1312 synchronized (mQuotaLock) {
1313 if (mActiveAlertIfaces.contains(iface)) {
1314 throw new IllegalStateException("iface " + iface + " already has alert");
1315 }
1316
1317 final StringBuilder command = new StringBuilder();
1318 command.append("bandwidth setinterfacealert ").append(iface).append(" ").append(
1319 alertBytes);
1320
1321 try {
1322 // TODO: support alert shared across interfaces
1323 mConnector.doCommand(command.toString());
1324 mActiveAlertIfaces.add(iface);
1325 } catch (NativeDaemonConnectorException e) {
1326 throw new IllegalStateException("Error communicating to native daemon", e);
1327 }
1328 }
1329 }
1330
1331 @Override
1332 public void removeInterfaceAlert(String iface) {
1333 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1334
1335 // silently discard when control disabled
1336 // TODO: eventually migrate to be always enabled
1337 if (!mBandwidthControlEnabled) return;
1338
1339 synchronized (mQuotaLock) {
1340 if (!mActiveAlertIfaces.contains(iface)) {
1341 // TODO: eventually consider throwing
1342 return;
1343 }
1344
1345 final StringBuilder command = new StringBuilder();
1346 command.append("bandwidth removeinterfacealert ").append(iface);
1347
1348 try {
1349 // TODO: support alert shared across interfaces
1350 mConnector.doCommand(command.toString());
1351 mActiveAlertIfaces.remove(iface);
1352 } catch (NativeDaemonConnectorException e) {
1353 throw new IllegalStateException("Error communicating to native daemon", e);
1354 }
1355 }
1356 }
1357
1358 @Override
1359 public void setGlobalAlert(long alertBytes) {
1360 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1361
1362 // silently discard when control disabled
1363 // TODO: eventually migrate to be always enabled
1364 if (!mBandwidthControlEnabled) return;
1365
1366 final StringBuilder command = new StringBuilder();
1367 command.append("bandwidth setglobalalert ").append(alertBytes);
1368
1369 try {
1370 mConnector.doCommand(command.toString());
1371 } catch (NativeDaemonConnectorException e) {
1372 throw new IllegalStateException("Error communicating to native daemon", e);
1373 }
1374 }
1375
1376 @Override
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001377 public void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces) {
1378 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1379
Jeff Sharkey350083e2011-06-29 10:45:16 -07001380 // silently discard when control disabled
1381 // TODO: eventually migrate to be always enabled
1382 if (!mBandwidthControlEnabled) return;
1383
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001384 synchronized (mUidRejectOnQuota) {
1385 final boolean oldRejectOnQuota = mUidRejectOnQuota.get(uid, false);
1386 if (oldRejectOnQuota == rejectOnQuotaInterfaces) {
1387 // TODO: eventually consider throwing
1388 return;
1389 }
1390
1391 final StringBuilder command = new StringBuilder();
1392 command.append("bandwidth");
1393 if (rejectOnQuotaInterfaces) {
1394 command.append(" addnaughtyapps");
1395 } else {
1396 command.append(" removenaughtyapps");
1397 }
1398 command.append(" ").append(uid);
1399
1400 try {
1401 mConnector.doCommand(command.toString());
1402 if (rejectOnQuotaInterfaces) {
1403 mUidRejectOnQuota.put(uid, true);
1404 } else {
1405 mUidRejectOnQuota.delete(uid);
1406 }
1407 } catch (NativeDaemonConnectorException e) {
1408 throw new IllegalStateException("Error communicating to native daemon", e);
1409 }
Ashish Sharma50fd36d2011-06-15 19:34:53 -07001410 }
1411 }
1412
Jeff Sharkey63d27a92011-08-03 17:04:22 -07001413 @Override
1414 public boolean isBandwidthControlEnabled() {
1415 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1416 return mBandwidthControlEnabled;
1417 }
1418
1419 @Override
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001420 public NetworkStats getNetworkStatsUidDetail(int uid) {
1421 if (Binder.getCallingUid() != uid) {
1422 mContext.enforceCallingOrSelfPermission(
1423 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
1424 }
1425
Jeff Sharkey350083e2011-06-29 10:45:16 -07001426 if (mBandwidthControlEnabled) {
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001427 return getNetworkStatsDetailNetfilter(uid);
1428 } else {
1429 return getNetworkStatsDetailUidstat(uid);
1430 }
1431 }
1432
1433 /**
1434 * Build {@link NetworkStats} with detailed UID statistics.
1435 */
1436 private NetworkStats getNetworkStatsDetailNetfilter(int limitUid) {
1437 final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 24);
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001438 final NetworkStats.Entry entry = new NetworkStats.Entry();
1439
Jeff Sharkeya63ba592011-07-19 23:47:12 -07001440 // TODO: remove knownLines check once 5087722 verified
1441 final HashSet<String> knownLines = Sets.newHashSet();
Jeff Sharkeyb3d59572011-09-07 17:20:27 -07001442 // TODO: remove lastIdx check once 5270106 verified
JP Abgrall6acf39b2011-09-08 15:13:26 -07001443 int lastIdx;
Jeff Sharkeya63ba592011-07-19 23:47:12 -07001444
Jeff Sharkey4414cea2011-06-24 17:05:24 -07001445 final ArrayList<String> keys = Lists.newArrayList();
1446 final ArrayList<String> values = Lists.newArrayList();
1447 final HashMap<String, String> parsed = Maps.newHashMap();
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001448
1449 BufferedReader reader = null;
Jeff Sharkeyb3d59572011-09-07 17:20:27 -07001450 String line = null;
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001451 try {
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001452 reader = new BufferedReader(new FileReader(mStatsXtUid));
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001453
Jeff Sharkey4414cea2011-06-24 17:05:24 -07001454 // parse first line as header
Jeff Sharkeyb3d59572011-09-07 17:20:27 -07001455 line = reader.readLine();
Jeff Sharkey4414cea2011-06-24 17:05:24 -07001456 splitLine(line, keys);
JP Abgrall6acf39b2011-09-08 15:13:26 -07001457 lastIdx = 1;
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001458
Jeff Sharkey4414cea2011-06-24 17:05:24 -07001459 // parse remaining lines
1460 while ((line = reader.readLine()) != null) {
1461 splitLine(line, values);
1462 parseLine(keys, values, parsed);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001463
Jeff Sharkeya63ba592011-07-19 23:47:12 -07001464 if (!knownLines.add(line)) {
Jeff Sharkeyb3d59572011-09-07 17:20:27 -07001465 throw new IllegalStateException("duplicate proc entry: " + line);
Jeff Sharkeya63ba592011-07-19 23:47:12 -07001466 }
1467
Jeff Sharkeyb3d59572011-09-07 17:20:27 -07001468 final int idx = getParsedInt(parsed, KEY_IDX);
JP Abgrall6acf39b2011-09-08 15:13:26 -07001469 if (idx != lastIdx + 1) {
Jeff Sharkeyb3d59572011-09-07 17:20:27 -07001470 throw new IllegalStateException(
1471 "inconsistent idx=" + idx + " after lastIdx=" + lastIdx);
1472 }
1473 lastIdx = idx;
Jeff Sharkeyd03fd3f2011-06-19 20:55:09 -07001474
Jeff Sharkeyb3d59572011-09-07 17:20:27 -07001475 entry.iface = parsed.get(KEY_IFACE);
1476 entry.uid = getParsedInt(parsed, KEY_UID);
1477 entry.set = getParsedInt(parsed, KEY_COUNTER_SET);
1478 entry.tag = kernelToTag(parsed.get(KEY_TAG_HEX));
1479 entry.rxBytes = getParsedLong(parsed, KEY_RX_BYTES);
1480 entry.rxPackets = getParsedLong(parsed, KEY_RX_PACKETS);
1481 entry.txBytes = getParsedLong(parsed, KEY_TX_BYTES);
1482 entry.txPackets = getParsedLong(parsed, KEY_TX_PACKETS);
1483
1484 if (limitUid == UID_ALL || limitUid == entry.uid) {
1485 stats.addValues(entry);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001486 }
1487 }
Jeff Sharkey558a2322011-08-24 15:42:09 -07001488 } catch (NullPointerException e) {
Jeff Sharkeyb3d59572011-09-07 17:20:27 -07001489 throw new IllegalStateException("problem parsing line: " + line, e);
Jeff Sharkey558a2322011-08-24 15:42:09 -07001490 } catch (NumberFormatException e) {
Jeff Sharkeyb3d59572011-09-07 17:20:27 -07001491 throw new IllegalStateException("problem parsing line: " + line, e);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001492 } catch (IOException e) {
Jeff Sharkeyb3d59572011-09-07 17:20:27 -07001493 throw new IllegalStateException("problem parsing line: " + line, e);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001494 } finally {
1495 IoUtils.closeQuietly(reader);
1496 }
1497
Jeff Sharkey4a971222011-06-11 22:16:55 -07001498 return stats;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001499 }
1500
Jeff Sharkeya63ba592011-07-19 23:47:12 -07001501 private static int getParsedInt(HashMap<String, String> parsed, String key) {
1502 final String value = parsed.get(key);
1503 return value != null ? Integer.parseInt(value) : 0;
1504 }
1505
1506 private static long getParsedLong(HashMap<String, String> parsed, String key) {
1507 final String value = parsed.get(key);
1508 return value != null ? Long.parseLong(value) : 0;
1509 }
1510
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001511 /**
1512 * Build {@link NetworkStats} with detailed UID statistics.
1513 *
1514 * @deprecated since this uses older "uid_stat" data, and doesn't provide
1515 * tag-level granularity or additional variables.
1516 */
1517 @Deprecated
1518 private NetworkStats getNetworkStatsDetailUidstat(int limitUid) {
1519 final String[] knownUids;
1520 if (limitUid == UID_ALL) {
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001521 knownUids = fileListWithoutNull(mStatsUid);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001522 } else {
1523 knownUids = new String[] { String.valueOf(limitUid) };
1524 }
1525
1526 final NetworkStats stats = new NetworkStats(
1527 SystemClock.elapsedRealtime(), knownUids.length);
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001528 final NetworkStats.Entry entry = new NetworkStats.Entry();
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001529 for (String uid : knownUids) {
1530 final int uidInt = Integer.parseInt(uid);
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001531 final File uidPath = new File(mStatsUid, uid);
1532
1533 entry.iface = IFACE_ALL;
1534 entry.uid = uidInt;
1535 entry.tag = TAG_NONE;
1536 entry.rxBytes = readSingleLongFromFile(new File(uidPath, "tcp_rcv"));
1537 entry.rxPackets = readSingleLongFromFile(new File(uidPath, "tcp_rcv_pkt"));
1538 entry.txBytes = readSingleLongFromFile(new File(uidPath, "tcp_snd"));
1539 entry.txPackets = readSingleLongFromFile(new File(uidPath, "tcp_snd_pkt"));
1540
1541 stats.addValues(entry);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001542 }
1543
1544 return stats;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001545 }
1546
Jeff Sharkeycdd02c5d2011-09-16 01:52:49 -07001547 @Override
1548 public NetworkStats getNetworkStatsTethering(String[] ifacePairs) {
1549 mContext.enforceCallingOrSelfPermission(
1550 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
1551
1552 if (ifacePairs.length % 2 != 0) {
1553 throw new IllegalArgumentException(
1554 "unexpected ifacePairs; length=" + ifacePairs.length);
1555 }
1556
1557 final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1);
1558 for (int i = 0; i < ifacePairs.length; i += 2) {
1559 final String ifaceIn = ifacePairs[i];
1560 final String ifaceOut = ifacePairs[i + 1];
1561 if (ifaceIn != null && ifaceOut != null) {
1562 stats.combineValues(getNetworkStatsTethering(ifaceIn, ifaceOut));
1563 }
1564 }
1565 return stats;
1566 }
1567
1568 private NetworkStats.Entry getNetworkStatsTethering(String ifaceIn, String ifaceOut) {
1569 final StringBuilder command = new StringBuilder();
1570 command.append("bandwidth gettetherstats ").append(ifaceIn).append(" ").append(ifaceOut);
1571
1572 final String rsp;
1573 try {
1574 rsp = mConnector.doCommand(command.toString()).get(0);
1575 } catch (NativeDaemonConnectorException e) {
1576 throw new IllegalStateException("Error communicating to native daemon", e);
1577 }
1578
1579 final String[] tok = rsp.split(" ");
1580 /* Expecting: "code ifaceIn ifaceOut rx_bytes rx_packets tx_bytes tx_packets" */
1581 if (tok.length != 7) {
1582 throw new IllegalStateException("Native daemon returned unexpected result: " + rsp);
1583 }
1584
1585 final int code;
1586 try {
1587 code = Integer.parseInt(tok[0]);
1588 } catch (NumberFormatException e) {
1589 throw new IllegalStateException(
1590 "Failed to parse native daemon return code for " + ifaceIn + " " + ifaceOut);
1591 }
1592 if (code != NetdResponseCode.TetheringStatsResult) {
1593 throw new IllegalStateException(
1594 "Unexpected return code from native daemon for " + ifaceIn + " " + ifaceOut);
1595 }
1596
1597 try {
1598 final NetworkStats.Entry entry = new NetworkStats.Entry();
1599 entry.iface = ifaceIn;
Jeff Sharkey905b5892011-09-30 15:19:49 -07001600 entry.uid = UID_TETHERING;
Jeff Sharkeycdd02c5d2011-09-16 01:52:49 -07001601 entry.set = SET_DEFAULT;
1602 entry.tag = TAG_NONE;
1603 entry.rxBytes = Long.parseLong(tok[3]);
1604 entry.rxPackets = Long.parseLong(tok[4]);
1605 entry.txBytes = Long.parseLong(tok[5]);
1606 entry.txPackets = Long.parseLong(tok[6]);
1607 return entry;
1608 } catch (NumberFormatException e) {
1609 throw new IllegalStateException(
1610 "problem parsing tethering stats for " + ifaceIn + " " + ifaceOut + ": " + e);
1611 }
1612 }
1613
San Mehatf0db6e12010-04-07 15:22:10 -07001614 public void setInterfaceThrottle(String iface, int rxKbps, int txKbps) {
San Mehat91cac642010-03-31 14:31:36 -07001615 mContext.enforceCallingOrSelfPermission(
1616 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -07001617 try {
1618 mConnector.doCommand(String.format(
1619 "interface setthrottle %s %d %d", iface, rxKbps, txKbps));
1620 } catch (NativeDaemonConnectorException e) {
1621 Slog.e(TAG, "Error communicating with native daemon to set throttle", e);
1622 }
San Mehat91cac642010-03-31 14:31:36 -07001623 }
1624
1625 private int getInterfaceThrottle(String iface, boolean rx) {
1626 mContext.enforceCallingOrSelfPermission(
1627 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
1628 try {
Kenny Roota80ce062010-06-01 13:23:53 -07001629 String rsp;
1630 try {
1631 rsp = mConnector.doCommand(
1632 String.format("interface getthrottle %s %s", iface,
1633 (rx ? "rx" : "tx"))).get(0);
1634 } catch (NativeDaemonConnectorException e) {
1635 Slog.e(TAG, "Error communicating with native daemon to getthrottle", e);
1636 return -1;
1637 }
1638
1639 String[] tok = rsp.split(" ");
1640 if (tok.length < 2) {
1641 Slog.e(TAG, "Malformed response to getthrottle command");
1642 return -1;
1643 }
1644
San Mehat91cac642010-03-31 14:31:36 -07001645 int code;
1646 try {
1647 code = Integer.parseInt(tok[0]);
1648 } catch (NumberFormatException nfe) {
1649 Slog.e(TAG, String.format("Error parsing code %s", tok[0]));
1650 return -1;
1651 }
1652 if ((rx && code != NetdResponseCode.InterfaceRxThrottleResult) || (
1653 !rx && code != NetdResponseCode.InterfaceTxThrottleResult)) {
1654 Slog.e(TAG, String.format("Unexpected response code %d", code));
1655 return -1;
1656 }
1657 return Integer.parseInt(tok[1]);
1658 } catch (Exception e) {
1659 Slog.e(TAG, String.format(
1660 "Failed to read interface %s throttle value", (rx ? "rx" : "tx")), e);
1661 }
1662 return -1;
1663 }
1664
1665 public int getInterfaceRxThrottle(String iface) {
1666 return getInterfaceThrottle(iface, true);
1667 }
1668
1669 public int getInterfaceTxThrottle(String iface) {
1670 return getInterfaceThrottle(iface, false);
1671 }
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001672
1673 /**
Jeff Sharkey4414cea2011-06-24 17:05:24 -07001674 * Split given line into {@link ArrayList}.
1675 */
1676 private static void splitLine(String line, ArrayList<String> outSplit) {
1677 outSplit.clear();
1678
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001679 final StringTokenizer t = new StringTokenizer(line, " \t\n\r\f:");
Jeff Sharkey4414cea2011-06-24 17:05:24 -07001680 while (t.hasMoreTokens()) {
1681 outSplit.add(t.nextToken());
1682 }
1683 }
1684
1685 /**
1686 * Zip the two given {@link ArrayList} as key and value pairs into
1687 * {@link HashMap}.
1688 */
1689 private static void parseLine(
1690 ArrayList<String> keys, ArrayList<String> values, HashMap<String, String> outParsed) {
1691 outParsed.clear();
1692
1693 final int size = Math.min(keys.size(), values.size());
1694 for (int i = 0; i < size; i++) {
1695 outParsed.put(keys.get(i), values.get(i));
1696 }
1697 }
1698
1699 /**
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001700 * Utility method to read a single plain-text {@link Long} from the given
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001701 * {@link File}, usually from a {@code /proc/} filesystem.
1702 */
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001703 private static long readSingleLongFromFile(File file) {
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001704 try {
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001705 final byte[] buffer = IoUtils.readFileAsByteArray(file.toString());
1706 return Long.parseLong(new String(buffer).trim());
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001707 } catch (NumberFormatException e) {
1708 return -1;
1709 } catch (IOException e) {
1710 return -1;
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001711 }
1712 }
Jean-Baptiste Querud5299ff2011-07-07 08:46:09 -07001713
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001714 /**
1715 * Wrapper for {@link File#list()} that returns empty array instead of
1716 * {@code null}.
1717 */
1718 private static String[] fileListWithoutNull(File file) {
1719 final String[] list = file.list();
1720 return list != null ? list : new String[0];
1721 }
1722
Mattias Falk7475c0c2011-04-04 16:10:36 +02001723 public void setDefaultInterfaceForDns(String iface) throws IllegalStateException {
1724 mContext.enforceCallingOrSelfPermission(
1725 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
1726 try {
1727 String cmd = "resolver setdefaultif " + iface;
1728
1729 mConnector.doCommand(cmd);
1730 } catch (NativeDaemonConnectorException e) {
1731 throw new IllegalStateException(
1732 "Error communicating with native daemon to set default interface", e);
1733 }
1734 }
1735
1736 public void setDnsServersForInterface(String iface, String[] servers)
1737 throws IllegalStateException {
1738 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_NETWORK_STATE,
1739 "NetworkManagementService");
1740 try {
1741 String cmd = "resolver setifdns " + iface;
1742 for (String s : servers) {
Robert Greenwalt572b7042011-07-25 17:00:13 -07001743 InetAddress a = NetworkUtils.numericToInetAddress(s);
1744 if (a.isAnyLocalAddress() == false) {
1745 cmd += " " + a.getHostAddress();
Mattias Falk7475c0c2011-04-04 16:10:36 +02001746 }
1747 }
Mattias Falk7475c0c2011-04-04 16:10:36 +02001748 mConnector.doCommand(cmd);
Robert Greenwalt572b7042011-07-25 17:00:13 -07001749 } catch (IllegalArgumentException e) {
1750 throw new IllegalStateException("Error setting dnsn for interface", e);
Mattias Falk7475c0c2011-04-04 16:10:36 +02001751 } catch (NativeDaemonConnectorException e) {
1752 throw new IllegalStateException(
Robert Greenwalt572b7042011-07-25 17:00:13 -07001753 "Error communicating with native daemon to set dns for interface", e);
Mattias Falk7475c0c2011-04-04 16:10:36 +02001754 }
1755 }
1756
1757 public void flushDefaultDnsCache() throws IllegalStateException {
1758 mContext.enforceCallingOrSelfPermission(
1759 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
1760 try {
1761 String cmd = "resolver flushdefaultif";
1762
1763 mConnector.doCommand(cmd);
1764 } catch (NativeDaemonConnectorException e) {
1765 throw new IllegalStateException(
1766 "Error communicating with native deamon to flush default interface", e);
1767 }
1768 }
1769
1770 public void flushInterfaceDnsCache(String iface) throws IllegalStateException {
1771 mContext.enforceCallingOrSelfPermission(
1772 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
1773 try {
1774 String cmd = "resolver flushif " + iface;
1775
1776 mConnector.doCommand(cmd);
1777 } catch (NativeDaemonConnectorException e) {
1778 throw new IllegalStateException(
Robert Greenwalt572b7042011-07-25 17:00:13 -07001779 "Error communicating with native daemon to flush interface " + iface, e);
Mattias Falk7475c0c2011-04-04 16:10:36 +02001780 }
1781 }
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07001782
1783 /** {@inheritDoc} */
1784 public void monitor() {
1785 if (mConnector != null) {
1786 mConnector.monitor();
1787 }
1788 }
Jeff Sharkey47eb1022011-08-25 17:48:52 -07001789
1790 @Override
1791 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1792 mContext.enforceCallingOrSelfPermission(DUMP, TAG);
1793
1794 pw.print("Bandwidth control enabled: "); pw.println(mBandwidthControlEnabled);
1795
1796 synchronized (mQuotaLock) {
1797 pw.print("Active quota ifaces: "); pw.println(mActiveQuotaIfaces.toString());
1798 pw.print("Active alert ifaces: "); pw.println(mActiveAlertIfaces.toString());
1799 }
1800
1801 synchronized (mUidRejectOnQuota) {
1802 pw.print("UID reject on quota ifaces: [");
1803 final int size = mUidRejectOnQuota.size();
1804 for (int i = 0; i < size; i++) {
1805 pw.print(mUidRejectOnQuota.keyAt(i));
1806 if (i < size - 1) pw.print(",");
1807 }
1808 pw.println("]");
1809 }
1810 }
San Mehat873f2142010-01-14 10:25:07 -08001811}