blob: abb780be8a573f3c091c4106d0b4c61be23a7a14 [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 */
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -070071class NetworkManagementService extends INetworkManagementService.Stub implements Watchdog.Monitor {
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 Sharkeyfa23c5a2011-08-09 21:44:24 -0700142 private volatile boolean mBandwidthControlEnabled;
Jeff Sharkey350083e2011-06-29 10:45:16 -0700143
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);
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -0700165
166 // Add ourself to the Watchdog monitors.
167 Watchdog.getInstance().addMonitor(this);
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700168 }
169
170 public static NetworkManagementService create(Context context) throws InterruptedException {
Jeff Sharkey4414cea2011-06-24 17:05:24 -0700171 NetworkManagementService service = new NetworkManagementService(
172 context, new File("/proc/"));
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700173 if (DBG) Slog.d(TAG, "Creating NetworkManagementService");
174 service.mThread.start();
175 if (DBG) Slog.d(TAG, "Awaiting socket connection");
176 service.mConnectedSignal.await();
177 if (DBG) Slog.d(TAG, "Connected");
178 return service;
San Mehat873f2142010-01-14 10:25:07 -0800179 }
180
Jeff Sharkey4414cea2011-06-24 17:05:24 -0700181 // @VisibleForTesting
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700182 public static NetworkManagementService createForTest(
183 Context context, File procRoot, boolean bandwidthControlEnabled) {
Jeff Sharkey4414cea2011-06-24 17:05:24 -0700184 // TODO: eventually connect with mock netd
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700185 final NetworkManagementService service = new NetworkManagementService(context, procRoot);
186 service.mBandwidthControlEnabled = bandwidthControlEnabled;
187 return service;
Jeff Sharkey4414cea2011-06-24 17:05:24 -0700188 }
189
Jeff Sharkey350083e2011-06-29 10:45:16 -0700190 public void systemReady() {
Jeff Sharkey350083e2011-06-29 10:45:16 -0700191 // only enable bandwidth control when support exists, and requested by
192 // system setting.
Jeff Sharkey350083e2011-06-29 10:45:16 -0700193 final boolean hasKernelSupport = new File("/proc/net/xt_qtaguid/ctrl").exists();
194 final boolean shouldEnable =
Jeff Sharkey05355c32011-08-09 14:44:19 -0700195 Settings.Secure.getInt(mContext.getContentResolver(), NETSTATS_ENABLED, 1) != 0;
Jeff Sharkey350083e2011-06-29 10:45:16 -0700196
Jeff Sharkey350083e2011-06-29 10:45:16 -0700197 if (hasKernelSupport && shouldEnable) {
198 Slog.d(TAG, "enabling bandwidth control");
199 try {
200 mConnector.doCommand("bandwidth enable");
201 mBandwidthControlEnabled = true;
202 } catch (NativeDaemonConnectorException e) {
203 Slog.e(TAG, "problem enabling bandwidth controls", e);
204 }
205 } else {
206 Slog.d(TAG, "not enabling bandwidth control");
207 }
Jeff Sharkey62a2c8f2011-07-13 15:24:02 -0700208
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700209 SystemProperties.set(PROP_QTAGUID_ENABLED, mBandwidthControlEnabled ? "1" : "0");
Jeff Sharkey350083e2011-06-29 10:45:16 -0700210 }
211
San Mehat4d02d002010-01-22 16:07:46 -0800212 public void registerObserver(INetworkManagementEventObserver obs) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800213 Slog.d(TAG, "Registering observer");
San Mehat4d02d002010-01-22 16:07:46 -0800214 mObservers.add(obs);
215 }
216
217 public void unregisterObserver(INetworkManagementEventObserver obs) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800218 Slog.d(TAG, "Unregistering observer");
San Mehat4d02d002010-01-22 16:07:46 -0800219 mObservers.remove(mObservers.indexOf(obs));
220 }
221
222 /**
Mike J. Chen6143f5f2011-06-23 15:17:51 -0700223 * Notify our observers of an interface status change
San Mehat4d02d002010-01-22 16:07:46 -0800224 */
Mike J. Chen6143f5f2011-06-23 15:17:51 -0700225 private void notifyInterfaceStatusChanged(String iface, boolean up) {
San Mehat4d02d002010-01-22 16:07:46 -0800226 for (INetworkManagementEventObserver obs : mObservers) {
227 try {
Mike J. Chen6143f5f2011-06-23 15:17:51 -0700228 obs.interfaceStatusChanged(iface, up);
229 } catch (Exception ex) {
230 Slog.w(TAG, "Observer notifier failed", ex);
231 }
232 }
233 }
234
235 /**
Mike J. Chenf59c7d02011-06-23 15:33:15 -0700236 * Notify our observers of an interface link state change
Mike J. Chen6143f5f2011-06-23 15:17:51 -0700237 * (typically, an Ethernet cable has been plugged-in or unplugged).
238 */
239 private void notifyInterfaceLinkStateChanged(String iface, boolean up) {
240 for (INetworkManagementEventObserver obs : mObservers) {
241 try {
242 obs.interfaceLinkStateChanged(iface, up);
San Mehat4d02d002010-01-22 16:07:46 -0800243 } catch (Exception ex) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800244 Slog.w(TAG, "Observer notifier failed", ex);
San Mehat4d02d002010-01-22 16:07:46 -0800245 }
246 }
247 }
248
249 /**
250 * Notify our observers of an interface addition.
251 */
252 private void notifyInterfaceAdded(String iface) {
253 for (INetworkManagementEventObserver obs : mObservers) {
254 try {
255 obs.interfaceAdded(iface);
256 } catch (Exception ex) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800257 Slog.w(TAG, "Observer notifier failed", ex);
San Mehat4d02d002010-01-22 16:07:46 -0800258 }
259 }
260 }
261
262 /**
263 * Notify our observers of an interface removal.
264 */
265 private void notifyInterfaceRemoved(String iface) {
266 for (INetworkManagementEventObserver obs : mObservers) {
267 try {
268 obs.interfaceRemoved(iface);
269 } 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
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700275 /**
JP Abgrall12b933d2011-07-14 18:09:22 -0700276 * Notify our observers of a limit reached.
277 */
278 private void notifyLimitReached(String limitName, String iface) {
279 for (INetworkManagementEventObserver obs : mObservers) {
280 try {
281 obs.limitReached(limitName, iface);
282 Slog.d(TAG, "Observer notified limit reached for " + limitName + " " + iface);
283 } catch (Exception ex) {
284 Slog.w(TAG, "Observer notifier failed", ex);
285 }
286 }
287 }
288
289 /**
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700290 * Let us know the daemon is connected
291 */
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -0700292 protected void onDaemonConnected() {
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700293 if (DBG) Slog.d(TAG, "onConnected");
294 mConnectedSignal.countDown();
295 }
296
San Mehat4d02d002010-01-22 16:07:46 -0800297
San Mehat873f2142010-01-14 10:25:07 -0800298 //
299 // Netd Callback handling
300 //
301
302 class NetdCallbackReceiver implements INativeDaemonConnectorCallbacks {
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -0700303 /** {@inheritDoc} */
San Mehat873f2142010-01-14 10:25:07 -0800304 public void onDaemonConnected() {
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -0700305 NetworkManagementService.this.onDaemonConnected();
San Mehat873f2142010-01-14 10:25:07 -0800306 }
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -0700307
308 /** {@inheritDoc} */
San Mehat873f2142010-01-14 10:25:07 -0800309 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 Sherifff5600612011-06-16 10:26:28 -0700449 /* TODO: This is right now a IPv4 only function. Works for wifi which loses its
450 IPv6 addresses on interface down, but we need to do full clean up here */
451 public void clearInterfaceAddresses(String iface) throws IllegalStateException {
452 String cmd = String.format("interface clearaddrs %s", iface);
453 try {
454 mConnector.doCommand(cmd);
455 } catch (NativeDaemonConnectorException e) {
456 throw new IllegalStateException(
457 "Unable to communicate with native daemon to interface clearallips - " + e);
458 }
459 }
460
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -0700461 public void addRoute(String interfaceName, RouteInfo route) {
462 modifyRoute(interfaceName, ADD, route);
463 }
464
465 public void removeRoute(String interfaceName, RouteInfo route) {
466 modifyRoute(interfaceName, REMOVE, route);
467 }
468
469 private void modifyRoute(String interfaceName, int action, RouteInfo route) {
470 ArrayList<String> rsp;
471
472 StringBuilder cmd;
473
474 switch (action) {
475 case ADD:
476 {
477 cmd = new StringBuilder("interface route add " + interfaceName);
478 break;
479 }
480 case REMOVE:
481 {
482 cmd = new StringBuilder("interface route remove " + interfaceName);
483 break;
484 }
485 default:
486 throw new IllegalStateException("Unknown action type " + action);
487 }
488
489 // create triplet: dest-ip-addr prefixlength gateway-ip-addr
490 LinkAddress la = route.getDestination();
491 cmd.append(' ');
492 cmd.append(la.getAddress().getHostAddress());
493 cmd.append(' ');
494 cmd.append(la.getNetworkPrefixLength());
495 cmd.append(' ');
496 if (route.getGateway() == null) {
497 if (la.getAddress() instanceof Inet4Address) {
498 cmd.append("0.0.0.0");
499 } else {
500 cmd.append ("::0");
501 }
502 } else {
503 cmd.append(route.getGateway().getHostAddress());
504 }
505 try {
506 rsp = mConnector.doCommand(cmd.toString());
507 } catch (NativeDaemonConnectorException e) {
508 throw new IllegalStateException(
509 "Unable to communicate with native dameon to add routes - "
510 + e);
511 }
512
513 for (String line : rsp) {
514 Log.v(TAG, "add route response is " + line);
515 }
516 }
517
518 private ArrayList<String> readRouteList(String filename) {
519 FileInputStream fstream = null;
520 ArrayList<String> list = new ArrayList<String>();
521
522 try {
523 fstream = new FileInputStream(filename);
524 DataInputStream in = new DataInputStream(fstream);
525 BufferedReader br = new BufferedReader(new InputStreamReader(in));
526 String s;
527
528 // throw away the title line
529
530 while (((s = br.readLine()) != null) && (s.length() != 0)) {
531 list.add(s);
532 }
533 } catch (IOException ex) {
534 // return current list, possibly empty
535 } finally {
536 if (fstream != null) {
537 try {
538 fstream.close();
539 } catch (IOException ex) {}
540 }
541 }
542
543 return list;
544 }
545
546 public RouteInfo[] getRoutes(String interfaceName) {
547 ArrayList<RouteInfo> routes = new ArrayList<RouteInfo>();
548
549 // v4 routes listed as:
550 // iface dest-addr gateway-addr flags refcnt use metric netmask mtu window IRTT
551 for (String s : readRouteList("/proc/net/route")) {
552 String[] fields = s.split("\t");
553
554 if (fields.length > 7) {
555 String iface = fields[0];
556
557 if (interfaceName.equals(iface)) {
558 String dest = fields[1];
559 String gate = fields[2];
560 String flags = fields[3]; // future use?
561 String mask = fields[7];
562 try {
563 // address stored as a hex string, ex: 0014A8C0
564 InetAddress destAddr =
565 NetworkUtils.intToInetAddress((int)Long.parseLong(dest, 16));
566 int prefixLength =
567 NetworkUtils.netmaskIntToPrefixLength(
568 (int)Long.parseLong(mask, 16));
569 LinkAddress linkAddress = new LinkAddress(destAddr, prefixLength);
570
571 // address stored as a hex string, ex 0014A8C0
572 InetAddress gatewayAddr =
573 NetworkUtils.intToInetAddress((int)Long.parseLong(gate, 16));
574
575 RouteInfo route = new RouteInfo(linkAddress, gatewayAddr);
576 routes.add(route);
577 } catch (Exception e) {
578 Log.e(TAG, "Error parsing route " + s + " : " + e);
579 continue;
580 }
581 }
582 }
583 }
584
585 // v6 routes listed as:
586 // dest-addr prefixlength ?? ?? gateway-addr ?? ?? ?? ?? iface
587 for (String s : readRouteList("/proc/net/ipv6_route")) {
588 String[]fields = s.split("\\s+");
589 if (fields.length > 9) {
590 String iface = fields[9].trim();
591 if (interfaceName.equals(iface)) {
592 String dest = fields[0];
593 String prefix = fields[1];
594 String gate = fields[4];
595
596 try {
597 // prefix length stored as a hex string, ex 40
598 int prefixLength = Integer.parseInt(prefix, 16);
599
600 // address stored as a 32 char hex string
601 // ex fe800000000000000000000000000000
602 InetAddress destAddr = NetworkUtils.hexToInet6Address(dest);
603 LinkAddress linkAddress = new LinkAddress(destAddr, prefixLength);
604
605 InetAddress gateAddr = NetworkUtils.hexToInet6Address(gate);
606
607 RouteInfo route = new RouteInfo(linkAddress, gateAddr);
608 routes.add(route);
609 } catch (Exception e) {
610 Log.e(TAG, "Error parsing route " + s + " : " + e);
611 continue;
612 }
613 }
614 }
615 }
616 return (RouteInfo[]) routes.toArray(new RouteInfo[0]);
617 }
618
San Mehat873f2142010-01-14 10:25:07 -0800619 public void shutdown() {
620 if (mContext.checkCallingOrSelfPermission(
621 android.Manifest.permission.SHUTDOWN)
622 != PackageManager.PERMISSION_GRANTED) {
623 throw new SecurityException("Requires SHUTDOWN permission");
624 }
625
Joe Onorato8a9b2202010-02-26 18:56:32 -0800626 Slog.d(TAG, "Shutting down");
San Mehat873f2142010-01-14 10:25:07 -0800627 }
628
629 public boolean getIpForwardingEnabled() throws IllegalStateException{
630 mContext.enforceCallingOrSelfPermission(
631 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
632
Kenny Roota80ce062010-06-01 13:23:53 -0700633 ArrayList<String> rsp;
634 try {
635 rsp = mConnector.doCommand("ipfwd status");
636 } catch (NativeDaemonConnectorException e) {
637 throw new IllegalStateException(
638 "Unable to communicate with native daemon to ipfwd status");
639 }
San Mehat873f2142010-01-14 10:25:07 -0800640
641 for (String line : rsp) {
Kenny Roota80ce062010-06-01 13:23:53 -0700642 String[] tok = line.split(" ");
643 if (tok.length < 3) {
644 Slog.e(TAG, "Malformed response from native daemon: " + line);
645 return false;
646 }
647
San Mehat873f2142010-01-14 10:25:07 -0800648 int code = Integer.parseInt(tok[0]);
649 if (code == NetdResponseCode.IpFwdStatusResult) {
650 // 211 Forwarding <enabled/disabled>
Kenny Roota80ce062010-06-01 13:23:53 -0700651 return "enabled".equals(tok[2]);
San Mehat873f2142010-01-14 10:25:07 -0800652 } else {
653 throw new IllegalStateException(String.format("Unexpected response code %d", code));
654 }
655 }
656 throw new IllegalStateException("Got an empty response");
657 }
658
659 public void setIpForwardingEnabled(boolean enable) throws IllegalStateException {
660 mContext.enforceCallingOrSelfPermission(
661 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
662 mConnector.doCommand(String.format("ipfwd %sable", (enable ? "en" : "dis")));
663 }
664
Robert Greenwaltbfb7bfa2010-03-24 16:03:21 -0700665 public void startTethering(String[] dhcpRange)
San Mehat873f2142010-01-14 10:25:07 -0800666 throws IllegalStateException {
667 mContext.enforceCallingOrSelfPermission(
668 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Robert Greenwaltbfb7bfa2010-03-24 16:03:21 -0700669 // cmd is "tether start first_start first_stop second_start second_stop ..."
670 // an odd number of addrs will fail
671 String cmd = "tether start";
672 for (String d : dhcpRange) {
673 cmd += " " + d;
674 }
Kenny Roota80ce062010-06-01 13:23:53 -0700675
676 try {
677 mConnector.doCommand(cmd);
678 } catch (NativeDaemonConnectorException e) {
679 throw new IllegalStateException("Unable to communicate to native daemon");
680 }
San Mehat873f2142010-01-14 10:25:07 -0800681 }
682
683 public void stopTethering() throws IllegalStateException {
684 mContext.enforceCallingOrSelfPermission(
685 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700686 try {
687 mConnector.doCommand("tether stop");
688 } catch (NativeDaemonConnectorException e) {
689 throw new IllegalStateException("Unable to communicate to native daemon to stop tether");
690 }
San Mehat873f2142010-01-14 10:25:07 -0800691 }
692
693 public boolean isTetheringStarted() throws IllegalStateException {
694 mContext.enforceCallingOrSelfPermission(
695 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
696
Kenny Roota80ce062010-06-01 13:23:53 -0700697 ArrayList<String> rsp;
698 try {
699 rsp = mConnector.doCommand("tether status");
700 } catch (NativeDaemonConnectorException e) {
701 throw new IllegalStateException(
702 "Unable to communicate to native daemon to get tether status");
703 }
San Mehat873f2142010-01-14 10:25:07 -0800704
705 for (String line : rsp) {
Kenny Roota80ce062010-06-01 13:23:53 -0700706 String[] tok = line.split(" ");
707 if (tok.length < 3) {
708 throw new IllegalStateException("Malformed response for tether status: " + line);
709 }
San Mehat873f2142010-01-14 10:25:07 -0800710 int code = Integer.parseInt(tok[0]);
711 if (code == NetdResponseCode.TetherStatusResult) {
712 // XXX: Tethering services <started/stopped> <TBD>...
Kenny Roota80ce062010-06-01 13:23:53 -0700713 return "started".equals(tok[2]);
San Mehat873f2142010-01-14 10:25:07 -0800714 } else {
715 throw new IllegalStateException(String.format("Unexpected response code %d", code));
716 }
717 }
718 throw new IllegalStateException("Got an empty response");
719 }
720
721 public void tetherInterface(String iface) throws IllegalStateException {
722 mContext.enforceCallingOrSelfPermission(
723 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700724 try {
725 mConnector.doCommand("tether interface add " + iface);
726 } catch (NativeDaemonConnectorException e) {
727 throw new IllegalStateException(
728 "Unable to communicate to native daemon for adding tether interface");
729 }
San Mehat873f2142010-01-14 10:25:07 -0800730 }
731
732 public void untetherInterface(String iface) {
733 mContext.enforceCallingOrSelfPermission(
734 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700735 try {
736 mConnector.doCommand("tether interface remove " + iface);
737 } catch (NativeDaemonConnectorException e) {
738 throw new IllegalStateException(
739 "Unable to communicate to native daemon for removing tether interface");
740 }
San Mehat873f2142010-01-14 10:25:07 -0800741 }
742
743 public String[] listTetheredInterfaces() throws IllegalStateException {
744 mContext.enforceCallingOrSelfPermission(
745 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700746 try {
747 return mConnector.doListCommand(
748 "tether interface list", NetdResponseCode.TetherInterfaceListResult);
749 } catch (NativeDaemonConnectorException e) {
750 throw new IllegalStateException(
751 "Unable to communicate to native daemon for listing tether interfaces");
752 }
San Mehat873f2142010-01-14 10:25:07 -0800753 }
754
755 public void setDnsForwarders(String[] dns) throws IllegalStateException {
756 mContext.enforceCallingOrSelfPermission(
757 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
758 try {
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800759 String cmd = "tether dns set";
San Mehat873f2142010-01-14 10:25:07 -0800760 for (String s : dns) {
Robert Greenwalte5903732011-02-22 16:00:42 -0800761 cmd += " " + NetworkUtils.numericToInetAddress(s).getHostAddress();
San Mehat873f2142010-01-14 10:25:07 -0800762 }
Kenny Roota80ce062010-06-01 13:23:53 -0700763 try {
764 mConnector.doCommand(cmd);
765 } catch (NativeDaemonConnectorException e) {
766 throw new IllegalStateException(
767 "Unable to communicate to native daemon for setting tether dns");
768 }
Robert Greenwalte5903732011-02-22 16:00:42 -0800769 } catch (IllegalArgumentException e) {
San Mehat873f2142010-01-14 10:25:07 -0800770 throw new IllegalStateException("Error resolving dns name", e);
771 }
772 }
773
774 public String[] getDnsForwarders() throws IllegalStateException {
775 mContext.enforceCallingOrSelfPermission(
776 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700777 try {
778 return mConnector.doListCommand(
779 "tether dns list", NetdResponseCode.TetherDnsFwdTgtListResult);
780 } catch (NativeDaemonConnectorException e) {
781 throw new IllegalStateException(
782 "Unable to communicate to native daemon for listing tether dns");
783 }
San Mehat873f2142010-01-14 10:25:07 -0800784 }
785
786 public void enableNat(String internalInterface, String externalInterface)
787 throws IllegalStateException {
788 mContext.enforceCallingOrSelfPermission(
789 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700790 try {
791 mConnector.doCommand(
792 String.format("nat enable %s %s", internalInterface, externalInterface));
793 } catch (NativeDaemonConnectorException e) {
794 throw new IllegalStateException(
795 "Unable to communicate to native daemon for enabling NAT interface");
796 }
San Mehat873f2142010-01-14 10:25:07 -0800797 }
798
799 public void disableNat(String internalInterface, String externalInterface)
800 throws IllegalStateException {
801 mContext.enforceCallingOrSelfPermission(
802 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700803 try {
804 mConnector.doCommand(
805 String.format("nat disable %s %s", internalInterface, externalInterface));
806 } catch (NativeDaemonConnectorException e) {
807 throw new IllegalStateException(
808 "Unable to communicate to native daemon for disabling NAT interface");
809 }
San Mehat873f2142010-01-14 10:25:07 -0800810 }
San Mehat72759df2010-01-19 13:50:37 -0800811
812 public String[] listTtys() throws IllegalStateException {
813 mContext.enforceCallingOrSelfPermission(
814 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700815 try {
816 return mConnector.doListCommand("list_ttys", NetdResponseCode.TtyListResult);
817 } catch (NativeDaemonConnectorException e) {
818 throw new IllegalStateException(
819 "Unable to communicate to native daemon for listing TTYs");
820 }
San Mehat72759df2010-01-19 13:50:37 -0800821 }
822
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800823 public void attachPppd(String tty, String localAddr, String remoteAddr, String dns1Addr,
824 String dns2Addr) throws IllegalStateException {
San Mehat72759df2010-01-19 13:50:37 -0800825 try {
826 mContext.enforceCallingOrSelfPermission(
827 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800828 mConnector.doCommand(String.format("pppd attach %s %s %s %s %s", tty,
Robert Greenwalte5903732011-02-22 16:00:42 -0800829 NetworkUtils.numericToInetAddress(localAddr).getHostAddress(),
830 NetworkUtils.numericToInetAddress(remoteAddr).getHostAddress(),
831 NetworkUtils.numericToInetAddress(dns1Addr).getHostAddress(),
832 NetworkUtils.numericToInetAddress(dns2Addr).getHostAddress()));
833 } catch (IllegalArgumentException e) {
San Mehat72759df2010-01-19 13:50:37 -0800834 throw new IllegalStateException("Error resolving addr", e);
Kenny Roota80ce062010-06-01 13:23:53 -0700835 } catch (NativeDaemonConnectorException e) {
836 throw new IllegalStateException("Error communicating to native daemon to attach pppd", e);
San Mehat72759df2010-01-19 13:50:37 -0800837 }
838 }
839
840 public void detachPppd(String tty) throws IllegalStateException {
841 mContext.enforceCallingOrSelfPermission(
842 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700843 try {
844 mConnector.doCommand(String.format("pppd detach %s", tty));
845 } catch (NativeDaemonConnectorException e) {
846 throw new IllegalStateException("Error communicating to native daemon to detach pppd", e);
847 }
San Mehat72759df2010-01-19 13:50:37 -0800848 }
Robert Greenwaltce1200d2010-02-18 11:25:54 -0800849
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700850 public void startAccessPoint(WifiConfiguration wifiConfig, String wlanIface, String softapIface)
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800851 throws IllegalStateException {
852 mContext.enforceCallingOrSelfPermission(
853 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
854 mContext.enforceCallingOrSelfPermission(
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700855 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700856 try {
Kenny Roota80ce062010-06-01 13:23:53 -0700857 mConnector.doCommand(String.format("softap fwreload " + wlanIface + " AP"));
858 mConnector.doCommand(String.format("softap start " + wlanIface));
859 if (wifiConfig == null) {
860 mConnector.doCommand(String.format("softap set " + wlanIface + " " + softapIface));
861 } else {
862 /**
863 * softap set arg1 arg2 arg3 [arg4 arg5 arg6 arg7 arg8]
864 * argv1 - wlan interface
865 * argv2 - softap interface
866 * argv3 - SSID
867 * argv4 - Security
868 * argv5 - Key
869 * argv6 - Channel
870 * argv7 - Preamble
871 * argv8 - Max SCB
872 */
Irfan Sheriffec8d23a2011-02-16 17:00:33 -0800873 String str = String.format("softap set " + wlanIface + " " + softapIface +
874 " %s %s %s", convertQuotedString(wifiConfig.SSID),
875 getSecurityType(wifiConfig),
876 convertQuotedString(wifiConfig.preSharedKey));
Kenny Roota80ce062010-06-01 13:23:53 -0700877 mConnector.doCommand(str);
878 }
879 mConnector.doCommand(String.format("softap startap"));
880 } catch (NativeDaemonConnectorException e) {
881 throw new IllegalStateException("Error communicating to native daemon to start softap", e);
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -0800882 }
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800883 }
884
Irfan Sheriffa6e559e2010-05-24 14:55:42 -0700885 private String convertQuotedString(String s) {
Irfan Sheriff7baec0f2010-05-26 17:16:47 -0700886 if (s == null) {
887 return s;
888 }
889 /* Replace \ with \\, then " with \" and add quotes at end */
890 return '"' + s.replaceAll("\\\\","\\\\\\\\").replaceAll("\"","\\\\\"") + '"';
Irfan Sheriffa6e559e2010-05-24 14:55:42 -0700891 }
892
Irfan Sheriffec8d23a2011-02-16 17:00:33 -0800893 private String getSecurityType(WifiConfiguration wifiConfig) {
894 switch (wifiConfig.getAuthType()) {
895 case KeyMgmt.WPA_PSK:
896 return "wpa-psk";
897 case KeyMgmt.WPA2_PSK:
898 return "wpa2-psk";
899 default:
900 return "open";
901 }
902 }
903
Irfan Sheriff23eb2972011-07-22 15:21:10 -0700904 public void stopAccessPoint(String wlanIface) throws IllegalStateException {
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800905 mContext.enforceCallingOrSelfPermission(
906 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
907 mContext.enforceCallingOrSelfPermission(
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700908 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700909 try {
910 mConnector.doCommand("softap stopap");
Irfan Sheriff23eb2972011-07-22 15:21:10 -0700911 mConnector.doCommand("softap stop " + wlanIface);
912 mConnector.doCommand(String.format("softap fwreload " + wlanIface + " STA"));
Kenny Roota80ce062010-06-01 13:23:53 -0700913 } catch (NativeDaemonConnectorException e) {
914 throw new IllegalStateException("Error communicating to native daemon to stop soft AP",
915 e);
916 }
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800917 }
918
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700919 public void setAccessPoint(WifiConfiguration wifiConfig, String wlanIface, String softapIface)
920 throws IllegalStateException {
921 mContext.enforceCallingOrSelfPermission(
922 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
923 mContext.enforceCallingOrSelfPermission(
924 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700925 try {
926 if (wifiConfig == null) {
927 mConnector.doCommand(String.format("softap set " + wlanIface + " " + softapIface));
928 } else {
929 String str = String.format("softap set " + wlanIface + " " + softapIface
930 + " %s %s %s", convertQuotedString(wifiConfig.SSID),
Irfan Sheriffec8d23a2011-02-16 17:00:33 -0800931 getSecurityType(wifiConfig),
Kenny Roota80ce062010-06-01 13:23:53 -0700932 convertQuotedString(wifiConfig.preSharedKey));
933 mConnector.doCommand(str);
934 }
935 } catch (NativeDaemonConnectorException e) {
936 throw new IllegalStateException("Error communicating to native daemon to set soft AP",
937 e);
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700938 }
939 }
San Mehat91cac642010-03-31 14:31:36 -0700940
941 private long getInterfaceCounter(String iface, boolean rx) {
942 mContext.enforceCallingOrSelfPermission(
943 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
944 try {
Kenny Roota80ce062010-06-01 13:23:53 -0700945 String rsp;
946 try {
947 rsp = mConnector.doCommand(
948 String.format("interface read%scounter %s", (rx ? "rx" : "tx"), iface)).get(0);
949 } catch (NativeDaemonConnectorException e1) {
950 Slog.e(TAG, "Error communicating with native daemon", e1);
951 return -1;
952 }
953
954 String[] tok = rsp.split(" ");
955 if (tok.length < 2) {
956 Slog.e(TAG, String.format("Malformed response for reading %s interface",
957 (rx ? "rx" : "tx")));
958 return -1;
959 }
960
San Mehat91cac642010-03-31 14:31:36 -0700961 int code;
962 try {
963 code = Integer.parseInt(tok[0]);
964 } catch (NumberFormatException nfe) {
965 Slog.e(TAG, String.format("Error parsing code %s", tok[0]));
966 return -1;
967 }
968 if ((rx && code != NetdResponseCode.InterfaceRxCounterResult) || (
969 !rx && code != NetdResponseCode.InterfaceTxCounterResult)) {
970 Slog.e(TAG, String.format("Unexpected response code %d", code));
971 return -1;
972 }
973 return Long.parseLong(tok[1]);
974 } catch (Exception e) {
975 Slog.e(TAG, String.format(
976 "Failed to read interface %s counters", (rx ? "rx" : "tx")), e);
977 }
978 return -1;
979 }
980
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700981 @Override
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700982 public NetworkStats getNetworkStatsSummary() {
983 mContext.enforceCallingOrSelfPermission(
984 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
985
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700986 final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6);
987 final NetworkStats.Entry entry = new NetworkStats.Entry();
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700988
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700989 final HashSet<String> activeIfaces = Sets.newHashSet();
990 final ArrayList<String> values = Lists.newArrayList();
991
992 BufferedReader reader = null;
993 try {
994 reader = new BufferedReader(new FileReader(mStatsIface));
995
996 // skip first two header lines
997 reader.readLine();
998 reader.readLine();
999
1000 // parse remaining lines
1001 String line;
1002 while ((line = reader.readLine()) != null) {
1003 splitLine(line, values);
1004
1005 try {
1006 entry.iface = values.get(0);
1007 entry.uid = UID_ALL;
1008 entry.tag = TAG_NONE;
1009 entry.rxBytes = Long.parseLong(values.get(1));
1010 entry.rxPackets = Long.parseLong(values.get(2));
1011 entry.txBytes = Long.parseLong(values.get(9));
1012 entry.txPackets = Long.parseLong(values.get(10));
1013
1014 activeIfaces.add(entry.iface);
1015 stats.addValues(entry);
1016 } catch (NumberFormatException e) {
1017 Slog.w(TAG, "problem parsing stats row '" + line + "': " + e);
1018 }
1019 }
1020 } catch (IOException e) {
1021 Slog.w(TAG, "problem parsing stats: " + e);
1022 } finally {
1023 IoUtils.closeQuietly(reader);
1024 }
1025
1026 if (DBG) Slog.d(TAG, "recorded active stats from " + activeIfaces);
1027
1028 // splice in stats from any disabled ifaces
1029 if (mBandwidthControlEnabled) {
1030 final HashSet<String> xtIfaces = Sets.newHashSet(fileListWithoutNull(mStatsXtIface));
1031 xtIfaces.removeAll(activeIfaces);
1032
1033 for (String iface : xtIfaces) {
1034 final File ifacePath = new File(mStatsXtIface, iface);
1035
1036 entry.iface = iface;
1037 entry.uid = UID_ALL;
1038 entry.tag = TAG_NONE;
1039 entry.rxBytes = readSingleLongFromFile(new File(ifacePath, "rx_bytes"));
1040 entry.rxPackets = readSingleLongFromFile(new File(ifacePath, "rx_packets"));
1041 entry.txBytes = readSingleLongFromFile(new File(ifacePath, "tx_bytes"));
1042 entry.txPackets = readSingleLongFromFile(new File(ifacePath, "tx_packets"));
1043
1044 stats.addValues(entry);
1045 }
1046
1047 if (DBG) Slog.d(TAG, "recorded stale stats from " + xtIfaces);
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001048 }
1049
Jeff Sharkey4a971222011-06-11 22:16:55 -07001050 return stats;
San Mehat91cac642010-03-31 14:31:36 -07001051 }
1052
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001053 @Override
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001054 public NetworkStats getNetworkStatsDetail() {
1055 mContext.enforceCallingOrSelfPermission(
1056 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
1057
Jeff Sharkey350083e2011-06-29 10:45:16 -07001058 if (mBandwidthControlEnabled) {
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001059 return getNetworkStatsDetailNetfilter(UID_ALL);
1060 } else {
1061 return getNetworkStatsDetailUidstat(UID_ALL);
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001062 }
San Mehat91cac642010-03-31 14:31:36 -07001063 }
1064
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001065 @Override
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001066 public void setInterfaceQuota(String iface, long quotaBytes) {
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001067 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1068
Jeff Sharkey350083e2011-06-29 10:45:16 -07001069 // silently discard when control disabled
1070 // TODO: eventually migrate to be always enabled
1071 if (!mBandwidthControlEnabled) return;
1072
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001073 synchronized (mQuotaLock) {
1074 if (mActiveQuotaIfaces.contains(iface)) {
1075 throw new IllegalStateException("iface " + iface + " already has quota");
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001076 }
1077
1078 final StringBuilder command = new StringBuilder();
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001079 command.append("bandwidth setiquota ").append(iface).append(" ").append(quotaBytes);
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001080
1081 try {
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001082 // TODO: support quota shared across interfaces
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001083 mConnector.doCommand(command.toString());
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001084 mActiveQuotaIfaces.add(iface);
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001085 } catch (NativeDaemonConnectorException e) {
1086 throw new IllegalStateException("Error communicating to native daemon", e);
1087 }
Ashish Sharma50fd36d2011-06-15 19:34:53 -07001088 }
1089 }
1090
1091 @Override
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001092 public void removeInterfaceQuota(String iface) {
1093 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1094
Jeff Sharkey350083e2011-06-29 10:45:16 -07001095 // silently discard when control disabled
1096 // TODO: eventually migrate to be always enabled
1097 if (!mBandwidthControlEnabled) return;
1098
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001099 synchronized (mQuotaLock) {
1100 if (!mActiveQuotaIfaces.contains(iface)) {
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001101 // TODO: eventually consider throwing
1102 return;
1103 }
1104
1105 final StringBuilder command = new StringBuilder();
1106 command.append("bandwidth removeiquota ").append(iface);
1107
1108 try {
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001109 // TODO: support quota shared across interfaces
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001110 mConnector.doCommand(command.toString());
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001111 mActiveQuotaIfaces.remove(iface);
1112 mActiveAlertIfaces.remove(iface);
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001113 } catch (NativeDaemonConnectorException e) {
1114 throw new IllegalStateException("Error communicating to native daemon", e);
1115 }
1116 }
1117 }
1118
1119 @Override
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001120 public void setInterfaceAlert(String iface, long alertBytes) {
1121 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1122
1123 // silently discard when control disabled
1124 // TODO: eventually migrate to be always enabled
1125 if (!mBandwidthControlEnabled) return;
1126
1127 // quick sanity check
1128 if (!mActiveQuotaIfaces.contains(iface)) {
1129 throw new IllegalStateException("setting alert requires existing quota on iface");
1130 }
1131
1132 synchronized (mQuotaLock) {
1133 if (mActiveAlertIfaces.contains(iface)) {
1134 throw new IllegalStateException("iface " + iface + " already has alert");
1135 }
1136
1137 final StringBuilder command = new StringBuilder();
1138 command.append("bandwidth setinterfacealert ").append(iface).append(" ").append(
1139 alertBytes);
1140
1141 try {
1142 // TODO: support alert shared across interfaces
1143 mConnector.doCommand(command.toString());
1144 mActiveAlertIfaces.add(iface);
1145 } catch (NativeDaemonConnectorException e) {
1146 throw new IllegalStateException("Error communicating to native daemon", e);
1147 }
1148 }
1149 }
1150
1151 @Override
1152 public void removeInterfaceAlert(String iface) {
1153 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1154
1155 // silently discard when control disabled
1156 // TODO: eventually migrate to be always enabled
1157 if (!mBandwidthControlEnabled) return;
1158
1159 synchronized (mQuotaLock) {
1160 if (!mActiveAlertIfaces.contains(iface)) {
1161 // TODO: eventually consider throwing
1162 return;
1163 }
1164
1165 final StringBuilder command = new StringBuilder();
1166 command.append("bandwidth removeinterfacealert ").append(iface);
1167
1168 try {
1169 // TODO: support alert shared across interfaces
1170 mConnector.doCommand(command.toString());
1171 mActiveAlertIfaces.remove(iface);
1172 } catch (NativeDaemonConnectorException e) {
1173 throw new IllegalStateException("Error communicating to native daemon", e);
1174 }
1175 }
1176 }
1177
1178 @Override
1179 public void setGlobalAlert(long alertBytes) {
1180 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1181
1182 // silently discard when control disabled
1183 // TODO: eventually migrate to be always enabled
1184 if (!mBandwidthControlEnabled) return;
1185
1186 final StringBuilder command = new StringBuilder();
1187 command.append("bandwidth setglobalalert ").append(alertBytes);
1188
1189 try {
1190 mConnector.doCommand(command.toString());
1191 } catch (NativeDaemonConnectorException e) {
1192 throw new IllegalStateException("Error communicating to native daemon", e);
1193 }
1194 }
1195
1196 @Override
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001197 public void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces) {
1198 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1199
Jeff Sharkey350083e2011-06-29 10:45:16 -07001200 // silently discard when control disabled
1201 // TODO: eventually migrate to be always enabled
1202 if (!mBandwidthControlEnabled) return;
1203
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001204 synchronized (mUidRejectOnQuota) {
1205 final boolean oldRejectOnQuota = mUidRejectOnQuota.get(uid, false);
1206 if (oldRejectOnQuota == rejectOnQuotaInterfaces) {
1207 // TODO: eventually consider throwing
1208 return;
1209 }
1210
1211 final StringBuilder command = new StringBuilder();
1212 command.append("bandwidth");
1213 if (rejectOnQuotaInterfaces) {
1214 command.append(" addnaughtyapps");
1215 } else {
1216 command.append(" removenaughtyapps");
1217 }
1218 command.append(" ").append(uid);
1219
1220 try {
1221 mConnector.doCommand(command.toString());
1222 if (rejectOnQuotaInterfaces) {
1223 mUidRejectOnQuota.put(uid, true);
1224 } else {
1225 mUidRejectOnQuota.delete(uid);
1226 }
1227 } catch (NativeDaemonConnectorException e) {
1228 throw new IllegalStateException("Error communicating to native daemon", e);
1229 }
Ashish Sharma50fd36d2011-06-15 19:34:53 -07001230 }
1231 }
1232
Jeff Sharkey63d27a92011-08-03 17:04:22 -07001233 @Override
1234 public boolean isBandwidthControlEnabled() {
1235 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1236 return mBandwidthControlEnabled;
1237 }
1238
1239 @Override
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001240 public NetworkStats getNetworkStatsUidDetail(int uid) {
1241 if (Binder.getCallingUid() != uid) {
1242 mContext.enforceCallingOrSelfPermission(
1243 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
1244 }
1245
Jeff Sharkey350083e2011-06-29 10:45:16 -07001246 if (mBandwidthControlEnabled) {
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001247 return getNetworkStatsDetailNetfilter(uid);
1248 } else {
1249 return getNetworkStatsDetailUidstat(uid);
1250 }
1251 }
1252
1253 /**
1254 * Build {@link NetworkStats} with detailed UID statistics.
1255 */
1256 private NetworkStats getNetworkStatsDetailNetfilter(int limitUid) {
1257 final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 24);
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001258 final NetworkStats.Entry entry = new NetworkStats.Entry();
1259
Jeff Sharkeya63ba592011-07-19 23:47:12 -07001260 // TODO: remove knownLines check once 5087722 verified
1261 final HashSet<String> knownLines = Sets.newHashSet();
1262
Jeff Sharkey4414cea2011-06-24 17:05:24 -07001263 final ArrayList<String> keys = Lists.newArrayList();
1264 final ArrayList<String> values = Lists.newArrayList();
1265 final HashMap<String, String> parsed = Maps.newHashMap();
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001266
1267 BufferedReader reader = null;
1268 try {
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001269 reader = new BufferedReader(new FileReader(mStatsXtUid));
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001270
Jeff Sharkey4414cea2011-06-24 17:05:24 -07001271 // parse first line as header
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001272 String line = reader.readLine();
Jeff Sharkey4414cea2011-06-24 17:05:24 -07001273 splitLine(line, keys);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001274
Jeff Sharkey4414cea2011-06-24 17:05:24 -07001275 // parse remaining lines
1276 while ((line = reader.readLine()) != null) {
1277 splitLine(line, values);
1278 parseLine(keys, values, parsed);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001279
Jeff Sharkeya63ba592011-07-19 23:47:12 -07001280 if (!knownLines.add(line)) {
1281 throw new IllegalStateException("encountered duplicate proc entry");
1282 }
1283
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001284 try {
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001285 entry.iface = parsed.get(KEY_IFACE);
Jeff Sharkeya63ba592011-07-19 23:47:12 -07001286 entry.tag = kernelToTag(parsed.get(KEY_TAG_HEX));
1287 entry.uid = getParsedInt(parsed, KEY_UID);
1288 entry.rxBytes = getParsedLong(parsed, KEY_RX_BYTES);
1289 entry.rxPackets = getParsedLong(parsed, KEY_RX_PACKETS);
1290 entry.txBytes = getParsedLong(parsed, KEY_TX_BYTES);
1291 entry.txPackets = getParsedLong(parsed, KEY_TX_PACKETS);
Jeff Sharkeyd03fd3f2011-06-19 20:55:09 -07001292
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001293 if (limitUid == UID_ALL || limitUid == entry.uid) {
1294 stats.addValues(entry);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001295 }
1296 } catch (NumberFormatException e) {
Jeff Sharkey4414cea2011-06-24 17:05:24 -07001297 Slog.w(TAG, "problem parsing stats row '" + line + "': " + e);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001298 }
1299 }
1300 } catch (IOException e) {
1301 Slog.w(TAG, "problem parsing stats: " + e);
1302 } finally {
1303 IoUtils.closeQuietly(reader);
1304 }
1305
Jeff Sharkey4a971222011-06-11 22:16:55 -07001306 return stats;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001307 }
1308
Jeff Sharkeya63ba592011-07-19 23:47:12 -07001309 private static int getParsedInt(HashMap<String, String> parsed, String key) {
1310 final String value = parsed.get(key);
1311 return value != null ? Integer.parseInt(value) : 0;
1312 }
1313
1314 private static long getParsedLong(HashMap<String, String> parsed, String key) {
1315 final String value = parsed.get(key);
1316 return value != null ? Long.parseLong(value) : 0;
1317 }
1318
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001319 /**
1320 * Build {@link NetworkStats} with detailed UID statistics.
1321 *
1322 * @deprecated since this uses older "uid_stat" data, and doesn't provide
1323 * tag-level granularity or additional variables.
1324 */
1325 @Deprecated
1326 private NetworkStats getNetworkStatsDetailUidstat(int limitUid) {
1327 final String[] knownUids;
1328 if (limitUid == UID_ALL) {
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001329 knownUids = fileListWithoutNull(mStatsUid);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001330 } else {
1331 knownUids = new String[] { String.valueOf(limitUid) };
1332 }
1333
1334 final NetworkStats stats = new NetworkStats(
1335 SystemClock.elapsedRealtime(), knownUids.length);
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001336 final NetworkStats.Entry entry = new NetworkStats.Entry();
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001337 for (String uid : knownUids) {
1338 final int uidInt = Integer.parseInt(uid);
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001339 final File uidPath = new File(mStatsUid, uid);
1340
1341 entry.iface = IFACE_ALL;
1342 entry.uid = uidInt;
1343 entry.tag = TAG_NONE;
1344 entry.rxBytes = readSingleLongFromFile(new File(uidPath, "tcp_rcv"));
1345 entry.rxPackets = readSingleLongFromFile(new File(uidPath, "tcp_rcv_pkt"));
1346 entry.txBytes = readSingleLongFromFile(new File(uidPath, "tcp_snd"));
1347 entry.txPackets = readSingleLongFromFile(new File(uidPath, "tcp_snd_pkt"));
1348
1349 stats.addValues(entry);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001350 }
1351
1352 return stats;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001353 }
1354
San Mehatf0db6e12010-04-07 15:22:10 -07001355 public void setInterfaceThrottle(String iface, int rxKbps, int txKbps) {
San Mehat91cac642010-03-31 14:31:36 -07001356 mContext.enforceCallingOrSelfPermission(
1357 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -07001358 try {
1359 mConnector.doCommand(String.format(
1360 "interface setthrottle %s %d %d", iface, rxKbps, txKbps));
1361 } catch (NativeDaemonConnectorException e) {
1362 Slog.e(TAG, "Error communicating with native daemon to set throttle", e);
1363 }
San Mehat91cac642010-03-31 14:31:36 -07001364 }
1365
1366 private int getInterfaceThrottle(String iface, boolean rx) {
1367 mContext.enforceCallingOrSelfPermission(
1368 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
1369 try {
Kenny Roota80ce062010-06-01 13:23:53 -07001370 String rsp;
1371 try {
1372 rsp = mConnector.doCommand(
1373 String.format("interface getthrottle %s %s", iface,
1374 (rx ? "rx" : "tx"))).get(0);
1375 } catch (NativeDaemonConnectorException e) {
1376 Slog.e(TAG, "Error communicating with native daemon to getthrottle", e);
1377 return -1;
1378 }
1379
1380 String[] tok = rsp.split(" ");
1381 if (tok.length < 2) {
1382 Slog.e(TAG, "Malformed response to getthrottle command");
1383 return -1;
1384 }
1385
San Mehat91cac642010-03-31 14:31:36 -07001386 int code;
1387 try {
1388 code = Integer.parseInt(tok[0]);
1389 } catch (NumberFormatException nfe) {
1390 Slog.e(TAG, String.format("Error parsing code %s", tok[0]));
1391 return -1;
1392 }
1393 if ((rx && code != NetdResponseCode.InterfaceRxThrottleResult) || (
1394 !rx && code != NetdResponseCode.InterfaceTxThrottleResult)) {
1395 Slog.e(TAG, String.format("Unexpected response code %d", code));
1396 return -1;
1397 }
1398 return Integer.parseInt(tok[1]);
1399 } catch (Exception e) {
1400 Slog.e(TAG, String.format(
1401 "Failed to read interface %s throttle value", (rx ? "rx" : "tx")), e);
1402 }
1403 return -1;
1404 }
1405
1406 public int getInterfaceRxThrottle(String iface) {
1407 return getInterfaceThrottle(iface, true);
1408 }
1409
1410 public int getInterfaceTxThrottle(String iface) {
1411 return getInterfaceThrottle(iface, false);
1412 }
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001413
1414 /**
Jeff Sharkey4414cea2011-06-24 17:05:24 -07001415 * Split given line into {@link ArrayList}.
1416 */
1417 private static void splitLine(String line, ArrayList<String> outSplit) {
1418 outSplit.clear();
1419
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001420 final StringTokenizer t = new StringTokenizer(line, " \t\n\r\f:");
Jeff Sharkey4414cea2011-06-24 17:05:24 -07001421 while (t.hasMoreTokens()) {
1422 outSplit.add(t.nextToken());
1423 }
1424 }
1425
1426 /**
1427 * Zip the two given {@link ArrayList} as key and value pairs into
1428 * {@link HashMap}.
1429 */
1430 private static void parseLine(
1431 ArrayList<String> keys, ArrayList<String> values, HashMap<String, String> outParsed) {
1432 outParsed.clear();
1433
1434 final int size = Math.min(keys.size(), values.size());
1435 for (int i = 0; i < size; i++) {
1436 outParsed.put(keys.get(i), values.get(i));
1437 }
1438 }
1439
1440 /**
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001441 * Utility method to read a single plain-text {@link Long} from the given
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001442 * {@link File}, usually from a {@code /proc/} filesystem.
1443 */
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001444 private static long readSingleLongFromFile(File file) {
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001445 try {
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001446 final byte[] buffer = IoUtils.readFileAsByteArray(file.toString());
1447 return Long.parseLong(new String(buffer).trim());
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001448 } catch (NumberFormatException e) {
1449 return -1;
1450 } catch (IOException e) {
1451 return -1;
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001452 }
1453 }
Jean-Baptiste Querud5299ff2011-07-07 08:46:09 -07001454
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001455 /**
1456 * Wrapper for {@link File#list()} that returns empty array instead of
1457 * {@code null}.
1458 */
1459 private static String[] fileListWithoutNull(File file) {
1460 final String[] list = file.list();
1461 return list != null ? list : new String[0];
1462 }
1463
Mattias Falk7475c0c2011-04-04 16:10:36 +02001464 public void setDefaultInterfaceForDns(String iface) throws IllegalStateException {
1465 mContext.enforceCallingOrSelfPermission(
1466 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
1467 try {
1468 String cmd = "resolver setdefaultif " + iface;
1469
1470 mConnector.doCommand(cmd);
1471 } catch (NativeDaemonConnectorException e) {
1472 throw new IllegalStateException(
1473 "Error communicating with native daemon to set default interface", e);
1474 }
1475 }
1476
1477 public void setDnsServersForInterface(String iface, String[] servers)
1478 throws IllegalStateException {
1479 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_NETWORK_STATE,
1480 "NetworkManagementService");
1481 try {
1482 String cmd = "resolver setifdns " + iface;
1483 for (String s : servers) {
Robert Greenwalt572b7042011-07-25 17:00:13 -07001484 InetAddress a = NetworkUtils.numericToInetAddress(s);
1485 if (a.isAnyLocalAddress() == false) {
1486 cmd += " " + a.getHostAddress();
Mattias Falk7475c0c2011-04-04 16:10:36 +02001487 }
1488 }
Mattias Falk7475c0c2011-04-04 16:10:36 +02001489 mConnector.doCommand(cmd);
Robert Greenwalt572b7042011-07-25 17:00:13 -07001490 } catch (IllegalArgumentException e) {
1491 throw new IllegalStateException("Error setting dnsn for interface", e);
Mattias Falk7475c0c2011-04-04 16:10:36 +02001492 } catch (NativeDaemonConnectorException e) {
1493 throw new IllegalStateException(
Robert Greenwalt572b7042011-07-25 17:00:13 -07001494 "Error communicating with native daemon to set dns for interface", e);
Mattias Falk7475c0c2011-04-04 16:10:36 +02001495 }
1496 }
1497
1498 public void flushDefaultDnsCache() throws IllegalStateException {
1499 mContext.enforceCallingOrSelfPermission(
1500 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
1501 try {
1502 String cmd = "resolver flushdefaultif";
1503
1504 mConnector.doCommand(cmd);
1505 } catch (NativeDaemonConnectorException e) {
1506 throw new IllegalStateException(
1507 "Error communicating with native deamon to flush default interface", e);
1508 }
1509 }
1510
1511 public void flushInterfaceDnsCache(String iface) throws IllegalStateException {
1512 mContext.enforceCallingOrSelfPermission(
1513 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
1514 try {
1515 String cmd = "resolver flushif " + iface;
1516
1517 mConnector.doCommand(cmd);
1518 } catch (NativeDaemonConnectorException e) {
1519 throw new IllegalStateException(
Robert Greenwalt572b7042011-07-25 17:00:13 -07001520 "Error communicating with native daemon to flush interface " + iface, e);
Mattias Falk7475c0c2011-04-04 16:10:36 +02001521 }
1522 }
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07001523
1524 /** {@inheritDoc} */
1525 public void monitor() {
1526 if (mConnector != null) {
1527 mConnector.monitor();
1528 }
1529 }
San Mehat873f2142010-01-14 10:25:07 -08001530}