blob: 39d2b1c30889e15c03f5dd5e42843da8d9aff0aa [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 Sharkey1b5a2a92011-06-18 18:34:16 -070024
San Mehat873f2142010-01-14 10:25:07 -080025import android.content.Context;
San Mehat873f2142010-01-14 10:25:07 -080026import android.content.pm.PackageManager;
San Mehat4d02d002010-01-22 16:07:46 -080027import android.net.INetworkManagementEventObserver;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070028import android.net.InterfaceConfiguration;
Robert Greenwalted126402011-01-28 15:34:55 -080029import android.net.LinkAddress;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070030import android.net.NetworkStats;
Robert Greenwalted126402011-01-28 15:34:55 -080031import android.net.NetworkUtils;
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -070032import android.net.RouteInfo;
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -080033import android.net.wifi.WifiConfiguration;
34import android.net.wifi.WifiConfiguration.KeyMgmt;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070035import android.os.Binder;
San Mehat873f2142010-01-14 10:25:07 -080036import android.os.INetworkManagementService;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070037import android.os.SystemClock;
Marco Nelissen62dbb222010-02-18 10:56:30 -080038import android.os.SystemProperties;
Jeff Sharkey350083e2011-06-29 10:45:16 -070039import android.provider.Settings;
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -080040import android.util.Log;
Joe Onorato8a9b2202010-02-26 18:56:32 -080041import android.util.Slog;
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -070042import android.util.SparseBooleanArray;
San Mehat873f2142010-01-14 10:25:07 -080043
Jeff Sharkey4414cea2011-06-24 17:05:24 -070044import com.google.android.collect.Lists;
45import com.google.android.collect.Maps;
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -070046import com.google.android.collect.Sets;
Jeff Sharkey4414cea2011-06-24 17:05:24 -070047
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -070048import java.io.BufferedReader;
49import java.io.DataInputStream;
San Mehat873f2142010-01-14 10:25:07 -080050import java.io.File;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070051import java.io.FileInputStream;
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -070052import java.io.FileReader;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070053import java.io.IOException;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070054import java.io.InputStreamReader;
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -070055import java.net.Inet4Address;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070056import java.net.InetAddress;
San Mehat873f2142010-01-14 10:25:07 -080057import java.net.UnknownHostException;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070058import java.util.ArrayList;
Jeff Sharkey4414cea2011-06-24 17:05:24 -070059import java.util.HashMap;
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -070060import java.util.HashSet;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070061import java.util.NoSuchElementException;
62import java.util.StringTokenizer;
Robert Greenwalte5c3afb2010-09-22 14:32:35 -070063import java.util.concurrent.CountDownLatch;
San Mehat873f2142010-01-14 10:25:07 -080064
Jeff Sharkey9a13f362011-04-26 16:25:36 -070065import libcore.io.IoUtils;
66
San Mehat873f2142010-01-14 10:25:07 -080067/**
68 * @hide
69 */
70class NetworkManagementService extends INetworkManagementService.Stub {
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070071 private static final String TAG = "NetworkManagementService";
Dianne Hackborncef65ee2010-09-30 18:27:22 -070072 private static final boolean DBG = false;
Kenny Root305bcbf2010-09-03 07:56:38 -070073 private static final String NETD_TAG = "NetdConnector";
74
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -070075 private static final int ADD = 1;
76 private static final int REMOVE = 2;
77
Jeff Sharkey4414cea2011-06-24 17:05:24 -070078 /** Path to {@code /proc/uid_stat}. */
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -070079 @Deprecated
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -070080 private final File mStatsUid;
81 /** Path to {@code /proc/net/dev}. */
82 private final File mStatsIface;
Jeff Sharkey4414cea2011-06-24 17:05:24 -070083 /** Path to {@code /proc/net/xt_qtaguid/stats}. */
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -070084 private final File mStatsXtUid;
85 /** Path to {@code /proc/net/xt_qtaguid/iface_stat}. */
86 private final File mStatsXtIface;
Jeff Sharkey4414cea2011-06-24 17:05:24 -070087
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -070088 /** {@link #mStatsXtUid} headers. */
Jeff Sharkey4414cea2011-06-24 17:05:24 -070089 private static final String KEY_IFACE = "iface";
90 private static final String KEY_TAG_HEX = "acct_tag_hex";
91 private static final String KEY_UID = "uid_tag_int";
92 private static final String KEY_RX = "rx_bytes";
93 private static final String KEY_TX = "tx_bytes";
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070094
San Mehat873f2142010-01-14 10:25:07 -080095 class NetdResponseCode {
JP Abgrall12b933d2011-07-14 18:09:22 -070096 /* Keep in sync with system/netd/ResponseCode.h */
San Mehat873f2142010-01-14 10:25:07 -080097 public static final int InterfaceListResult = 110;
98 public static final int TetherInterfaceListResult = 111;
99 public static final int TetherDnsFwdTgtListResult = 112;
San Mehat72759df2010-01-19 13:50:37 -0800100 public static final int TtyListResult = 113;
San Mehat873f2142010-01-14 10:25:07 -0800101
102 public static final int TetherStatusResult = 210;
103 public static final int IpFwdStatusResult = 211;
San Mehated4fc8a2010-01-22 12:28:36 -0800104 public static final int InterfaceGetCfgResult = 213;
Robert Greenwalte3253922010-02-18 09:23:25 -0800105 public static final int SoftapStatusResult = 214;
San Mehat91cac642010-03-31 14:31:36 -0700106 public static final int InterfaceRxCounterResult = 216;
107 public static final int InterfaceTxCounterResult = 217;
108 public static final int InterfaceRxThrottleResult = 218;
109 public static final int InterfaceTxThrottleResult = 219;
Robert Greenwalte3253922010-02-18 09:23:25 -0800110
111 public static final int InterfaceChange = 600;
JP Abgrall12b933d2011-07-14 18:09:22 -0700112 public static final int BandwidthControl = 601;
San Mehat873f2142010-01-14 10:25:07 -0800113 }
114
115 /**
116 * Binder context for this service
117 */
118 private Context mContext;
119
120 /**
121 * connector object for communicating with netd
122 */
123 private NativeDaemonConnector mConnector;
124
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700125 private Thread mThread;
126 private final CountDownLatch mConnectedSignal = new CountDownLatch(1);
127
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -0700128 // TODO: replace with RemoteCallbackList
San Mehat4d02d002010-01-22 16:07:46 -0800129 private ArrayList<INetworkManagementEventObserver> mObservers;
130
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -0700131 private Object mQuotaLock = new Object();
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -0700132 /** Set of interfaces with active quotas. */
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -0700133 private HashSet<String> mActiveQuotaIfaces = Sets.newHashSet();
134 /** Set of interfaces with active alerts. */
135 private HashSet<String> mActiveAlertIfaces = Sets.newHashSet();
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -0700136 /** Set of UIDs with active reject rules. */
137 private SparseBooleanArray mUidRejectOnQuota = new SparseBooleanArray();
138
Jeff Sharkey350083e2011-06-29 10:45:16 -0700139 private boolean mBandwidthControlEnabled;
140
San Mehat873f2142010-01-14 10:25:07 -0800141 /**
142 * Constructs a new NetworkManagementService instance
143 *
144 * @param context Binder context for this service
145 */
Jeff Sharkey4414cea2011-06-24 17:05:24 -0700146 private NetworkManagementService(Context context, File procRoot) {
San Mehat873f2142010-01-14 10:25:07 -0800147 mContext = context;
San Mehat4d02d002010-01-22 16:07:46 -0800148 mObservers = new ArrayList<INetworkManagementEventObserver>();
149
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700150 mStatsUid = new File(procRoot, "uid_stat");
151 mStatsIface = new File(procRoot, "net/dev");
152 mStatsXtUid = new File(procRoot, "net/xt_qtaguid/stats");
153 mStatsXtIface = new File(procRoot, "net/xt_qtaguid/iface_stat");
Jeff Sharkey4414cea2011-06-24 17:05:24 -0700154
Marco Nelissen62dbb222010-02-18 10:56:30 -0800155 if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
156 return;
157 }
158
San Mehat873f2142010-01-14 10:25:07 -0800159 mConnector = new NativeDaemonConnector(
Kenny Root305bcbf2010-09-03 07:56:38 -0700160 new NetdCallbackReceiver(), "netd", 10, NETD_TAG);
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700161 mThread = new Thread(mConnector, NETD_TAG);
162 }
163
164 public static NetworkManagementService create(Context context) throws InterruptedException {
Jeff Sharkey4414cea2011-06-24 17:05:24 -0700165 NetworkManagementService service = new NetworkManagementService(
166 context, new File("/proc/"));
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700167 if (DBG) Slog.d(TAG, "Creating NetworkManagementService");
168 service.mThread.start();
169 if (DBG) Slog.d(TAG, "Awaiting socket connection");
170 service.mConnectedSignal.await();
171 if (DBG) Slog.d(TAG, "Connected");
172 return service;
San Mehat873f2142010-01-14 10:25:07 -0800173 }
174
Jeff Sharkey4414cea2011-06-24 17:05:24 -0700175 // @VisibleForTesting
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700176 public static NetworkManagementService createForTest(
177 Context context, File procRoot, boolean bandwidthControlEnabled) {
Jeff Sharkey4414cea2011-06-24 17:05:24 -0700178 // TODO: eventually connect with mock netd
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700179 final NetworkManagementService service = new NetworkManagementService(context, procRoot);
180 service.mBandwidthControlEnabled = bandwidthControlEnabled;
181 return service;
Jeff Sharkey4414cea2011-06-24 17:05:24 -0700182 }
183
Jeff Sharkey350083e2011-06-29 10:45:16 -0700184 public void systemReady() {
185
186 // only enable bandwidth control when support exists, and requested by
187 // system setting.
188 // TODO: eventually migrate to be always enabled
189 final boolean hasKernelSupport = new File("/proc/net/xt_qtaguid/ctrl").exists();
190 final boolean shouldEnable =
191 Settings.Secure.getInt(mContext.getContentResolver(), NETSTATS_ENABLED, 0) != 0;
192
193 mBandwidthControlEnabled = false;
194 if (hasKernelSupport && shouldEnable) {
195 Slog.d(TAG, "enabling bandwidth control");
196 try {
197 mConnector.doCommand("bandwidth enable");
198 mBandwidthControlEnabled = true;
199 } catch (NativeDaemonConnectorException e) {
200 Slog.e(TAG, "problem enabling bandwidth controls", e);
201 }
202 } else {
203 Slog.d(TAG, "not enabling bandwidth control");
204 }
Jeff Sharkey62a2c8f2011-07-13 15:24:02 -0700205
206 SystemProperties.set(NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED,
207 mBandwidthControlEnabled ? "1" : "0");
Jeff Sharkey350083e2011-06-29 10:45:16 -0700208 }
209
San Mehat4d02d002010-01-22 16:07:46 -0800210 public void registerObserver(INetworkManagementEventObserver obs) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800211 Slog.d(TAG, "Registering observer");
San Mehat4d02d002010-01-22 16:07:46 -0800212 mObservers.add(obs);
213 }
214
215 public void unregisterObserver(INetworkManagementEventObserver obs) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800216 Slog.d(TAG, "Unregistering observer");
San Mehat4d02d002010-01-22 16:07:46 -0800217 mObservers.remove(mObservers.indexOf(obs));
218 }
219
220 /**
Mike J. Chen6143f5f2011-06-23 15:17:51 -0700221 * Notify our observers of an interface status change
San Mehat4d02d002010-01-22 16:07:46 -0800222 */
Mike J. Chen6143f5f2011-06-23 15:17:51 -0700223 private void notifyInterfaceStatusChanged(String iface, boolean up) {
San Mehat4d02d002010-01-22 16:07:46 -0800224 for (INetworkManagementEventObserver obs : mObservers) {
225 try {
Mike J. Chen6143f5f2011-06-23 15:17:51 -0700226 obs.interfaceStatusChanged(iface, up);
227 } catch (Exception ex) {
228 Slog.w(TAG, "Observer notifier failed", ex);
229 }
230 }
231 }
232
233 /**
Mike J. Chenf59c7d02011-06-23 15:33:15 -0700234 * Notify our observers of an interface link state change
Mike J. Chen6143f5f2011-06-23 15:17:51 -0700235 * (typically, an Ethernet cable has been plugged-in or unplugged).
236 */
237 private void notifyInterfaceLinkStateChanged(String iface, boolean up) {
238 for (INetworkManagementEventObserver obs : mObservers) {
239 try {
240 obs.interfaceLinkStateChanged(iface, up);
San Mehat4d02d002010-01-22 16:07:46 -0800241 } catch (Exception ex) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800242 Slog.w(TAG, "Observer notifier failed", ex);
San Mehat4d02d002010-01-22 16:07:46 -0800243 }
244 }
245 }
246
247 /**
248 * Notify our observers of an interface addition.
249 */
250 private void notifyInterfaceAdded(String iface) {
251 for (INetworkManagementEventObserver obs : mObservers) {
252 try {
253 obs.interfaceAdded(iface);
254 } catch (Exception ex) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800255 Slog.w(TAG, "Observer notifier failed", ex);
San Mehat4d02d002010-01-22 16:07:46 -0800256 }
257 }
258 }
259
260 /**
261 * Notify our observers of an interface removal.
262 */
263 private void notifyInterfaceRemoved(String iface) {
264 for (INetworkManagementEventObserver obs : mObservers) {
265 try {
266 obs.interfaceRemoved(iface);
267 } catch (Exception ex) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800268 Slog.w(TAG, "Observer notifier failed", ex);
San Mehat4d02d002010-01-22 16:07:46 -0800269 }
270 }
271 }
272
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700273 /**
JP Abgrall12b933d2011-07-14 18:09:22 -0700274 * Notify our observers of a limit reached.
275 */
276 private void notifyLimitReached(String limitName, String iface) {
277 for (INetworkManagementEventObserver obs : mObservers) {
278 try {
279 obs.limitReached(limitName, iface);
280 Slog.d(TAG, "Observer notified limit reached for " + limitName + " " + iface);
281 } catch (Exception ex) {
282 Slog.w(TAG, "Observer notifier failed", ex);
283 }
284 }
285 }
286
287 /**
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700288 * Let us know the daemon is connected
289 */
290 protected void onConnected() {
291 if (DBG) Slog.d(TAG, "onConnected");
292 mConnectedSignal.countDown();
293 }
294
San Mehat4d02d002010-01-22 16:07:46 -0800295
San Mehat873f2142010-01-14 10:25:07 -0800296 //
297 // Netd Callback handling
298 //
299
300 class NetdCallbackReceiver implements INativeDaemonConnectorCallbacks {
301 public void onDaemonConnected() {
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700302 NetworkManagementService.this.onConnected();
San Mehat873f2142010-01-14 10:25:07 -0800303 new Thread() {
304 public void run() {
San Mehat873f2142010-01-14 10:25:07 -0800305 }
306 }.start();
307 }
308 public boolean onEvent(int code, String raw, String[] cooked) {
JP Abgrall12b933d2011-07-14 18:09:22 -0700309 switch (code) {
310 case NetdResponseCode.InterfaceChange:
311 /*
312 * a network interface change occured
313 * Format: "NNN Iface added <name>"
314 * "NNN Iface removed <name>"
315 * "NNN Iface changed <name> <up/down>"
316 * "NNN Iface linkstatus <name> <up/down>"
317 */
318 if (cooked.length < 4 || !cooked[1].equals("Iface")) {
319 throw new IllegalStateException(
320 String.format("Invalid event from daemon (%s)", raw));
321 }
322 if (cooked[2].equals("added")) {
323 notifyInterfaceAdded(cooked[3]);
324 return true;
325 } else if (cooked[2].equals("removed")) {
326 notifyInterfaceRemoved(cooked[3]);
327 return true;
328 } else if (cooked[2].equals("changed") && cooked.length == 5) {
329 notifyInterfaceStatusChanged(cooked[3], cooked[4].equals("up"));
330 return true;
331 } else if (cooked[2].equals("linkstate") && cooked.length == 5) {
332 notifyInterfaceLinkStateChanged(cooked[3], cooked[4].equals("up"));
333 return true;
334 }
Robert Greenwalte3253922010-02-18 09:23:25 -0800335 throw new IllegalStateException(
336 String.format("Invalid event from daemon (%s)", raw));
JP Abgrall12b933d2011-07-14 18:09:22 -0700337 // break;
338 case NetdResponseCode.BandwidthControl:
339 /*
340 * Bandwidth control needs some attention
341 * Format: "NNN limit alert <alertName> <ifaceName>"
342 */
343 if (cooked.length < 5 || !cooked[1].equals("limit")) {
344 throw new IllegalStateException(
345 String.format("Invalid event from daemon (%s)", raw));
346 }
347 if (cooked[2].equals("alert")) {
348 notifyLimitReached(cooked[3], cooked[4]);
349 return true;
350 }
351 throw new IllegalStateException(
352 String.format("Invalid event from daemon (%s)", raw));
353 // break;
354 default: break;
Robert Greenwalte3253922010-02-18 09:23:25 -0800355 }
356 return false;
San Mehat873f2142010-01-14 10:25:07 -0800357 }
358 }
359
San Mehated4fc8a2010-01-22 12:28:36 -0800360
San Mehat873f2142010-01-14 10:25:07 -0800361 //
362 // INetworkManagementService members
363 //
364
365 public String[] listInterfaces() throws IllegalStateException {
366 mContext.enforceCallingOrSelfPermission(
367 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
368
Kenny Roota80ce062010-06-01 13:23:53 -0700369 try {
370 return mConnector.doListCommand("interface list", NetdResponseCode.InterfaceListResult);
371 } catch (NativeDaemonConnectorException e) {
372 throw new IllegalStateException(
373 "Cannot communicate with native daemon to list interfaces");
374 }
San Mehated4fc8a2010-01-22 12:28:36 -0800375 }
376
377 public InterfaceConfiguration getInterfaceConfig(String iface) throws IllegalStateException {
Kenny Roota80ce062010-06-01 13:23:53 -0700378 String rsp;
379 try {
380 rsp = mConnector.doCommand("interface getcfg " + iface).get(0);
381 } catch (NativeDaemonConnectorException e) {
382 throw new IllegalStateException(
383 "Cannot communicate with native daemon to get interface config");
384 }
Joe Onorato8a9b2202010-02-26 18:56:32 -0800385 Slog.d(TAG, String.format("rsp <%s>", rsp));
San Mehated4fc8a2010-01-22 12:28:36 -0800386
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800387 // Rsp: 213 xx:xx:xx:xx:xx:xx yyy.yyy.yyy.yyy zzz [flag1 flag2 flag3]
San Mehated4fc8a2010-01-22 12:28:36 -0800388 StringTokenizer st = new StringTokenizer(rsp);
389
Kenny Roota80ce062010-06-01 13:23:53 -0700390 InterfaceConfiguration cfg;
San Mehated4fc8a2010-01-22 12:28:36 -0800391 try {
Kenny Roota80ce062010-06-01 13:23:53 -0700392 try {
393 int code = Integer.parseInt(st.nextToken(" "));
394 if (code != NetdResponseCode.InterfaceGetCfgResult) {
395 throw new IllegalStateException(
396 String.format("Expected code %d, but got %d",
397 NetdResponseCode.InterfaceGetCfgResult, code));
398 }
399 } catch (NumberFormatException nfe) {
San Mehated4fc8a2010-01-22 12:28:36 -0800400 throw new IllegalStateException(
Kenny Roota80ce062010-06-01 13:23:53 -0700401 String.format("Invalid response from daemon (%s)", rsp));
San Mehated4fc8a2010-01-22 12:28:36 -0800402 }
Kenny Roota80ce062010-06-01 13:23:53 -0700403
404 cfg = new InterfaceConfiguration();
405 cfg.hwAddr = st.nextToken(" ");
Robert Greenwalted126402011-01-28 15:34:55 -0800406 InetAddress addr = null;
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800407 int prefixLength = 0;
Kenny Roota80ce062010-06-01 13:23:53 -0700408 try {
Robert Greenwalte5903732011-02-22 16:00:42 -0800409 addr = NetworkUtils.numericToInetAddress(st.nextToken(" "));
410 } catch (IllegalArgumentException iae) {
411 Slog.e(TAG, "Failed to parse ipaddr", iae);
Kenny Roota80ce062010-06-01 13:23:53 -0700412 }
413
414 try {
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800415 prefixLength = Integer.parseInt(st.nextToken(" "));
416 } catch (NumberFormatException nfe) {
417 Slog.e(TAG, "Failed to parse prefixLength", nfe);
Kenny Roota80ce062010-06-01 13:23:53 -0700418 }
Robert Greenwalt04808c22010-12-13 17:01:41 -0800419
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800420 cfg.addr = new LinkAddress(addr, prefixLength);
Kenny Roota80ce062010-06-01 13:23:53 -0700421 cfg.interfaceFlags = st.nextToken("]").trim() +"]";
422 } catch (NoSuchElementException nsee) {
San Mehated4fc8a2010-01-22 12:28:36 -0800423 throw new IllegalStateException(
424 String.format("Invalid response from daemon (%s)", rsp));
425 }
Joe Onorato8a9b2202010-02-26 18:56:32 -0800426 Slog.d(TAG, String.format("flags <%s>", cfg.interfaceFlags));
San Mehated4fc8a2010-01-22 12:28:36 -0800427 return cfg;
428 }
429
430 public void setInterfaceConfig(
431 String iface, InterfaceConfiguration cfg) throws IllegalStateException {
Robert Greenwalted126402011-01-28 15:34:55 -0800432 LinkAddress linkAddr = cfg.addr;
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800433 if (linkAddr == null || linkAddr.getAddress() == null) {
434 throw new IllegalStateException("Null LinkAddress given");
Robert Greenwalted126402011-01-28 15:34:55 -0800435 }
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800436 String cmd = String.format("interface setcfg %s %s %d %s", iface,
437 linkAddr.getAddress().getHostAddress(),
438 linkAddr.getNetworkPrefixLength(),
439 cfg.interfaceFlags);
Kenny Roota80ce062010-06-01 13:23:53 -0700440 try {
441 mConnector.doCommand(cmd);
442 } catch (NativeDaemonConnectorException e) {
443 throw new IllegalStateException(
Robert Greenwalt81d5ad52010-12-16 11:27:38 -0800444 "Unable to communicate with native daemon to interface setcfg - " + e);
Kenny Roota80ce062010-06-01 13:23:53 -0700445 }
San Mehat873f2142010-01-14 10:25:07 -0800446 }
447
Irfan Sherifff5600612011-06-16 10:26:28 -0700448 /* TODO: This is right now a IPv4 only function. Works for wifi which loses its
449 IPv6 addresses on interface down, but we need to do full clean up here */
450 public void clearInterfaceAddresses(String iface) throws IllegalStateException {
451 String cmd = String.format("interface clearaddrs %s", iface);
452 try {
453 mConnector.doCommand(cmd);
454 } catch (NativeDaemonConnectorException e) {
455 throw new IllegalStateException(
456 "Unable to communicate with native daemon to interface clearallips - " + e);
457 }
458 }
459
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -0700460 public void addRoute(String interfaceName, RouteInfo route) {
461 modifyRoute(interfaceName, ADD, route);
462 }
463
464 public void removeRoute(String interfaceName, RouteInfo route) {
465 modifyRoute(interfaceName, REMOVE, route);
466 }
467
468 private void modifyRoute(String interfaceName, int action, RouteInfo route) {
469 ArrayList<String> rsp;
470
471 StringBuilder cmd;
472
473 switch (action) {
474 case ADD:
475 {
476 cmd = new StringBuilder("interface route add " + interfaceName);
477 break;
478 }
479 case REMOVE:
480 {
481 cmd = new StringBuilder("interface route remove " + interfaceName);
482 break;
483 }
484 default:
485 throw new IllegalStateException("Unknown action type " + action);
486 }
487
488 // create triplet: dest-ip-addr prefixlength gateway-ip-addr
489 LinkAddress la = route.getDestination();
490 cmd.append(' ');
491 cmd.append(la.getAddress().getHostAddress());
492 cmd.append(' ');
493 cmd.append(la.getNetworkPrefixLength());
494 cmd.append(' ');
495 if (route.getGateway() == null) {
496 if (la.getAddress() instanceof Inet4Address) {
497 cmd.append("0.0.0.0");
498 } else {
499 cmd.append ("::0");
500 }
501 } else {
502 cmd.append(route.getGateway().getHostAddress());
503 }
504 try {
505 rsp = mConnector.doCommand(cmd.toString());
506 } catch (NativeDaemonConnectorException e) {
507 throw new IllegalStateException(
508 "Unable to communicate with native dameon to add routes - "
509 + e);
510 }
511
512 for (String line : rsp) {
513 Log.v(TAG, "add route response is " + line);
514 }
515 }
516
517 private ArrayList<String> readRouteList(String filename) {
518 FileInputStream fstream = null;
519 ArrayList<String> list = new ArrayList<String>();
520
521 try {
522 fstream = new FileInputStream(filename);
523 DataInputStream in = new DataInputStream(fstream);
524 BufferedReader br = new BufferedReader(new InputStreamReader(in));
525 String s;
526
527 // throw away the title line
528
529 while (((s = br.readLine()) != null) && (s.length() != 0)) {
530 list.add(s);
531 }
532 } catch (IOException ex) {
533 // return current list, possibly empty
534 } finally {
535 if (fstream != null) {
536 try {
537 fstream.close();
538 } catch (IOException ex) {}
539 }
540 }
541
542 return list;
543 }
544
545 public RouteInfo[] getRoutes(String interfaceName) {
546 ArrayList<RouteInfo> routes = new ArrayList<RouteInfo>();
547
548 // v4 routes listed as:
549 // iface dest-addr gateway-addr flags refcnt use metric netmask mtu window IRTT
550 for (String s : readRouteList("/proc/net/route")) {
551 String[] fields = s.split("\t");
552
553 if (fields.length > 7) {
554 String iface = fields[0];
555
556 if (interfaceName.equals(iface)) {
557 String dest = fields[1];
558 String gate = fields[2];
559 String flags = fields[3]; // future use?
560 String mask = fields[7];
561 try {
562 // address stored as a hex string, ex: 0014A8C0
563 InetAddress destAddr =
564 NetworkUtils.intToInetAddress((int)Long.parseLong(dest, 16));
565 int prefixLength =
566 NetworkUtils.netmaskIntToPrefixLength(
567 (int)Long.parseLong(mask, 16));
568 LinkAddress linkAddress = new LinkAddress(destAddr, prefixLength);
569
570 // address stored as a hex string, ex 0014A8C0
571 InetAddress gatewayAddr =
572 NetworkUtils.intToInetAddress((int)Long.parseLong(gate, 16));
573
574 RouteInfo route = new RouteInfo(linkAddress, gatewayAddr);
575 routes.add(route);
576 } catch (Exception e) {
577 Log.e(TAG, "Error parsing route " + s + " : " + e);
578 continue;
579 }
580 }
581 }
582 }
583
584 // v6 routes listed as:
585 // dest-addr prefixlength ?? ?? gateway-addr ?? ?? ?? ?? iface
586 for (String s : readRouteList("/proc/net/ipv6_route")) {
587 String[]fields = s.split("\\s+");
588 if (fields.length > 9) {
589 String iface = fields[9].trim();
590 if (interfaceName.equals(iface)) {
591 String dest = fields[0];
592 String prefix = fields[1];
593 String gate = fields[4];
594
595 try {
596 // prefix length stored as a hex string, ex 40
597 int prefixLength = Integer.parseInt(prefix, 16);
598
599 // address stored as a 32 char hex string
600 // ex fe800000000000000000000000000000
601 InetAddress destAddr = NetworkUtils.hexToInet6Address(dest);
602 LinkAddress linkAddress = new LinkAddress(destAddr, prefixLength);
603
604 InetAddress gateAddr = NetworkUtils.hexToInet6Address(gate);
605
606 RouteInfo route = new RouteInfo(linkAddress, gateAddr);
607 routes.add(route);
608 } catch (Exception e) {
609 Log.e(TAG, "Error parsing route " + s + " : " + e);
610 continue;
611 }
612 }
613 }
614 }
615 return (RouteInfo[]) routes.toArray(new RouteInfo[0]);
616 }
617
San Mehat873f2142010-01-14 10:25:07 -0800618 public void shutdown() {
619 if (mContext.checkCallingOrSelfPermission(
620 android.Manifest.permission.SHUTDOWN)
621 != PackageManager.PERMISSION_GRANTED) {
622 throw new SecurityException("Requires SHUTDOWN permission");
623 }
624
Joe Onorato8a9b2202010-02-26 18:56:32 -0800625 Slog.d(TAG, "Shutting down");
San Mehat873f2142010-01-14 10:25:07 -0800626 }
627
628 public boolean getIpForwardingEnabled() throws IllegalStateException{
629 mContext.enforceCallingOrSelfPermission(
630 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
631
Kenny Roota80ce062010-06-01 13:23:53 -0700632 ArrayList<String> rsp;
633 try {
634 rsp = mConnector.doCommand("ipfwd status");
635 } catch (NativeDaemonConnectorException e) {
636 throw new IllegalStateException(
637 "Unable to communicate with native daemon to ipfwd status");
638 }
San Mehat873f2142010-01-14 10:25:07 -0800639
640 for (String line : rsp) {
Kenny Roota80ce062010-06-01 13:23:53 -0700641 String[] tok = line.split(" ");
642 if (tok.length < 3) {
643 Slog.e(TAG, "Malformed response from native daemon: " + line);
644 return false;
645 }
646
San Mehat873f2142010-01-14 10:25:07 -0800647 int code = Integer.parseInt(tok[0]);
648 if (code == NetdResponseCode.IpFwdStatusResult) {
649 // 211 Forwarding <enabled/disabled>
Kenny Roota80ce062010-06-01 13:23:53 -0700650 return "enabled".equals(tok[2]);
San Mehat873f2142010-01-14 10:25:07 -0800651 } else {
652 throw new IllegalStateException(String.format("Unexpected response code %d", code));
653 }
654 }
655 throw new IllegalStateException("Got an empty response");
656 }
657
658 public void setIpForwardingEnabled(boolean enable) throws IllegalStateException {
659 mContext.enforceCallingOrSelfPermission(
660 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
661 mConnector.doCommand(String.format("ipfwd %sable", (enable ? "en" : "dis")));
662 }
663
Robert Greenwaltbfb7bfa2010-03-24 16:03:21 -0700664 public void startTethering(String[] dhcpRange)
San Mehat873f2142010-01-14 10:25:07 -0800665 throws IllegalStateException {
666 mContext.enforceCallingOrSelfPermission(
667 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Robert Greenwaltbfb7bfa2010-03-24 16:03:21 -0700668 // cmd is "tether start first_start first_stop second_start second_stop ..."
669 // an odd number of addrs will fail
670 String cmd = "tether start";
671 for (String d : dhcpRange) {
672 cmd += " " + d;
673 }
Kenny Roota80ce062010-06-01 13:23:53 -0700674
675 try {
676 mConnector.doCommand(cmd);
677 } catch (NativeDaemonConnectorException e) {
678 throw new IllegalStateException("Unable to communicate to native daemon");
679 }
San Mehat873f2142010-01-14 10:25:07 -0800680 }
681
682 public void stopTethering() throws IllegalStateException {
683 mContext.enforceCallingOrSelfPermission(
684 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700685 try {
686 mConnector.doCommand("tether stop");
687 } catch (NativeDaemonConnectorException e) {
688 throw new IllegalStateException("Unable to communicate to native daemon to stop tether");
689 }
San Mehat873f2142010-01-14 10:25:07 -0800690 }
691
692 public boolean isTetheringStarted() throws IllegalStateException {
693 mContext.enforceCallingOrSelfPermission(
694 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
695
Kenny Roota80ce062010-06-01 13:23:53 -0700696 ArrayList<String> rsp;
697 try {
698 rsp = mConnector.doCommand("tether status");
699 } catch (NativeDaemonConnectorException e) {
700 throw new IllegalStateException(
701 "Unable to communicate to native daemon to get tether status");
702 }
San Mehat873f2142010-01-14 10:25:07 -0800703
704 for (String line : rsp) {
Kenny Roota80ce062010-06-01 13:23:53 -0700705 String[] tok = line.split(" ");
706 if (tok.length < 3) {
707 throw new IllegalStateException("Malformed response for tether status: " + line);
708 }
San Mehat873f2142010-01-14 10:25:07 -0800709 int code = Integer.parseInt(tok[0]);
710 if (code == NetdResponseCode.TetherStatusResult) {
711 // XXX: Tethering services <started/stopped> <TBD>...
Kenny Roota80ce062010-06-01 13:23:53 -0700712 return "started".equals(tok[2]);
San Mehat873f2142010-01-14 10:25:07 -0800713 } else {
714 throw new IllegalStateException(String.format("Unexpected response code %d", code));
715 }
716 }
717 throw new IllegalStateException("Got an empty response");
718 }
719
720 public void tetherInterface(String iface) throws IllegalStateException {
721 mContext.enforceCallingOrSelfPermission(
722 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700723 try {
724 mConnector.doCommand("tether interface add " + iface);
725 } catch (NativeDaemonConnectorException e) {
726 throw new IllegalStateException(
727 "Unable to communicate to native daemon for adding tether interface");
728 }
San Mehat873f2142010-01-14 10:25:07 -0800729 }
730
731 public void untetherInterface(String iface) {
732 mContext.enforceCallingOrSelfPermission(
733 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700734 try {
735 mConnector.doCommand("tether interface remove " + iface);
736 } catch (NativeDaemonConnectorException e) {
737 throw new IllegalStateException(
738 "Unable to communicate to native daemon for removing tether interface");
739 }
San Mehat873f2142010-01-14 10:25:07 -0800740 }
741
742 public String[] listTetheredInterfaces() throws IllegalStateException {
743 mContext.enforceCallingOrSelfPermission(
744 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700745 try {
746 return mConnector.doListCommand(
747 "tether interface list", NetdResponseCode.TetherInterfaceListResult);
748 } catch (NativeDaemonConnectorException e) {
749 throw new IllegalStateException(
750 "Unable to communicate to native daemon for listing tether interfaces");
751 }
San Mehat873f2142010-01-14 10:25:07 -0800752 }
753
754 public void setDnsForwarders(String[] dns) throws IllegalStateException {
755 mContext.enforceCallingOrSelfPermission(
756 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
757 try {
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800758 String cmd = "tether dns set";
San Mehat873f2142010-01-14 10:25:07 -0800759 for (String s : dns) {
Robert Greenwalte5903732011-02-22 16:00:42 -0800760 cmd += " " + NetworkUtils.numericToInetAddress(s).getHostAddress();
San Mehat873f2142010-01-14 10:25:07 -0800761 }
Kenny Roota80ce062010-06-01 13:23:53 -0700762 try {
763 mConnector.doCommand(cmd);
764 } catch (NativeDaemonConnectorException e) {
765 throw new IllegalStateException(
766 "Unable to communicate to native daemon for setting tether dns");
767 }
Robert Greenwalte5903732011-02-22 16:00:42 -0800768 } catch (IllegalArgumentException e) {
San Mehat873f2142010-01-14 10:25:07 -0800769 throw new IllegalStateException("Error resolving dns name", e);
770 }
771 }
772
773 public String[] getDnsForwarders() throws IllegalStateException {
774 mContext.enforceCallingOrSelfPermission(
775 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700776 try {
777 return mConnector.doListCommand(
778 "tether dns list", NetdResponseCode.TetherDnsFwdTgtListResult);
779 } catch (NativeDaemonConnectorException e) {
780 throw new IllegalStateException(
781 "Unable to communicate to native daemon for listing tether dns");
782 }
San Mehat873f2142010-01-14 10:25:07 -0800783 }
784
785 public void enableNat(String internalInterface, String externalInterface)
786 throws IllegalStateException {
787 mContext.enforceCallingOrSelfPermission(
788 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700789 try {
790 mConnector.doCommand(
791 String.format("nat enable %s %s", internalInterface, externalInterface));
792 } catch (NativeDaemonConnectorException e) {
793 throw new IllegalStateException(
794 "Unable to communicate to native daemon for enabling NAT interface");
795 }
San Mehat873f2142010-01-14 10:25:07 -0800796 }
797
798 public void disableNat(String internalInterface, String externalInterface)
799 throws IllegalStateException {
800 mContext.enforceCallingOrSelfPermission(
801 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700802 try {
803 mConnector.doCommand(
804 String.format("nat disable %s %s", internalInterface, externalInterface));
805 } catch (NativeDaemonConnectorException e) {
806 throw new IllegalStateException(
807 "Unable to communicate to native daemon for disabling NAT interface");
808 }
San Mehat873f2142010-01-14 10:25:07 -0800809 }
San Mehat72759df2010-01-19 13:50:37 -0800810
811 public String[] listTtys() throws IllegalStateException {
812 mContext.enforceCallingOrSelfPermission(
813 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700814 try {
815 return mConnector.doListCommand("list_ttys", NetdResponseCode.TtyListResult);
816 } catch (NativeDaemonConnectorException e) {
817 throw new IllegalStateException(
818 "Unable to communicate to native daemon for listing TTYs");
819 }
San Mehat72759df2010-01-19 13:50:37 -0800820 }
821
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800822 public void attachPppd(String tty, String localAddr, String remoteAddr, String dns1Addr,
823 String dns2Addr) throws IllegalStateException {
San Mehat72759df2010-01-19 13:50:37 -0800824 try {
825 mContext.enforceCallingOrSelfPermission(
826 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800827 mConnector.doCommand(String.format("pppd attach %s %s %s %s %s", tty,
Robert Greenwalte5903732011-02-22 16:00:42 -0800828 NetworkUtils.numericToInetAddress(localAddr).getHostAddress(),
829 NetworkUtils.numericToInetAddress(remoteAddr).getHostAddress(),
830 NetworkUtils.numericToInetAddress(dns1Addr).getHostAddress(),
831 NetworkUtils.numericToInetAddress(dns2Addr).getHostAddress()));
832 } catch (IllegalArgumentException e) {
San Mehat72759df2010-01-19 13:50:37 -0800833 throw new IllegalStateException("Error resolving addr", e);
Kenny Roota80ce062010-06-01 13:23:53 -0700834 } catch (NativeDaemonConnectorException e) {
835 throw new IllegalStateException("Error communicating to native daemon to attach pppd", e);
San Mehat72759df2010-01-19 13:50:37 -0800836 }
837 }
838
839 public void detachPppd(String tty) throws IllegalStateException {
840 mContext.enforceCallingOrSelfPermission(
841 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700842 try {
843 mConnector.doCommand(String.format("pppd detach %s", tty));
844 } catch (NativeDaemonConnectorException e) {
845 throw new IllegalStateException("Error communicating to native daemon to detach pppd", e);
846 }
San Mehat72759df2010-01-19 13:50:37 -0800847 }
Robert Greenwaltce1200d2010-02-18 11:25:54 -0800848
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700849 public void startAccessPoint(WifiConfiguration wifiConfig, String wlanIface, String softapIface)
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800850 throws IllegalStateException {
851 mContext.enforceCallingOrSelfPermission(
852 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
853 mContext.enforceCallingOrSelfPermission(
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700854 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700855 try {
Kenny Roota80ce062010-06-01 13:23:53 -0700856 mConnector.doCommand(String.format("softap fwreload " + wlanIface + " AP"));
857 mConnector.doCommand(String.format("softap start " + wlanIface));
858 if (wifiConfig == null) {
859 mConnector.doCommand(String.format("softap set " + wlanIface + " " + softapIface));
860 } else {
861 /**
862 * softap set arg1 arg2 arg3 [arg4 arg5 arg6 arg7 arg8]
863 * argv1 - wlan interface
864 * argv2 - softap interface
865 * argv3 - SSID
866 * argv4 - Security
867 * argv5 - Key
868 * argv6 - Channel
869 * argv7 - Preamble
870 * argv8 - Max SCB
871 */
Irfan Sheriffec8d23a2011-02-16 17:00:33 -0800872 String str = String.format("softap set " + wlanIface + " " + softapIface +
873 " %s %s %s", convertQuotedString(wifiConfig.SSID),
874 getSecurityType(wifiConfig),
875 convertQuotedString(wifiConfig.preSharedKey));
Kenny Roota80ce062010-06-01 13:23:53 -0700876 mConnector.doCommand(str);
877 }
878 mConnector.doCommand(String.format("softap startap"));
879 } catch (NativeDaemonConnectorException e) {
880 throw new IllegalStateException("Error communicating to native daemon to start softap", e);
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -0800881 }
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800882 }
883
Irfan Sheriffa6e559e2010-05-24 14:55:42 -0700884 private String convertQuotedString(String s) {
Irfan Sheriff7baec0f2010-05-26 17:16:47 -0700885 if (s == null) {
886 return s;
887 }
888 /* Replace \ with \\, then " with \" and add quotes at end */
889 return '"' + s.replaceAll("\\\\","\\\\\\\\").replaceAll("\"","\\\\\"") + '"';
Irfan Sheriffa6e559e2010-05-24 14:55:42 -0700890 }
891
Irfan Sheriffec8d23a2011-02-16 17:00:33 -0800892 private String getSecurityType(WifiConfiguration wifiConfig) {
893 switch (wifiConfig.getAuthType()) {
894 case KeyMgmt.WPA_PSK:
895 return "wpa-psk";
896 case KeyMgmt.WPA2_PSK:
897 return "wpa2-psk";
898 default:
899 return "open";
900 }
901 }
902
Irfan Sheriff23eb2972011-07-22 15:21:10 -0700903 public void stopAccessPoint(String wlanIface) throws IllegalStateException {
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800904 mContext.enforceCallingOrSelfPermission(
905 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
906 mContext.enforceCallingOrSelfPermission(
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700907 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700908 try {
909 mConnector.doCommand("softap stopap");
Irfan Sheriff23eb2972011-07-22 15:21:10 -0700910 mConnector.doCommand("softap stop " + wlanIface);
911 mConnector.doCommand(String.format("softap fwreload " + wlanIface + " STA"));
Kenny Roota80ce062010-06-01 13:23:53 -0700912 } catch (NativeDaemonConnectorException e) {
913 throw new IllegalStateException("Error communicating to native daemon to stop soft AP",
914 e);
915 }
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800916 }
917
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700918 public void setAccessPoint(WifiConfiguration wifiConfig, String wlanIface, String softapIface)
919 throws IllegalStateException {
920 mContext.enforceCallingOrSelfPermission(
921 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
922 mContext.enforceCallingOrSelfPermission(
923 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700924 try {
925 if (wifiConfig == null) {
926 mConnector.doCommand(String.format("softap set " + wlanIface + " " + softapIface));
927 } else {
928 String str = String.format("softap set " + wlanIface + " " + softapIface
929 + " %s %s %s", convertQuotedString(wifiConfig.SSID),
Irfan Sheriffec8d23a2011-02-16 17:00:33 -0800930 getSecurityType(wifiConfig),
Kenny Roota80ce062010-06-01 13:23:53 -0700931 convertQuotedString(wifiConfig.preSharedKey));
932 mConnector.doCommand(str);
933 }
934 } catch (NativeDaemonConnectorException e) {
935 throw new IllegalStateException("Error communicating to native daemon to set soft AP",
936 e);
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700937 }
938 }
San Mehat91cac642010-03-31 14:31:36 -0700939
940 private long getInterfaceCounter(String iface, boolean rx) {
941 mContext.enforceCallingOrSelfPermission(
942 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
943 try {
Kenny Roota80ce062010-06-01 13:23:53 -0700944 String rsp;
945 try {
946 rsp = mConnector.doCommand(
947 String.format("interface read%scounter %s", (rx ? "rx" : "tx"), iface)).get(0);
948 } catch (NativeDaemonConnectorException e1) {
949 Slog.e(TAG, "Error communicating with native daemon", e1);
950 return -1;
951 }
952
953 String[] tok = rsp.split(" ");
954 if (tok.length < 2) {
955 Slog.e(TAG, String.format("Malformed response for reading %s interface",
956 (rx ? "rx" : "tx")));
957 return -1;
958 }
959
San Mehat91cac642010-03-31 14:31:36 -0700960 int code;
961 try {
962 code = Integer.parseInt(tok[0]);
963 } catch (NumberFormatException nfe) {
964 Slog.e(TAG, String.format("Error parsing code %s", tok[0]));
965 return -1;
966 }
967 if ((rx && code != NetdResponseCode.InterfaceRxCounterResult) || (
968 !rx && code != NetdResponseCode.InterfaceTxCounterResult)) {
969 Slog.e(TAG, String.format("Unexpected response code %d", code));
970 return -1;
971 }
972 return Long.parseLong(tok[1]);
973 } catch (Exception e) {
974 Slog.e(TAG, String.format(
975 "Failed to read interface %s counters", (rx ? "rx" : "tx")), e);
976 }
977 return -1;
978 }
979
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700980 @Override
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700981 public NetworkStats getNetworkStatsSummary() {
982 mContext.enforceCallingOrSelfPermission(
983 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
984
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700985 final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6);
986 final NetworkStats.Entry entry = new NetworkStats.Entry();
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700987
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700988 final HashSet<String> activeIfaces = Sets.newHashSet();
989 final ArrayList<String> values = Lists.newArrayList();
990
991 BufferedReader reader = null;
992 try {
993 reader = new BufferedReader(new FileReader(mStatsIface));
994
995 // skip first two header lines
996 reader.readLine();
997 reader.readLine();
998
999 // parse remaining lines
1000 String line;
1001 while ((line = reader.readLine()) != null) {
1002 splitLine(line, values);
1003
1004 try {
1005 entry.iface = values.get(0);
1006 entry.uid = UID_ALL;
1007 entry.tag = TAG_NONE;
1008 entry.rxBytes = Long.parseLong(values.get(1));
1009 entry.rxPackets = Long.parseLong(values.get(2));
1010 entry.txBytes = Long.parseLong(values.get(9));
1011 entry.txPackets = Long.parseLong(values.get(10));
1012
1013 activeIfaces.add(entry.iface);
1014 stats.addValues(entry);
1015 } catch (NumberFormatException e) {
1016 Slog.w(TAG, "problem parsing stats row '" + line + "': " + e);
1017 }
1018 }
1019 } catch (IOException e) {
1020 Slog.w(TAG, "problem parsing stats: " + e);
1021 } finally {
1022 IoUtils.closeQuietly(reader);
1023 }
1024
1025 if (DBG) Slog.d(TAG, "recorded active stats from " + activeIfaces);
1026
1027 // splice in stats from any disabled ifaces
1028 if (mBandwidthControlEnabled) {
1029 final HashSet<String> xtIfaces = Sets.newHashSet(fileListWithoutNull(mStatsXtIface));
1030 xtIfaces.removeAll(activeIfaces);
1031
1032 for (String iface : xtIfaces) {
1033 final File ifacePath = new File(mStatsXtIface, iface);
1034
1035 entry.iface = iface;
1036 entry.uid = UID_ALL;
1037 entry.tag = TAG_NONE;
1038 entry.rxBytes = readSingleLongFromFile(new File(ifacePath, "rx_bytes"));
1039 entry.rxPackets = readSingleLongFromFile(new File(ifacePath, "rx_packets"));
1040 entry.txBytes = readSingleLongFromFile(new File(ifacePath, "tx_bytes"));
1041 entry.txPackets = readSingleLongFromFile(new File(ifacePath, "tx_packets"));
1042
1043 stats.addValues(entry);
1044 }
1045
1046 if (DBG) Slog.d(TAG, "recorded stale stats from " + xtIfaces);
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001047 }
1048
Jeff Sharkey4a971222011-06-11 22:16:55 -07001049 return stats;
San Mehat91cac642010-03-31 14:31:36 -07001050 }
1051
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001052 @Override
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001053 public NetworkStats getNetworkStatsDetail() {
1054 mContext.enforceCallingOrSelfPermission(
1055 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
1056
Jeff Sharkey350083e2011-06-29 10:45:16 -07001057 if (mBandwidthControlEnabled) {
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001058 return getNetworkStatsDetailNetfilter(UID_ALL);
1059 } else {
1060 return getNetworkStatsDetailUidstat(UID_ALL);
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001061 }
San Mehat91cac642010-03-31 14:31:36 -07001062 }
1063
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001064 @Override
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001065 public void setInterfaceQuota(String iface, long quotaBytes) {
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001066 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1067
Jeff Sharkey350083e2011-06-29 10:45:16 -07001068 // silently discard when control disabled
1069 // TODO: eventually migrate to be always enabled
1070 if (!mBandwidthControlEnabled) return;
1071
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001072 synchronized (mQuotaLock) {
1073 if (mActiveQuotaIfaces.contains(iface)) {
1074 throw new IllegalStateException("iface " + iface + " already has quota");
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001075 }
1076
1077 final StringBuilder command = new StringBuilder();
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001078 command.append("bandwidth setiquota ").append(iface).append(" ").append(quotaBytes);
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001079
1080 try {
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001081 // TODO: support quota shared across interfaces
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001082 mConnector.doCommand(command.toString());
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001083 mActiveQuotaIfaces.add(iface);
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001084 } catch (NativeDaemonConnectorException e) {
1085 throw new IllegalStateException("Error communicating to native daemon", e);
1086 }
Ashish Sharma50fd36d2011-06-15 19:34:53 -07001087 }
1088 }
1089
1090 @Override
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001091 public void removeInterfaceQuota(String iface) {
1092 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1093
Jeff Sharkey350083e2011-06-29 10:45:16 -07001094 // silently discard when control disabled
1095 // TODO: eventually migrate to be always enabled
1096 if (!mBandwidthControlEnabled) return;
1097
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001098 synchronized (mQuotaLock) {
1099 if (!mActiveQuotaIfaces.contains(iface)) {
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001100 // TODO: eventually consider throwing
1101 return;
1102 }
1103
1104 final StringBuilder command = new StringBuilder();
1105 command.append("bandwidth removeiquota ").append(iface);
1106
1107 try {
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001108 // TODO: support quota shared across interfaces
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001109 mConnector.doCommand(command.toString());
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001110 mActiveQuotaIfaces.remove(iface);
1111 mActiveAlertIfaces.remove(iface);
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001112 } catch (NativeDaemonConnectorException e) {
1113 throw new IllegalStateException("Error communicating to native daemon", e);
1114 }
1115 }
1116 }
1117
1118 @Override
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001119 public void setInterfaceAlert(String iface, long alertBytes) {
1120 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1121
1122 // silently discard when control disabled
1123 // TODO: eventually migrate to be always enabled
1124 if (!mBandwidthControlEnabled) return;
1125
1126 // quick sanity check
1127 if (!mActiveQuotaIfaces.contains(iface)) {
1128 throw new IllegalStateException("setting alert requires existing quota on iface");
1129 }
1130
1131 synchronized (mQuotaLock) {
1132 if (mActiveAlertIfaces.contains(iface)) {
1133 throw new IllegalStateException("iface " + iface + " already has alert");
1134 }
1135
1136 final StringBuilder command = new StringBuilder();
1137 command.append("bandwidth setinterfacealert ").append(iface).append(" ").append(
1138 alertBytes);
1139
1140 try {
1141 // TODO: support alert shared across interfaces
1142 mConnector.doCommand(command.toString());
1143 mActiveAlertIfaces.add(iface);
1144 } catch (NativeDaemonConnectorException e) {
1145 throw new IllegalStateException("Error communicating to native daemon", e);
1146 }
1147 }
1148 }
1149
1150 @Override
1151 public void removeInterfaceAlert(String iface) {
1152 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1153
1154 // silently discard when control disabled
1155 // TODO: eventually migrate to be always enabled
1156 if (!mBandwidthControlEnabled) return;
1157
1158 synchronized (mQuotaLock) {
1159 if (!mActiveAlertIfaces.contains(iface)) {
1160 // TODO: eventually consider throwing
1161 return;
1162 }
1163
1164 final StringBuilder command = new StringBuilder();
1165 command.append("bandwidth removeinterfacealert ").append(iface);
1166
1167 try {
1168 // TODO: support alert shared across interfaces
1169 mConnector.doCommand(command.toString());
1170 mActiveAlertIfaces.remove(iface);
1171 } catch (NativeDaemonConnectorException e) {
1172 throw new IllegalStateException("Error communicating to native daemon", e);
1173 }
1174 }
1175 }
1176
1177 @Override
1178 public void setGlobalAlert(long alertBytes) {
1179 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1180
1181 // silently discard when control disabled
1182 // TODO: eventually migrate to be always enabled
1183 if (!mBandwidthControlEnabled) return;
1184
1185 final StringBuilder command = new StringBuilder();
1186 command.append("bandwidth setglobalalert ").append(alertBytes);
1187
1188 try {
1189 mConnector.doCommand(command.toString());
1190 } catch (NativeDaemonConnectorException e) {
1191 throw new IllegalStateException("Error communicating to native daemon", e);
1192 }
1193 }
1194
1195 @Override
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001196 public void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces) {
1197 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1198
Jeff Sharkey350083e2011-06-29 10:45:16 -07001199 // silently discard when control disabled
1200 // TODO: eventually migrate to be always enabled
1201 if (!mBandwidthControlEnabled) return;
1202
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001203 synchronized (mUidRejectOnQuota) {
1204 final boolean oldRejectOnQuota = mUidRejectOnQuota.get(uid, false);
1205 if (oldRejectOnQuota == rejectOnQuotaInterfaces) {
1206 // TODO: eventually consider throwing
1207 return;
1208 }
1209
1210 final StringBuilder command = new StringBuilder();
1211 command.append("bandwidth");
1212 if (rejectOnQuotaInterfaces) {
1213 command.append(" addnaughtyapps");
1214 } else {
1215 command.append(" removenaughtyapps");
1216 }
1217 command.append(" ").append(uid);
1218
1219 try {
1220 mConnector.doCommand(command.toString());
1221 if (rejectOnQuotaInterfaces) {
1222 mUidRejectOnQuota.put(uid, true);
1223 } else {
1224 mUidRejectOnQuota.delete(uid);
1225 }
1226 } catch (NativeDaemonConnectorException e) {
1227 throw new IllegalStateException("Error communicating to native daemon", e);
1228 }
Ashish Sharma50fd36d2011-06-15 19:34:53 -07001229 }
1230 }
1231
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001232 public NetworkStats getNetworkStatsUidDetail(int uid) {
1233 if (Binder.getCallingUid() != uid) {
1234 mContext.enforceCallingOrSelfPermission(
1235 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
1236 }
1237
Jeff Sharkey350083e2011-06-29 10:45:16 -07001238 if (mBandwidthControlEnabled) {
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001239 return getNetworkStatsDetailNetfilter(uid);
1240 } else {
1241 return getNetworkStatsDetailUidstat(uid);
1242 }
1243 }
1244
1245 /**
1246 * Build {@link NetworkStats} with detailed UID statistics.
1247 */
1248 private NetworkStats getNetworkStatsDetailNetfilter(int limitUid) {
1249 final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 24);
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001250 final NetworkStats.Entry entry = new NetworkStats.Entry();
1251
Jeff Sharkey4414cea2011-06-24 17:05:24 -07001252 final ArrayList<String> keys = Lists.newArrayList();
1253 final ArrayList<String> values = Lists.newArrayList();
1254 final HashMap<String, String> parsed = Maps.newHashMap();
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001255
1256 BufferedReader reader = null;
1257 try {
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001258 reader = new BufferedReader(new FileReader(mStatsXtUid));
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001259
Jeff Sharkey4414cea2011-06-24 17:05:24 -07001260 // parse first line as header
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001261 String line = reader.readLine();
Jeff Sharkey4414cea2011-06-24 17:05:24 -07001262 splitLine(line, keys);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001263
Jeff Sharkey4414cea2011-06-24 17:05:24 -07001264 // parse remaining lines
1265 while ((line = reader.readLine()) != null) {
1266 splitLine(line, values);
1267 parseLine(keys, values, parsed);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001268
1269 try {
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001270 // TODO: add rxPackets/txPackets once kernel exports
1271 entry.iface = parsed.get(KEY_IFACE);
1272 entry.tag = NetworkManagementSocketTagger.kernelToTag(
Jesse Wilson8568db52011-06-28 19:06:31 -07001273 parsed.get(KEY_TAG_HEX));
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001274 entry.uid = Integer.parseInt(parsed.get(KEY_UID));
1275 entry.rxBytes = Long.parseLong(parsed.get(KEY_RX));
1276 entry.txBytes = Long.parseLong(parsed.get(KEY_TX));
Jeff Sharkeyd03fd3f2011-06-19 20:55:09 -07001277
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001278 if (limitUid == UID_ALL || limitUid == entry.uid) {
1279 stats.addValues(entry);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001280 }
1281 } catch (NumberFormatException e) {
Jeff Sharkey4414cea2011-06-24 17:05:24 -07001282 Slog.w(TAG, "problem parsing stats row '" + line + "': " + e);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001283 }
1284 }
1285 } catch (IOException e) {
1286 Slog.w(TAG, "problem parsing stats: " + e);
1287 } finally {
1288 IoUtils.closeQuietly(reader);
1289 }
1290
Jeff Sharkey4a971222011-06-11 22:16:55 -07001291 return stats;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001292 }
1293
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001294 /**
1295 * Build {@link NetworkStats} with detailed UID statistics.
1296 *
1297 * @deprecated since this uses older "uid_stat" data, and doesn't provide
1298 * tag-level granularity or additional variables.
1299 */
1300 @Deprecated
1301 private NetworkStats getNetworkStatsDetailUidstat(int limitUid) {
1302 final String[] knownUids;
1303 if (limitUid == UID_ALL) {
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001304 knownUids = fileListWithoutNull(mStatsUid);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001305 } else {
1306 knownUids = new String[] { String.valueOf(limitUid) };
1307 }
1308
1309 final NetworkStats stats = new NetworkStats(
1310 SystemClock.elapsedRealtime(), knownUids.length);
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001311 final NetworkStats.Entry entry = new NetworkStats.Entry();
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001312 for (String uid : knownUids) {
1313 final int uidInt = Integer.parseInt(uid);
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001314 final File uidPath = new File(mStatsUid, uid);
1315
1316 entry.iface = IFACE_ALL;
1317 entry.uid = uidInt;
1318 entry.tag = TAG_NONE;
1319 entry.rxBytes = readSingleLongFromFile(new File(uidPath, "tcp_rcv"));
1320 entry.rxPackets = readSingleLongFromFile(new File(uidPath, "tcp_rcv_pkt"));
1321 entry.txBytes = readSingleLongFromFile(new File(uidPath, "tcp_snd"));
1322 entry.txPackets = readSingleLongFromFile(new File(uidPath, "tcp_snd_pkt"));
1323
1324 stats.addValues(entry);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001325 }
1326
1327 return stats;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001328 }
1329
San Mehatf0db6e12010-04-07 15:22:10 -07001330 public void setInterfaceThrottle(String iface, int rxKbps, int txKbps) {
San Mehat91cac642010-03-31 14:31:36 -07001331 mContext.enforceCallingOrSelfPermission(
1332 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -07001333 try {
1334 mConnector.doCommand(String.format(
1335 "interface setthrottle %s %d %d", iface, rxKbps, txKbps));
1336 } catch (NativeDaemonConnectorException e) {
1337 Slog.e(TAG, "Error communicating with native daemon to set throttle", e);
1338 }
San Mehat91cac642010-03-31 14:31:36 -07001339 }
1340
1341 private int getInterfaceThrottle(String iface, boolean rx) {
1342 mContext.enforceCallingOrSelfPermission(
1343 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
1344 try {
Kenny Roota80ce062010-06-01 13:23:53 -07001345 String rsp;
1346 try {
1347 rsp = mConnector.doCommand(
1348 String.format("interface getthrottle %s %s", iface,
1349 (rx ? "rx" : "tx"))).get(0);
1350 } catch (NativeDaemonConnectorException e) {
1351 Slog.e(TAG, "Error communicating with native daemon to getthrottle", e);
1352 return -1;
1353 }
1354
1355 String[] tok = rsp.split(" ");
1356 if (tok.length < 2) {
1357 Slog.e(TAG, "Malformed response to getthrottle command");
1358 return -1;
1359 }
1360
San Mehat91cac642010-03-31 14:31:36 -07001361 int code;
1362 try {
1363 code = Integer.parseInt(tok[0]);
1364 } catch (NumberFormatException nfe) {
1365 Slog.e(TAG, String.format("Error parsing code %s", tok[0]));
1366 return -1;
1367 }
1368 if ((rx && code != NetdResponseCode.InterfaceRxThrottleResult) || (
1369 !rx && code != NetdResponseCode.InterfaceTxThrottleResult)) {
1370 Slog.e(TAG, String.format("Unexpected response code %d", code));
1371 return -1;
1372 }
1373 return Integer.parseInt(tok[1]);
1374 } catch (Exception e) {
1375 Slog.e(TAG, String.format(
1376 "Failed to read interface %s throttle value", (rx ? "rx" : "tx")), e);
1377 }
1378 return -1;
1379 }
1380
1381 public int getInterfaceRxThrottle(String iface) {
1382 return getInterfaceThrottle(iface, true);
1383 }
1384
1385 public int getInterfaceTxThrottle(String iface) {
1386 return getInterfaceThrottle(iface, false);
1387 }
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001388
1389 /**
Jeff Sharkey4414cea2011-06-24 17:05:24 -07001390 * Split given line into {@link ArrayList}.
1391 */
1392 private static void splitLine(String line, ArrayList<String> outSplit) {
1393 outSplit.clear();
1394
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001395 final StringTokenizer t = new StringTokenizer(line, " \t\n\r\f:");
Jeff Sharkey4414cea2011-06-24 17:05:24 -07001396 while (t.hasMoreTokens()) {
1397 outSplit.add(t.nextToken());
1398 }
1399 }
1400
1401 /**
1402 * Zip the two given {@link ArrayList} as key and value pairs into
1403 * {@link HashMap}.
1404 */
1405 private static void parseLine(
1406 ArrayList<String> keys, ArrayList<String> values, HashMap<String, String> outParsed) {
1407 outParsed.clear();
1408
1409 final int size = Math.min(keys.size(), values.size());
1410 for (int i = 0; i < size; i++) {
1411 outParsed.put(keys.get(i), values.get(i));
1412 }
1413 }
1414
1415 /**
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001416 * Utility method to read a single plain-text {@link Long} from the given
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001417 * {@link File}, usually from a {@code /proc/} filesystem.
1418 */
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001419 private static long readSingleLongFromFile(File file) {
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001420 try {
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001421 final byte[] buffer = IoUtils.readFileAsByteArray(file.toString());
1422 return Long.parseLong(new String(buffer).trim());
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001423 } catch (NumberFormatException e) {
1424 return -1;
1425 } catch (IOException e) {
1426 return -1;
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001427 }
1428 }
Jean-Baptiste Querud5299ff2011-07-07 08:46:09 -07001429
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001430 /**
1431 * Wrapper for {@link File#list()} that returns empty array instead of
1432 * {@code null}.
1433 */
1434 private static String[] fileListWithoutNull(File file) {
1435 final String[] list = file.list();
1436 return list != null ? list : new String[0];
1437 }
1438
Mattias Falk7475c0c2011-04-04 16:10:36 +02001439 public void setDefaultInterfaceForDns(String iface) throws IllegalStateException {
1440 mContext.enforceCallingOrSelfPermission(
1441 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
1442 try {
1443 String cmd = "resolver setdefaultif " + iface;
1444
1445 mConnector.doCommand(cmd);
1446 } catch (NativeDaemonConnectorException e) {
1447 throw new IllegalStateException(
1448 "Error communicating with native daemon to set default interface", e);
1449 }
1450 }
1451
1452 public void setDnsServersForInterface(String iface, String[] servers)
1453 throws IllegalStateException {
1454 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_NETWORK_STATE,
1455 "NetworkManagementService");
1456 try {
1457 String cmd = "resolver setifdns " + iface;
1458 for (String s : servers) {
Robert Greenwalt572b7042011-07-25 17:00:13 -07001459 InetAddress a = NetworkUtils.numericToInetAddress(s);
1460 if (a.isAnyLocalAddress() == false) {
1461 cmd += " " + a.getHostAddress();
Mattias Falk7475c0c2011-04-04 16:10:36 +02001462 }
1463 }
Mattias Falk7475c0c2011-04-04 16:10:36 +02001464 mConnector.doCommand(cmd);
Robert Greenwalt572b7042011-07-25 17:00:13 -07001465 } catch (IllegalArgumentException e) {
1466 throw new IllegalStateException("Error setting dnsn for interface", e);
Mattias Falk7475c0c2011-04-04 16:10:36 +02001467 } catch (NativeDaemonConnectorException e) {
1468 throw new IllegalStateException(
Robert Greenwalt572b7042011-07-25 17:00:13 -07001469 "Error communicating with native daemon to set dns for interface", e);
Mattias Falk7475c0c2011-04-04 16:10:36 +02001470 }
1471 }
1472
1473 public void flushDefaultDnsCache() throws IllegalStateException {
1474 mContext.enforceCallingOrSelfPermission(
1475 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
1476 try {
1477 String cmd = "resolver flushdefaultif";
1478
1479 mConnector.doCommand(cmd);
1480 } catch (NativeDaemonConnectorException e) {
1481 throw new IllegalStateException(
1482 "Error communicating with native deamon to flush default interface", e);
1483 }
1484 }
1485
1486 public void flushInterfaceDnsCache(String iface) throws IllegalStateException {
1487 mContext.enforceCallingOrSelfPermission(
1488 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
1489 try {
1490 String cmd = "resolver flushif " + iface;
1491
1492 mConnector.doCommand(cmd);
1493 } catch (NativeDaemonConnectorException e) {
1494 throw new IllegalStateException(
Robert Greenwalt572b7042011-07-25 17:00:13 -07001495 "Error communicating with native daemon to flush interface " + iface, e);
Mattias Falk7475c0c2011-04-04 16:10:36 +02001496 }
1497 }
San Mehat873f2142010-01-14 10:25:07 -08001498}