blob: 30de385f305a79b7e4265099c1986b2a1226b5b6 [file] [log] [blame]
San Mehat873f2142010-01-14 10:25:07 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
Jeff Sharkey350083e2011-06-29 10:45:16 -070019import static android.Manifest.permission.MANAGE_NETWORK_POLICY;
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -070020import static android.net.NetworkStats.IFACE_ALL;
21import static android.net.NetworkStats.TAG_NONE;
22import static android.net.NetworkStats.UID_ALL;
Jeff Sharkey350083e2011-06-29 10:45:16 -070023import static android.provider.Settings.Secure.NETSTATS_ENABLED;
Jeff Sharkeya63ba592011-07-19 23:47:12 -070024import static com.android.server.NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED;
25import static com.android.server.NetworkManagementSocketTagger.kernelToTag;
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -070026
San Mehat873f2142010-01-14 10:25:07 -080027import android.content.Context;
San Mehat873f2142010-01-14 10:25:07 -080028import android.content.pm.PackageManager;
San Mehat4d02d002010-01-22 16:07:46 -080029import android.net.INetworkManagementEventObserver;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070030import android.net.InterfaceConfiguration;
Robert Greenwalted126402011-01-28 15:34:55 -080031import android.net.LinkAddress;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070032import android.net.NetworkStats;
Robert Greenwalted126402011-01-28 15:34:55 -080033import android.net.NetworkUtils;
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -070034import android.net.RouteInfo;
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -080035import android.net.wifi.WifiConfiguration;
36import android.net.wifi.WifiConfiguration.KeyMgmt;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070037import android.os.Binder;
San Mehat873f2142010-01-14 10:25:07 -080038import android.os.INetworkManagementService;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070039import android.os.SystemClock;
Marco Nelissen62dbb222010-02-18 10:56:30 -080040import android.os.SystemProperties;
Jeff Sharkey350083e2011-06-29 10:45:16 -070041import android.provider.Settings;
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -080042import android.util.Log;
Joe Onorato8a9b2202010-02-26 18:56:32 -080043import android.util.Slog;
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -070044import android.util.SparseBooleanArray;
San Mehat873f2142010-01-14 10:25:07 -080045
Jeff Sharkey4414cea2011-06-24 17:05:24 -070046import com.google.android.collect.Lists;
47import com.google.android.collect.Maps;
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -070048import com.google.android.collect.Sets;
Jeff Sharkey4414cea2011-06-24 17:05:24 -070049
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -070050import java.io.BufferedReader;
51import java.io.DataInputStream;
San Mehat873f2142010-01-14 10:25:07 -080052import java.io.File;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070053import java.io.FileInputStream;
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -070054import java.io.FileReader;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070055import java.io.IOException;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070056import java.io.InputStreamReader;
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -070057import java.net.Inet4Address;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070058import java.net.InetAddress;
59import java.util.ArrayList;
Jeff Sharkey4414cea2011-06-24 17:05:24 -070060import java.util.HashMap;
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -070061import java.util.HashSet;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070062import java.util.NoSuchElementException;
63import java.util.StringTokenizer;
Robert Greenwalte5c3afb2010-09-22 14:32:35 -070064import java.util.concurrent.CountDownLatch;
San Mehat873f2142010-01-14 10:25:07 -080065
Jeff Sharkey9a13f362011-04-26 16:25:36 -070066import libcore.io.IoUtils;
67
San Mehat873f2142010-01-14 10:25:07 -080068/**
69 * @hide
70 */
71class NetworkManagementService extends INetworkManagementService.Stub {
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070072 private static final String TAG = "NetworkManagementService";
Dianne Hackborncef65ee2010-09-30 18:27:22 -070073 private static final boolean DBG = false;
Kenny Root305bcbf2010-09-03 07:56:38 -070074 private static final String NETD_TAG = "NetdConnector";
75
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -070076 private static final int ADD = 1;
77 private static final int REMOVE = 2;
78
Jeff Sharkey4414cea2011-06-24 17:05:24 -070079 /** Path to {@code /proc/uid_stat}. */
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -070080 @Deprecated
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -070081 private final File mStatsUid;
82 /** Path to {@code /proc/net/dev}. */
83 private final File mStatsIface;
Jeff Sharkey4414cea2011-06-24 17:05:24 -070084 /** Path to {@code /proc/net/xt_qtaguid/stats}. */
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -070085 private final File mStatsXtUid;
86 /** Path to {@code /proc/net/xt_qtaguid/iface_stat}. */
87 private final File mStatsXtIface;
Jeff Sharkey4414cea2011-06-24 17:05:24 -070088
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -070089 /** {@link #mStatsXtUid} headers. */
Jeff Sharkey4414cea2011-06-24 17:05:24 -070090 private static final String KEY_IFACE = "iface";
91 private static final String KEY_TAG_HEX = "acct_tag_hex";
92 private static final String KEY_UID = "uid_tag_int";
Jeff Sharkeya63ba592011-07-19 23:47:12 -070093 private static final String KEY_RX_BYTES = "rx_bytes";
94 private static final String KEY_RX_PACKETS = "rx_packets";
95 private static final String KEY_TX_BYTES = "tx_bytes";
96 private static final String KEY_TX_PACKETS = "tx_packets";
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070097
San Mehat873f2142010-01-14 10:25:07 -080098 class NetdResponseCode {
JP Abgrall12b933d2011-07-14 18:09:22 -070099 /* Keep in sync with system/netd/ResponseCode.h */
San Mehat873f2142010-01-14 10:25:07 -0800100 public static final int InterfaceListResult = 110;
101 public static final int TetherInterfaceListResult = 111;
102 public static final int TetherDnsFwdTgtListResult = 112;
San Mehat72759df2010-01-19 13:50:37 -0800103 public static final int TtyListResult = 113;
San Mehat873f2142010-01-14 10:25:07 -0800104
105 public static final int TetherStatusResult = 210;
106 public static final int IpFwdStatusResult = 211;
San Mehated4fc8a2010-01-22 12:28:36 -0800107 public static final int InterfaceGetCfgResult = 213;
Robert Greenwalte3253922010-02-18 09:23:25 -0800108 public static final int SoftapStatusResult = 214;
San Mehat91cac642010-03-31 14:31:36 -0700109 public static final int InterfaceRxCounterResult = 216;
110 public static final int InterfaceTxCounterResult = 217;
111 public static final int InterfaceRxThrottleResult = 218;
112 public static final int InterfaceTxThrottleResult = 219;
Robert Greenwalte3253922010-02-18 09:23:25 -0800113
114 public static final int InterfaceChange = 600;
JP Abgrall12b933d2011-07-14 18:09:22 -0700115 public static final int BandwidthControl = 601;
San Mehat873f2142010-01-14 10:25:07 -0800116 }
117
118 /**
119 * Binder context for this service
120 */
121 private Context mContext;
122
123 /**
124 * connector object for communicating with netd
125 */
126 private NativeDaemonConnector mConnector;
127
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700128 private Thread mThread;
129 private final CountDownLatch mConnectedSignal = new CountDownLatch(1);
130
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -0700131 // TODO: replace with RemoteCallbackList
San Mehat4d02d002010-01-22 16:07:46 -0800132 private ArrayList<INetworkManagementEventObserver> mObservers;
133
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -0700134 private Object mQuotaLock = new Object();
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -0700135 /** Set of interfaces with active quotas. */
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -0700136 private HashSet<String> mActiveQuotaIfaces = Sets.newHashSet();
137 /** Set of interfaces with active alerts. */
138 private HashSet<String> mActiveAlertIfaces = Sets.newHashSet();
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -0700139 /** Set of UIDs with active reject rules. */
140 private SparseBooleanArray mUidRejectOnQuota = new SparseBooleanArray();
141
Jeff Sharkey350083e2011-06-29 10:45:16 -0700142 private boolean mBandwidthControlEnabled;
143
San Mehat873f2142010-01-14 10:25:07 -0800144 /**
145 * Constructs a new NetworkManagementService instance
146 *
147 * @param context Binder context for this service
148 */
Jeff Sharkey4414cea2011-06-24 17:05:24 -0700149 private NetworkManagementService(Context context, File procRoot) {
San Mehat873f2142010-01-14 10:25:07 -0800150 mContext = context;
San Mehat4d02d002010-01-22 16:07:46 -0800151 mObservers = new ArrayList<INetworkManagementEventObserver>();
152
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700153 mStatsUid = new File(procRoot, "uid_stat");
154 mStatsIface = new File(procRoot, "net/dev");
155 mStatsXtUid = new File(procRoot, "net/xt_qtaguid/stats");
156 mStatsXtIface = new File(procRoot, "net/xt_qtaguid/iface_stat");
Jeff Sharkey4414cea2011-06-24 17:05:24 -0700157
Marco Nelissen62dbb222010-02-18 10:56:30 -0800158 if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
159 return;
160 }
161
San Mehat873f2142010-01-14 10:25:07 -0800162 mConnector = new NativeDaemonConnector(
Kenny Root305bcbf2010-09-03 07:56:38 -0700163 new NetdCallbackReceiver(), "netd", 10, NETD_TAG);
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700164 mThread = new Thread(mConnector, NETD_TAG);
165 }
166
167 public static NetworkManagementService create(Context context) throws InterruptedException {
Jeff Sharkey4414cea2011-06-24 17:05:24 -0700168 NetworkManagementService service = new NetworkManagementService(
169 context, new File("/proc/"));
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700170 if (DBG) Slog.d(TAG, "Creating NetworkManagementService");
171 service.mThread.start();
172 if (DBG) Slog.d(TAG, "Awaiting socket connection");
173 service.mConnectedSignal.await();
174 if (DBG) Slog.d(TAG, "Connected");
175 return service;
San Mehat873f2142010-01-14 10:25:07 -0800176 }
177
Jeff Sharkey4414cea2011-06-24 17:05:24 -0700178 // @VisibleForTesting
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700179 public static NetworkManagementService createForTest(
180 Context context, File procRoot, boolean bandwidthControlEnabled) {
Jeff Sharkey4414cea2011-06-24 17:05:24 -0700181 // TODO: eventually connect with mock netd
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700182 final NetworkManagementService service = new NetworkManagementService(context, procRoot);
183 service.mBandwidthControlEnabled = bandwidthControlEnabled;
184 return service;
Jeff Sharkey4414cea2011-06-24 17:05:24 -0700185 }
186
Jeff Sharkey350083e2011-06-29 10:45:16 -0700187 public void systemReady() {
188
189 // only enable bandwidth control when support exists, and requested by
190 // system setting.
191 // TODO: eventually migrate to be always enabled
192 final boolean hasKernelSupport = new File("/proc/net/xt_qtaguid/ctrl").exists();
193 final boolean shouldEnable =
194 Settings.Secure.getInt(mContext.getContentResolver(), NETSTATS_ENABLED, 0) != 0;
195
196 mBandwidthControlEnabled = false;
197 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 */
292 protected void onConnected() {
293 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 {
303 public void onDaemonConnected() {
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700304 NetworkManagementService.this.onConnected();
San Mehat873f2142010-01-14 10:25:07 -0800305 new Thread() {
306 public void run() {
San Mehat873f2142010-01-14 10:25:07 -0800307 }
308 }.start();
309 }
310 public boolean onEvent(int code, String raw, String[] cooked) {
JP Abgrall12b933d2011-07-14 18:09:22 -0700311 switch (code) {
312 case NetdResponseCode.InterfaceChange:
313 /*
314 * a network interface change occured
315 * Format: "NNN Iface added <name>"
316 * "NNN Iface removed <name>"
317 * "NNN Iface changed <name> <up/down>"
318 * "NNN Iface linkstatus <name> <up/down>"
319 */
320 if (cooked.length < 4 || !cooked[1].equals("Iface")) {
321 throw new IllegalStateException(
322 String.format("Invalid event from daemon (%s)", raw));
323 }
324 if (cooked[2].equals("added")) {
325 notifyInterfaceAdded(cooked[3]);
326 return true;
327 } else if (cooked[2].equals("removed")) {
328 notifyInterfaceRemoved(cooked[3]);
329 return true;
330 } else if (cooked[2].equals("changed") && cooked.length == 5) {
331 notifyInterfaceStatusChanged(cooked[3], cooked[4].equals("up"));
332 return true;
333 } else if (cooked[2].equals("linkstate") && cooked.length == 5) {
334 notifyInterfaceLinkStateChanged(cooked[3], cooked[4].equals("up"));
335 return true;
336 }
Robert Greenwalte3253922010-02-18 09:23:25 -0800337 throw new IllegalStateException(
338 String.format("Invalid event from daemon (%s)", raw));
JP Abgrall12b933d2011-07-14 18:09:22 -0700339 // break;
340 case NetdResponseCode.BandwidthControl:
341 /*
342 * Bandwidth control needs some attention
343 * Format: "NNN limit alert <alertName> <ifaceName>"
344 */
345 if (cooked.length < 5 || !cooked[1].equals("limit")) {
346 throw new IllegalStateException(
347 String.format("Invalid event from daemon (%s)", raw));
348 }
349 if (cooked[2].equals("alert")) {
350 notifyLimitReached(cooked[3], cooked[4]);
351 return true;
352 }
353 throw new IllegalStateException(
354 String.format("Invalid event from daemon (%s)", raw));
355 // break;
356 default: break;
Robert Greenwalte3253922010-02-18 09:23:25 -0800357 }
358 return false;
San Mehat873f2142010-01-14 10:25:07 -0800359 }
360 }
361
San Mehated4fc8a2010-01-22 12:28:36 -0800362
San Mehat873f2142010-01-14 10:25:07 -0800363 //
364 // INetworkManagementService members
365 //
366
367 public String[] listInterfaces() throws IllegalStateException {
368 mContext.enforceCallingOrSelfPermission(
369 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
370
Kenny Roota80ce062010-06-01 13:23:53 -0700371 try {
372 return mConnector.doListCommand("interface list", NetdResponseCode.InterfaceListResult);
373 } catch (NativeDaemonConnectorException e) {
374 throw new IllegalStateException(
375 "Cannot communicate with native daemon to list interfaces");
376 }
San Mehated4fc8a2010-01-22 12:28:36 -0800377 }
378
379 public InterfaceConfiguration getInterfaceConfig(String iface) throws IllegalStateException {
Kenny Roota80ce062010-06-01 13:23:53 -0700380 String rsp;
381 try {
382 rsp = mConnector.doCommand("interface getcfg " + iface).get(0);
383 } catch (NativeDaemonConnectorException e) {
384 throw new IllegalStateException(
385 "Cannot communicate with native daemon to get interface config");
386 }
Joe Onorato8a9b2202010-02-26 18:56:32 -0800387 Slog.d(TAG, String.format("rsp <%s>", rsp));
San Mehated4fc8a2010-01-22 12:28:36 -0800388
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800389 // Rsp: 213 xx:xx:xx:xx:xx:xx yyy.yyy.yyy.yyy zzz [flag1 flag2 flag3]
San Mehated4fc8a2010-01-22 12:28:36 -0800390 StringTokenizer st = new StringTokenizer(rsp);
391
Kenny Roota80ce062010-06-01 13:23:53 -0700392 InterfaceConfiguration cfg;
San Mehated4fc8a2010-01-22 12:28:36 -0800393 try {
Kenny Roota80ce062010-06-01 13:23:53 -0700394 try {
395 int code = Integer.parseInt(st.nextToken(" "));
396 if (code != NetdResponseCode.InterfaceGetCfgResult) {
397 throw new IllegalStateException(
398 String.format("Expected code %d, but got %d",
399 NetdResponseCode.InterfaceGetCfgResult, code));
400 }
401 } catch (NumberFormatException nfe) {
San Mehated4fc8a2010-01-22 12:28:36 -0800402 throw new IllegalStateException(
Kenny Roota80ce062010-06-01 13:23:53 -0700403 String.format("Invalid response from daemon (%s)", rsp));
San Mehated4fc8a2010-01-22 12:28:36 -0800404 }
Kenny Roota80ce062010-06-01 13:23:53 -0700405
406 cfg = new InterfaceConfiguration();
407 cfg.hwAddr = st.nextToken(" ");
Robert Greenwalted126402011-01-28 15:34:55 -0800408 InetAddress addr = null;
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800409 int prefixLength = 0;
Kenny Roota80ce062010-06-01 13:23:53 -0700410 try {
Robert Greenwalte5903732011-02-22 16:00:42 -0800411 addr = NetworkUtils.numericToInetAddress(st.nextToken(" "));
412 } catch (IllegalArgumentException iae) {
413 Slog.e(TAG, "Failed to parse ipaddr", iae);
Kenny Roota80ce062010-06-01 13:23:53 -0700414 }
415
416 try {
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800417 prefixLength = Integer.parseInt(st.nextToken(" "));
418 } catch (NumberFormatException nfe) {
419 Slog.e(TAG, "Failed to parse prefixLength", nfe);
Kenny Roota80ce062010-06-01 13:23:53 -0700420 }
Robert Greenwalt04808c22010-12-13 17:01:41 -0800421
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800422 cfg.addr = new LinkAddress(addr, prefixLength);
Kenny Roota80ce062010-06-01 13:23:53 -0700423 cfg.interfaceFlags = st.nextToken("]").trim() +"]";
424 } catch (NoSuchElementException nsee) {
San Mehated4fc8a2010-01-22 12:28:36 -0800425 throw new IllegalStateException(
426 String.format("Invalid response from daemon (%s)", rsp));
427 }
Joe Onorato8a9b2202010-02-26 18:56:32 -0800428 Slog.d(TAG, String.format("flags <%s>", cfg.interfaceFlags));
San Mehated4fc8a2010-01-22 12:28:36 -0800429 return cfg;
430 }
431
432 public void setInterfaceConfig(
433 String iface, InterfaceConfiguration cfg) throws IllegalStateException {
Robert Greenwalted126402011-01-28 15:34:55 -0800434 LinkAddress linkAddr = cfg.addr;
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800435 if (linkAddr == null || linkAddr.getAddress() == null) {
436 throw new IllegalStateException("Null LinkAddress given");
Robert Greenwalted126402011-01-28 15:34:55 -0800437 }
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800438 String cmd = String.format("interface setcfg %s %s %d %s", iface,
439 linkAddr.getAddress().getHostAddress(),
440 linkAddr.getNetworkPrefixLength(),
441 cfg.interfaceFlags);
Kenny Roota80ce062010-06-01 13:23:53 -0700442 try {
443 mConnector.doCommand(cmd);
444 } catch (NativeDaemonConnectorException e) {
445 throw new IllegalStateException(
Robert Greenwalt81d5ad52010-12-16 11:27:38 -0800446 "Unable to communicate with native daemon to interface setcfg - " + e);
Kenny Roota80ce062010-06-01 13:23:53 -0700447 }
San Mehat873f2142010-01-14 10:25:07 -0800448 }
449
Irfan Sherifff5600612011-06-16 10:26:28 -0700450 /* TODO: This is right now a IPv4 only function. Works for wifi which loses its
451 IPv6 addresses on interface down, but we need to do full clean up here */
452 public void clearInterfaceAddresses(String iface) throws IllegalStateException {
453 String cmd = String.format("interface clearaddrs %s", iface);
454 try {
455 mConnector.doCommand(cmd);
456 } catch (NativeDaemonConnectorException e) {
457 throw new IllegalStateException(
458 "Unable to communicate with native daemon to interface clearallips - " + e);
459 }
460 }
461
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -0700462 public void addRoute(String interfaceName, RouteInfo route) {
463 modifyRoute(interfaceName, ADD, route);
464 }
465
466 public void removeRoute(String interfaceName, RouteInfo route) {
467 modifyRoute(interfaceName, REMOVE, route);
468 }
469
470 private void modifyRoute(String interfaceName, int action, RouteInfo route) {
471 ArrayList<String> rsp;
472
473 StringBuilder cmd;
474
475 switch (action) {
476 case ADD:
477 {
478 cmd = new StringBuilder("interface route add " + interfaceName);
479 break;
480 }
481 case REMOVE:
482 {
483 cmd = new StringBuilder("interface route remove " + interfaceName);
484 break;
485 }
486 default:
487 throw new IllegalStateException("Unknown action type " + action);
488 }
489
490 // create triplet: dest-ip-addr prefixlength gateway-ip-addr
491 LinkAddress la = route.getDestination();
492 cmd.append(' ');
493 cmd.append(la.getAddress().getHostAddress());
494 cmd.append(' ');
495 cmd.append(la.getNetworkPrefixLength());
496 cmd.append(' ');
497 if (route.getGateway() == null) {
498 if (la.getAddress() instanceof Inet4Address) {
499 cmd.append("0.0.0.0");
500 } else {
501 cmd.append ("::0");
502 }
503 } else {
504 cmd.append(route.getGateway().getHostAddress());
505 }
506 try {
507 rsp = mConnector.doCommand(cmd.toString());
508 } catch (NativeDaemonConnectorException e) {
509 throw new IllegalStateException(
510 "Unable to communicate with native dameon to add routes - "
511 + e);
512 }
513
514 for (String line : rsp) {
515 Log.v(TAG, "add route response is " + line);
516 }
517 }
518
519 private ArrayList<String> readRouteList(String filename) {
520 FileInputStream fstream = null;
521 ArrayList<String> list = new ArrayList<String>();
522
523 try {
524 fstream = new FileInputStream(filename);
525 DataInputStream in = new DataInputStream(fstream);
526 BufferedReader br = new BufferedReader(new InputStreamReader(in));
527 String s;
528
529 // throw away the title line
530
531 while (((s = br.readLine()) != null) && (s.length() != 0)) {
532 list.add(s);
533 }
534 } catch (IOException ex) {
535 // return current list, possibly empty
536 } finally {
537 if (fstream != null) {
538 try {
539 fstream.close();
540 } catch (IOException ex) {}
541 }
542 }
543
544 return list;
545 }
546
547 public RouteInfo[] getRoutes(String interfaceName) {
548 ArrayList<RouteInfo> routes = new ArrayList<RouteInfo>();
549
550 // v4 routes listed as:
551 // iface dest-addr gateway-addr flags refcnt use metric netmask mtu window IRTT
552 for (String s : readRouteList("/proc/net/route")) {
553 String[] fields = s.split("\t");
554
555 if (fields.length > 7) {
556 String iface = fields[0];
557
558 if (interfaceName.equals(iface)) {
559 String dest = fields[1];
560 String gate = fields[2];
561 String flags = fields[3]; // future use?
562 String mask = fields[7];
563 try {
564 // address stored as a hex string, ex: 0014A8C0
565 InetAddress destAddr =
566 NetworkUtils.intToInetAddress((int)Long.parseLong(dest, 16));
567 int prefixLength =
568 NetworkUtils.netmaskIntToPrefixLength(
569 (int)Long.parseLong(mask, 16));
570 LinkAddress linkAddress = new LinkAddress(destAddr, prefixLength);
571
572 // address stored as a hex string, ex 0014A8C0
573 InetAddress gatewayAddr =
574 NetworkUtils.intToInetAddress((int)Long.parseLong(gate, 16));
575
576 RouteInfo route = new RouteInfo(linkAddress, gatewayAddr);
577 routes.add(route);
578 } catch (Exception e) {
579 Log.e(TAG, "Error parsing route " + s + " : " + e);
580 continue;
581 }
582 }
583 }
584 }
585
586 // v6 routes listed as:
587 // dest-addr prefixlength ?? ?? gateway-addr ?? ?? ?? ?? iface
588 for (String s : readRouteList("/proc/net/ipv6_route")) {
589 String[]fields = s.split("\\s+");
590 if (fields.length > 9) {
591 String iface = fields[9].trim();
592 if (interfaceName.equals(iface)) {
593 String dest = fields[0];
594 String prefix = fields[1];
595 String gate = fields[4];
596
597 try {
598 // prefix length stored as a hex string, ex 40
599 int prefixLength = Integer.parseInt(prefix, 16);
600
601 // address stored as a 32 char hex string
602 // ex fe800000000000000000000000000000
603 InetAddress destAddr = NetworkUtils.hexToInet6Address(dest);
604 LinkAddress linkAddress = new LinkAddress(destAddr, prefixLength);
605
606 InetAddress gateAddr = NetworkUtils.hexToInet6Address(gate);
607
608 RouteInfo route = new RouteInfo(linkAddress, gateAddr);
609 routes.add(route);
610 } catch (Exception e) {
611 Log.e(TAG, "Error parsing route " + s + " : " + e);
612 continue;
613 }
614 }
615 }
616 }
617 return (RouteInfo[]) routes.toArray(new RouteInfo[0]);
618 }
619
San Mehat873f2142010-01-14 10:25:07 -0800620 public void shutdown() {
621 if (mContext.checkCallingOrSelfPermission(
622 android.Manifest.permission.SHUTDOWN)
623 != PackageManager.PERMISSION_GRANTED) {
624 throw new SecurityException("Requires SHUTDOWN permission");
625 }
626
Joe Onorato8a9b2202010-02-26 18:56:32 -0800627 Slog.d(TAG, "Shutting down");
San Mehat873f2142010-01-14 10:25:07 -0800628 }
629
630 public boolean getIpForwardingEnabled() throws IllegalStateException{
631 mContext.enforceCallingOrSelfPermission(
632 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
633
Kenny Roota80ce062010-06-01 13:23:53 -0700634 ArrayList<String> rsp;
635 try {
636 rsp = mConnector.doCommand("ipfwd status");
637 } catch (NativeDaemonConnectorException e) {
638 throw new IllegalStateException(
639 "Unable to communicate with native daemon to ipfwd status");
640 }
San Mehat873f2142010-01-14 10:25:07 -0800641
642 for (String line : rsp) {
Kenny Roota80ce062010-06-01 13:23:53 -0700643 String[] tok = line.split(" ");
644 if (tok.length < 3) {
645 Slog.e(TAG, "Malformed response from native daemon: " + line);
646 return false;
647 }
648
San Mehat873f2142010-01-14 10:25:07 -0800649 int code = Integer.parseInt(tok[0]);
650 if (code == NetdResponseCode.IpFwdStatusResult) {
651 // 211 Forwarding <enabled/disabled>
Kenny Roota80ce062010-06-01 13:23:53 -0700652 return "enabled".equals(tok[2]);
San Mehat873f2142010-01-14 10:25:07 -0800653 } else {
654 throw new IllegalStateException(String.format("Unexpected response code %d", code));
655 }
656 }
657 throw new IllegalStateException("Got an empty response");
658 }
659
660 public void setIpForwardingEnabled(boolean enable) throws IllegalStateException {
661 mContext.enforceCallingOrSelfPermission(
662 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
663 mConnector.doCommand(String.format("ipfwd %sable", (enable ? "en" : "dis")));
664 }
665
Robert Greenwaltbfb7bfa2010-03-24 16:03:21 -0700666 public void startTethering(String[] dhcpRange)
San Mehat873f2142010-01-14 10:25:07 -0800667 throws IllegalStateException {
668 mContext.enforceCallingOrSelfPermission(
669 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Robert Greenwaltbfb7bfa2010-03-24 16:03:21 -0700670 // cmd is "tether start first_start first_stop second_start second_stop ..."
671 // an odd number of addrs will fail
672 String cmd = "tether start";
673 for (String d : dhcpRange) {
674 cmd += " " + d;
675 }
Kenny Roota80ce062010-06-01 13:23:53 -0700676
677 try {
678 mConnector.doCommand(cmd);
679 } catch (NativeDaemonConnectorException e) {
680 throw new IllegalStateException("Unable to communicate to native daemon");
681 }
San Mehat873f2142010-01-14 10:25:07 -0800682 }
683
684 public void stopTethering() throws IllegalStateException {
685 mContext.enforceCallingOrSelfPermission(
686 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700687 try {
688 mConnector.doCommand("tether stop");
689 } catch (NativeDaemonConnectorException e) {
690 throw new IllegalStateException("Unable to communicate to native daemon to stop tether");
691 }
San Mehat873f2142010-01-14 10:25:07 -0800692 }
693
694 public boolean isTetheringStarted() throws IllegalStateException {
695 mContext.enforceCallingOrSelfPermission(
696 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
697
Kenny Roota80ce062010-06-01 13:23:53 -0700698 ArrayList<String> rsp;
699 try {
700 rsp = mConnector.doCommand("tether status");
701 } catch (NativeDaemonConnectorException e) {
702 throw new IllegalStateException(
703 "Unable to communicate to native daemon to get tether status");
704 }
San Mehat873f2142010-01-14 10:25:07 -0800705
706 for (String line : rsp) {
Kenny Roota80ce062010-06-01 13:23:53 -0700707 String[] tok = line.split(" ");
708 if (tok.length < 3) {
709 throw new IllegalStateException("Malformed response for tether status: " + line);
710 }
San Mehat873f2142010-01-14 10:25:07 -0800711 int code = Integer.parseInt(tok[0]);
712 if (code == NetdResponseCode.TetherStatusResult) {
713 // XXX: Tethering services <started/stopped> <TBD>...
Kenny Roota80ce062010-06-01 13:23:53 -0700714 return "started".equals(tok[2]);
San Mehat873f2142010-01-14 10:25:07 -0800715 } else {
716 throw new IllegalStateException(String.format("Unexpected response code %d", code));
717 }
718 }
719 throw new IllegalStateException("Got an empty response");
720 }
721
722 public void tetherInterface(String iface) throws IllegalStateException {
723 mContext.enforceCallingOrSelfPermission(
724 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700725 try {
726 mConnector.doCommand("tether interface add " + iface);
727 } catch (NativeDaemonConnectorException e) {
728 throw new IllegalStateException(
729 "Unable to communicate to native daemon for adding tether interface");
730 }
San Mehat873f2142010-01-14 10:25:07 -0800731 }
732
733 public void untetherInterface(String iface) {
734 mContext.enforceCallingOrSelfPermission(
735 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700736 try {
737 mConnector.doCommand("tether interface remove " + iface);
738 } catch (NativeDaemonConnectorException e) {
739 throw new IllegalStateException(
740 "Unable to communicate to native daemon for removing tether interface");
741 }
San Mehat873f2142010-01-14 10:25:07 -0800742 }
743
744 public String[] listTetheredInterfaces() throws IllegalStateException {
745 mContext.enforceCallingOrSelfPermission(
746 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700747 try {
748 return mConnector.doListCommand(
749 "tether interface list", NetdResponseCode.TetherInterfaceListResult);
750 } catch (NativeDaemonConnectorException e) {
751 throw new IllegalStateException(
752 "Unable to communicate to native daemon for listing tether interfaces");
753 }
San Mehat873f2142010-01-14 10:25:07 -0800754 }
755
756 public void setDnsForwarders(String[] dns) throws IllegalStateException {
757 mContext.enforceCallingOrSelfPermission(
758 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
759 try {
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800760 String cmd = "tether dns set";
San Mehat873f2142010-01-14 10:25:07 -0800761 for (String s : dns) {
Robert Greenwalte5903732011-02-22 16:00:42 -0800762 cmd += " " + NetworkUtils.numericToInetAddress(s).getHostAddress();
San Mehat873f2142010-01-14 10:25:07 -0800763 }
Kenny Roota80ce062010-06-01 13:23:53 -0700764 try {
765 mConnector.doCommand(cmd);
766 } catch (NativeDaemonConnectorException e) {
767 throw new IllegalStateException(
768 "Unable to communicate to native daemon for setting tether dns");
769 }
Robert Greenwalte5903732011-02-22 16:00:42 -0800770 } catch (IllegalArgumentException e) {
San Mehat873f2142010-01-14 10:25:07 -0800771 throw new IllegalStateException("Error resolving dns name", e);
772 }
773 }
774
775 public String[] getDnsForwarders() throws IllegalStateException {
776 mContext.enforceCallingOrSelfPermission(
777 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700778 try {
779 return mConnector.doListCommand(
780 "tether dns list", NetdResponseCode.TetherDnsFwdTgtListResult);
781 } catch (NativeDaemonConnectorException e) {
782 throw new IllegalStateException(
783 "Unable to communicate to native daemon for listing tether dns");
784 }
San Mehat873f2142010-01-14 10:25:07 -0800785 }
786
787 public void enableNat(String internalInterface, String externalInterface)
788 throws IllegalStateException {
789 mContext.enforceCallingOrSelfPermission(
790 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700791 try {
792 mConnector.doCommand(
793 String.format("nat enable %s %s", internalInterface, externalInterface));
794 } catch (NativeDaemonConnectorException e) {
795 throw new IllegalStateException(
796 "Unable to communicate to native daemon for enabling NAT interface");
797 }
San Mehat873f2142010-01-14 10:25:07 -0800798 }
799
800 public void disableNat(String internalInterface, String externalInterface)
801 throws IllegalStateException {
802 mContext.enforceCallingOrSelfPermission(
803 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700804 try {
805 mConnector.doCommand(
806 String.format("nat disable %s %s", internalInterface, externalInterface));
807 } catch (NativeDaemonConnectorException e) {
808 throw new IllegalStateException(
809 "Unable to communicate to native daemon for disabling NAT interface");
810 }
San Mehat873f2142010-01-14 10:25:07 -0800811 }
San Mehat72759df2010-01-19 13:50:37 -0800812
813 public String[] listTtys() throws IllegalStateException {
814 mContext.enforceCallingOrSelfPermission(
815 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700816 try {
817 return mConnector.doListCommand("list_ttys", NetdResponseCode.TtyListResult);
818 } catch (NativeDaemonConnectorException e) {
819 throw new IllegalStateException(
820 "Unable to communicate to native daemon for listing TTYs");
821 }
San Mehat72759df2010-01-19 13:50:37 -0800822 }
823
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800824 public void attachPppd(String tty, String localAddr, String remoteAddr, String dns1Addr,
825 String dns2Addr) throws IllegalStateException {
San Mehat72759df2010-01-19 13:50:37 -0800826 try {
827 mContext.enforceCallingOrSelfPermission(
828 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800829 mConnector.doCommand(String.format("pppd attach %s %s %s %s %s", tty,
Robert Greenwalte5903732011-02-22 16:00:42 -0800830 NetworkUtils.numericToInetAddress(localAddr).getHostAddress(),
831 NetworkUtils.numericToInetAddress(remoteAddr).getHostAddress(),
832 NetworkUtils.numericToInetAddress(dns1Addr).getHostAddress(),
833 NetworkUtils.numericToInetAddress(dns2Addr).getHostAddress()));
834 } catch (IllegalArgumentException e) {
San Mehat72759df2010-01-19 13:50:37 -0800835 throw new IllegalStateException("Error resolving addr", e);
Kenny Roota80ce062010-06-01 13:23:53 -0700836 } catch (NativeDaemonConnectorException e) {
837 throw new IllegalStateException("Error communicating to native daemon to attach pppd", e);
San Mehat72759df2010-01-19 13:50:37 -0800838 }
839 }
840
841 public void detachPppd(String tty) throws IllegalStateException {
842 mContext.enforceCallingOrSelfPermission(
843 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700844 try {
845 mConnector.doCommand(String.format("pppd detach %s", tty));
846 } catch (NativeDaemonConnectorException e) {
847 throw new IllegalStateException("Error communicating to native daemon to detach pppd", e);
848 }
San Mehat72759df2010-01-19 13:50:37 -0800849 }
Robert Greenwaltce1200d2010-02-18 11:25:54 -0800850
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700851 public void startAccessPoint(WifiConfiguration wifiConfig, String wlanIface, String softapIface)
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800852 throws IllegalStateException {
853 mContext.enforceCallingOrSelfPermission(
854 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
855 mContext.enforceCallingOrSelfPermission(
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700856 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700857 try {
Kenny Roota80ce062010-06-01 13:23:53 -0700858 mConnector.doCommand(String.format("softap fwreload " + wlanIface + " AP"));
859 mConnector.doCommand(String.format("softap start " + wlanIface));
860 if (wifiConfig == null) {
861 mConnector.doCommand(String.format("softap set " + wlanIface + " " + softapIface));
862 } else {
863 /**
864 * softap set arg1 arg2 arg3 [arg4 arg5 arg6 arg7 arg8]
865 * argv1 - wlan interface
866 * argv2 - softap interface
867 * argv3 - SSID
868 * argv4 - Security
869 * argv5 - Key
870 * argv6 - Channel
871 * argv7 - Preamble
872 * argv8 - Max SCB
873 */
Irfan Sheriffec8d23a2011-02-16 17:00:33 -0800874 String str = String.format("softap set " + wlanIface + " " + softapIface +
875 " %s %s %s", convertQuotedString(wifiConfig.SSID),
876 getSecurityType(wifiConfig),
877 convertQuotedString(wifiConfig.preSharedKey));
Kenny Roota80ce062010-06-01 13:23:53 -0700878 mConnector.doCommand(str);
879 }
880 mConnector.doCommand(String.format("softap startap"));
881 } catch (NativeDaemonConnectorException e) {
882 throw new IllegalStateException("Error communicating to native daemon to start softap", e);
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -0800883 }
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800884 }
885
Irfan Sheriffa6e559e2010-05-24 14:55:42 -0700886 private String convertQuotedString(String s) {
Irfan Sheriff7baec0f2010-05-26 17:16:47 -0700887 if (s == null) {
888 return s;
889 }
890 /* Replace \ with \\, then " with \" and add quotes at end */
891 return '"' + s.replaceAll("\\\\","\\\\\\\\").replaceAll("\"","\\\\\"") + '"';
Irfan Sheriffa6e559e2010-05-24 14:55:42 -0700892 }
893
Irfan Sheriffec8d23a2011-02-16 17:00:33 -0800894 private String getSecurityType(WifiConfiguration wifiConfig) {
895 switch (wifiConfig.getAuthType()) {
896 case KeyMgmt.WPA_PSK:
897 return "wpa-psk";
898 case KeyMgmt.WPA2_PSK:
899 return "wpa2-psk";
900 default:
901 return "open";
902 }
903 }
904
Irfan Sheriff23eb2972011-07-22 15:21:10 -0700905 public void stopAccessPoint(String wlanIface) throws IllegalStateException {
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800906 mContext.enforceCallingOrSelfPermission(
907 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
908 mContext.enforceCallingOrSelfPermission(
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700909 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700910 try {
911 mConnector.doCommand("softap stopap");
Irfan Sheriff23eb2972011-07-22 15:21:10 -0700912 mConnector.doCommand("softap stop " + wlanIface);
913 mConnector.doCommand(String.format("softap fwreload " + wlanIface + " STA"));
Kenny Roota80ce062010-06-01 13:23:53 -0700914 } catch (NativeDaemonConnectorException e) {
915 throw new IllegalStateException("Error communicating to native daemon to stop soft AP",
916 e);
917 }
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800918 }
919
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700920 public void setAccessPoint(WifiConfiguration wifiConfig, String wlanIface, String softapIface)
921 throws IllegalStateException {
922 mContext.enforceCallingOrSelfPermission(
923 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
924 mContext.enforceCallingOrSelfPermission(
925 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700926 try {
927 if (wifiConfig == null) {
928 mConnector.doCommand(String.format("softap set " + wlanIface + " " + softapIface));
929 } else {
930 String str = String.format("softap set " + wlanIface + " " + softapIface
931 + " %s %s %s", convertQuotedString(wifiConfig.SSID),
Irfan Sheriffec8d23a2011-02-16 17:00:33 -0800932 getSecurityType(wifiConfig),
Kenny Roota80ce062010-06-01 13:23:53 -0700933 convertQuotedString(wifiConfig.preSharedKey));
934 mConnector.doCommand(str);
935 }
936 } catch (NativeDaemonConnectorException e) {
937 throw new IllegalStateException("Error communicating to native daemon to set soft AP",
938 e);
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700939 }
940 }
San Mehat91cac642010-03-31 14:31:36 -0700941
942 private long getInterfaceCounter(String iface, boolean rx) {
943 mContext.enforceCallingOrSelfPermission(
944 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
945 try {
Kenny Roota80ce062010-06-01 13:23:53 -0700946 String rsp;
947 try {
948 rsp = mConnector.doCommand(
949 String.format("interface read%scounter %s", (rx ? "rx" : "tx"), iface)).get(0);
950 } catch (NativeDaemonConnectorException e1) {
951 Slog.e(TAG, "Error communicating with native daemon", e1);
952 return -1;
953 }
954
955 String[] tok = rsp.split(" ");
956 if (tok.length < 2) {
957 Slog.e(TAG, String.format("Malformed response for reading %s interface",
958 (rx ? "rx" : "tx")));
959 return -1;
960 }
961
San Mehat91cac642010-03-31 14:31:36 -0700962 int code;
963 try {
964 code = Integer.parseInt(tok[0]);
965 } catch (NumberFormatException nfe) {
966 Slog.e(TAG, String.format("Error parsing code %s", tok[0]));
967 return -1;
968 }
969 if ((rx && code != NetdResponseCode.InterfaceRxCounterResult) || (
970 !rx && code != NetdResponseCode.InterfaceTxCounterResult)) {
971 Slog.e(TAG, String.format("Unexpected response code %d", code));
972 return -1;
973 }
974 return Long.parseLong(tok[1]);
975 } catch (Exception e) {
976 Slog.e(TAG, String.format(
977 "Failed to read interface %s counters", (rx ? "rx" : "tx")), e);
978 }
979 return -1;
980 }
981
Jeff Sharkeyeedcb952011-05-17 14:55:15 -0700982 @Override
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700983 public NetworkStats getNetworkStatsSummary() {
984 mContext.enforceCallingOrSelfPermission(
985 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
986
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700987 final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6);
988 final NetworkStats.Entry entry = new NetworkStats.Entry();
Jeff Sharkey9a13f362011-04-26 16:25:36 -0700989
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700990 final HashSet<String> activeIfaces = Sets.newHashSet();
991 final ArrayList<String> values = Lists.newArrayList();
992
993 BufferedReader reader = null;
994 try {
995 reader = new BufferedReader(new FileReader(mStatsIface));
996
997 // skip first two header lines
998 reader.readLine();
999 reader.readLine();
1000
1001 // parse remaining lines
1002 String line;
1003 while ((line = reader.readLine()) != null) {
1004 splitLine(line, values);
1005
1006 try {
1007 entry.iface = values.get(0);
1008 entry.uid = UID_ALL;
1009 entry.tag = TAG_NONE;
1010 entry.rxBytes = Long.parseLong(values.get(1));
1011 entry.rxPackets = Long.parseLong(values.get(2));
1012 entry.txBytes = Long.parseLong(values.get(9));
1013 entry.txPackets = Long.parseLong(values.get(10));
1014
1015 activeIfaces.add(entry.iface);
1016 stats.addValues(entry);
1017 } catch (NumberFormatException e) {
1018 Slog.w(TAG, "problem parsing stats row '" + line + "': " + e);
1019 }
1020 }
1021 } catch (IOException e) {
1022 Slog.w(TAG, "problem parsing stats: " + e);
1023 } finally {
1024 IoUtils.closeQuietly(reader);
1025 }
1026
1027 if (DBG) Slog.d(TAG, "recorded active stats from " + activeIfaces);
1028
1029 // splice in stats from any disabled ifaces
1030 if (mBandwidthControlEnabled) {
1031 final HashSet<String> xtIfaces = Sets.newHashSet(fileListWithoutNull(mStatsXtIface));
1032 xtIfaces.removeAll(activeIfaces);
1033
1034 for (String iface : xtIfaces) {
1035 final File ifacePath = new File(mStatsXtIface, iface);
1036
1037 entry.iface = iface;
1038 entry.uid = UID_ALL;
1039 entry.tag = TAG_NONE;
1040 entry.rxBytes = readSingleLongFromFile(new File(ifacePath, "rx_bytes"));
1041 entry.rxPackets = readSingleLongFromFile(new File(ifacePath, "rx_packets"));
1042 entry.txBytes = readSingleLongFromFile(new File(ifacePath, "tx_bytes"));
1043 entry.txPackets = readSingleLongFromFile(new File(ifacePath, "tx_packets"));
1044
1045 stats.addValues(entry);
1046 }
1047
1048 if (DBG) Slog.d(TAG, "recorded stale stats from " + xtIfaces);
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001049 }
1050
Jeff Sharkey4a971222011-06-11 22:16:55 -07001051 return stats;
San Mehat91cac642010-03-31 14:31:36 -07001052 }
1053
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001054 @Override
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001055 public NetworkStats getNetworkStatsDetail() {
1056 mContext.enforceCallingOrSelfPermission(
1057 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
1058
Jeff Sharkey350083e2011-06-29 10:45:16 -07001059 if (mBandwidthControlEnabled) {
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001060 return getNetworkStatsDetailNetfilter(UID_ALL);
1061 } else {
1062 return getNetworkStatsDetailUidstat(UID_ALL);
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001063 }
San Mehat91cac642010-03-31 14:31:36 -07001064 }
1065
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001066 @Override
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001067 public void setInterfaceQuota(String iface, long quotaBytes) {
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001068 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1069
Jeff Sharkey350083e2011-06-29 10:45:16 -07001070 // silently discard when control disabled
1071 // TODO: eventually migrate to be always enabled
1072 if (!mBandwidthControlEnabled) return;
1073
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001074 synchronized (mQuotaLock) {
1075 if (mActiveQuotaIfaces.contains(iface)) {
1076 throw new IllegalStateException("iface " + iface + " already has quota");
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001077 }
1078
1079 final StringBuilder command = new StringBuilder();
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001080 command.append("bandwidth setiquota ").append(iface).append(" ").append(quotaBytes);
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001081
1082 try {
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001083 // TODO: support quota shared across interfaces
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001084 mConnector.doCommand(command.toString());
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001085 mActiveQuotaIfaces.add(iface);
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001086 } catch (NativeDaemonConnectorException e) {
1087 throw new IllegalStateException("Error communicating to native daemon", e);
1088 }
Ashish Sharma50fd36d2011-06-15 19:34:53 -07001089 }
1090 }
1091
1092 @Override
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001093 public void removeInterfaceQuota(String iface) {
1094 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1095
Jeff Sharkey350083e2011-06-29 10:45:16 -07001096 // silently discard when control disabled
1097 // TODO: eventually migrate to be always enabled
1098 if (!mBandwidthControlEnabled) return;
1099
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001100 synchronized (mQuotaLock) {
1101 if (!mActiveQuotaIfaces.contains(iface)) {
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001102 // TODO: eventually consider throwing
1103 return;
1104 }
1105
1106 final StringBuilder command = new StringBuilder();
1107 command.append("bandwidth removeiquota ").append(iface);
1108
1109 try {
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001110 // TODO: support quota shared across interfaces
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001111 mConnector.doCommand(command.toString());
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001112 mActiveQuotaIfaces.remove(iface);
1113 mActiveAlertIfaces.remove(iface);
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001114 } catch (NativeDaemonConnectorException e) {
1115 throw new IllegalStateException("Error communicating to native daemon", e);
1116 }
1117 }
1118 }
1119
1120 @Override
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001121 public void setInterfaceAlert(String iface, long alertBytes) {
1122 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1123
1124 // silently discard when control disabled
1125 // TODO: eventually migrate to be always enabled
1126 if (!mBandwidthControlEnabled) return;
1127
1128 // quick sanity check
1129 if (!mActiveQuotaIfaces.contains(iface)) {
1130 throw new IllegalStateException("setting alert requires existing quota on iface");
1131 }
1132
1133 synchronized (mQuotaLock) {
1134 if (mActiveAlertIfaces.contains(iface)) {
1135 throw new IllegalStateException("iface " + iface + " already has alert");
1136 }
1137
1138 final StringBuilder command = new StringBuilder();
1139 command.append("bandwidth setinterfacealert ").append(iface).append(" ").append(
1140 alertBytes);
1141
1142 try {
1143 // TODO: support alert shared across interfaces
1144 mConnector.doCommand(command.toString());
1145 mActiveAlertIfaces.add(iface);
1146 } catch (NativeDaemonConnectorException e) {
1147 throw new IllegalStateException("Error communicating to native daemon", e);
1148 }
1149 }
1150 }
1151
1152 @Override
1153 public void removeInterfaceAlert(String iface) {
1154 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1155
1156 // silently discard when control disabled
1157 // TODO: eventually migrate to be always enabled
1158 if (!mBandwidthControlEnabled) return;
1159
1160 synchronized (mQuotaLock) {
1161 if (!mActiveAlertIfaces.contains(iface)) {
1162 // TODO: eventually consider throwing
1163 return;
1164 }
1165
1166 final StringBuilder command = new StringBuilder();
1167 command.append("bandwidth removeinterfacealert ").append(iface);
1168
1169 try {
1170 // TODO: support alert shared across interfaces
1171 mConnector.doCommand(command.toString());
1172 mActiveAlertIfaces.remove(iface);
1173 } catch (NativeDaemonConnectorException e) {
1174 throw new IllegalStateException("Error communicating to native daemon", e);
1175 }
1176 }
1177 }
1178
1179 @Override
1180 public void setGlobalAlert(long alertBytes) {
1181 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1182
1183 // silently discard when control disabled
1184 // TODO: eventually migrate to be always enabled
1185 if (!mBandwidthControlEnabled) return;
1186
1187 final StringBuilder command = new StringBuilder();
1188 command.append("bandwidth setglobalalert ").append(alertBytes);
1189
1190 try {
1191 mConnector.doCommand(command.toString());
1192 } catch (NativeDaemonConnectorException e) {
1193 throw new IllegalStateException("Error communicating to native daemon", e);
1194 }
1195 }
1196
1197 @Override
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001198 public void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces) {
1199 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1200
Jeff Sharkey350083e2011-06-29 10:45:16 -07001201 // silently discard when control disabled
1202 // TODO: eventually migrate to be always enabled
1203 if (!mBandwidthControlEnabled) return;
1204
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001205 synchronized (mUidRejectOnQuota) {
1206 final boolean oldRejectOnQuota = mUidRejectOnQuota.get(uid, false);
1207 if (oldRejectOnQuota == rejectOnQuotaInterfaces) {
1208 // TODO: eventually consider throwing
1209 return;
1210 }
1211
1212 final StringBuilder command = new StringBuilder();
1213 command.append("bandwidth");
1214 if (rejectOnQuotaInterfaces) {
1215 command.append(" addnaughtyapps");
1216 } else {
1217 command.append(" removenaughtyapps");
1218 }
1219 command.append(" ").append(uid);
1220
1221 try {
1222 mConnector.doCommand(command.toString());
1223 if (rejectOnQuotaInterfaces) {
1224 mUidRejectOnQuota.put(uid, true);
1225 } else {
1226 mUidRejectOnQuota.delete(uid);
1227 }
1228 } catch (NativeDaemonConnectorException e) {
1229 throw new IllegalStateException("Error communicating to native daemon", e);
1230 }
Ashish Sharma50fd36d2011-06-15 19:34:53 -07001231 }
1232 }
1233
Jeff Sharkey63d27a92011-08-03 17:04:22 -07001234 @Override
1235 public boolean isBandwidthControlEnabled() {
1236 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1237 return mBandwidthControlEnabled;
1238 }
1239
1240 @Override
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001241 public NetworkStats getNetworkStatsUidDetail(int uid) {
1242 if (Binder.getCallingUid() != uid) {
1243 mContext.enforceCallingOrSelfPermission(
1244 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
1245 }
1246
Jeff Sharkey350083e2011-06-29 10:45:16 -07001247 if (mBandwidthControlEnabled) {
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001248 return getNetworkStatsDetailNetfilter(uid);
1249 } else {
1250 return getNetworkStatsDetailUidstat(uid);
1251 }
1252 }
1253
1254 /**
1255 * Build {@link NetworkStats} with detailed UID statistics.
1256 */
1257 private NetworkStats getNetworkStatsDetailNetfilter(int limitUid) {
1258 final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 24);
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001259 final NetworkStats.Entry entry = new NetworkStats.Entry();
1260
Jeff Sharkeya63ba592011-07-19 23:47:12 -07001261 // TODO: remove knownLines check once 5087722 verified
1262 final HashSet<String> knownLines = Sets.newHashSet();
1263
Jeff Sharkey4414cea2011-06-24 17:05:24 -07001264 final ArrayList<String> keys = Lists.newArrayList();
1265 final ArrayList<String> values = Lists.newArrayList();
1266 final HashMap<String, String> parsed = Maps.newHashMap();
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001267
1268 BufferedReader reader = null;
1269 try {
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001270 reader = new BufferedReader(new FileReader(mStatsXtUid));
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001271
Jeff Sharkey4414cea2011-06-24 17:05:24 -07001272 // parse first line as header
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001273 String line = reader.readLine();
Jeff Sharkey4414cea2011-06-24 17:05:24 -07001274 splitLine(line, keys);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001275
Jeff Sharkey4414cea2011-06-24 17:05:24 -07001276 // parse remaining lines
1277 while ((line = reader.readLine()) != null) {
1278 splitLine(line, values);
1279 parseLine(keys, values, parsed);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001280
Jeff Sharkeya63ba592011-07-19 23:47:12 -07001281 if (!knownLines.add(line)) {
1282 throw new IllegalStateException("encountered duplicate proc entry");
1283 }
1284
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001285 try {
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001286 entry.iface = parsed.get(KEY_IFACE);
Jeff Sharkeya63ba592011-07-19 23:47:12 -07001287 entry.tag = kernelToTag(parsed.get(KEY_TAG_HEX));
1288 entry.uid = getParsedInt(parsed, KEY_UID);
1289 entry.rxBytes = getParsedLong(parsed, KEY_RX_BYTES);
1290 entry.rxPackets = getParsedLong(parsed, KEY_RX_PACKETS);
1291 entry.txBytes = getParsedLong(parsed, KEY_TX_BYTES);
1292 entry.txPackets = getParsedLong(parsed, KEY_TX_PACKETS);
Jeff Sharkeyd03fd3f2011-06-19 20:55:09 -07001293
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001294 if (limitUid == UID_ALL || limitUid == entry.uid) {
1295 stats.addValues(entry);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001296 }
1297 } catch (NumberFormatException e) {
Jeff Sharkey4414cea2011-06-24 17:05:24 -07001298 Slog.w(TAG, "problem parsing stats row '" + line + "': " + e);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001299 }
1300 }
1301 } catch (IOException e) {
1302 Slog.w(TAG, "problem parsing stats: " + e);
1303 } finally {
1304 IoUtils.closeQuietly(reader);
1305 }
1306
Jeff Sharkey4a971222011-06-11 22:16:55 -07001307 return stats;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001308 }
1309
Jeff Sharkeya63ba592011-07-19 23:47:12 -07001310 private static int getParsedInt(HashMap<String, String> parsed, String key) {
1311 final String value = parsed.get(key);
1312 return value != null ? Integer.parseInt(value) : 0;
1313 }
1314
1315 private static long getParsedLong(HashMap<String, String> parsed, String key) {
1316 final String value = parsed.get(key);
1317 return value != null ? Long.parseLong(value) : 0;
1318 }
1319
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001320 /**
1321 * Build {@link NetworkStats} with detailed UID statistics.
1322 *
1323 * @deprecated since this uses older "uid_stat" data, and doesn't provide
1324 * tag-level granularity or additional variables.
1325 */
1326 @Deprecated
1327 private NetworkStats getNetworkStatsDetailUidstat(int limitUid) {
1328 final String[] knownUids;
1329 if (limitUid == UID_ALL) {
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001330 knownUids = fileListWithoutNull(mStatsUid);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001331 } else {
1332 knownUids = new String[] { String.valueOf(limitUid) };
1333 }
1334
1335 final NetworkStats stats = new NetworkStats(
1336 SystemClock.elapsedRealtime(), knownUids.length);
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001337 final NetworkStats.Entry entry = new NetworkStats.Entry();
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001338 for (String uid : knownUids) {
1339 final int uidInt = Integer.parseInt(uid);
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001340 final File uidPath = new File(mStatsUid, uid);
1341
1342 entry.iface = IFACE_ALL;
1343 entry.uid = uidInt;
1344 entry.tag = TAG_NONE;
1345 entry.rxBytes = readSingleLongFromFile(new File(uidPath, "tcp_rcv"));
1346 entry.rxPackets = readSingleLongFromFile(new File(uidPath, "tcp_rcv_pkt"));
1347 entry.txBytes = readSingleLongFromFile(new File(uidPath, "tcp_snd"));
1348 entry.txPackets = readSingleLongFromFile(new File(uidPath, "tcp_snd_pkt"));
1349
1350 stats.addValues(entry);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001351 }
1352
1353 return stats;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001354 }
1355
San Mehatf0db6e12010-04-07 15:22:10 -07001356 public void setInterfaceThrottle(String iface, int rxKbps, int txKbps) {
San Mehat91cac642010-03-31 14:31:36 -07001357 mContext.enforceCallingOrSelfPermission(
1358 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -07001359 try {
1360 mConnector.doCommand(String.format(
1361 "interface setthrottle %s %d %d", iface, rxKbps, txKbps));
1362 } catch (NativeDaemonConnectorException e) {
1363 Slog.e(TAG, "Error communicating with native daemon to set throttle", e);
1364 }
San Mehat91cac642010-03-31 14:31:36 -07001365 }
1366
1367 private int getInterfaceThrottle(String iface, boolean rx) {
1368 mContext.enforceCallingOrSelfPermission(
1369 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
1370 try {
Kenny Roota80ce062010-06-01 13:23:53 -07001371 String rsp;
1372 try {
1373 rsp = mConnector.doCommand(
1374 String.format("interface getthrottle %s %s", iface,
1375 (rx ? "rx" : "tx"))).get(0);
1376 } catch (NativeDaemonConnectorException e) {
1377 Slog.e(TAG, "Error communicating with native daemon to getthrottle", e);
1378 return -1;
1379 }
1380
1381 String[] tok = rsp.split(" ");
1382 if (tok.length < 2) {
1383 Slog.e(TAG, "Malformed response to getthrottle command");
1384 return -1;
1385 }
1386
San Mehat91cac642010-03-31 14:31:36 -07001387 int code;
1388 try {
1389 code = Integer.parseInt(tok[0]);
1390 } catch (NumberFormatException nfe) {
1391 Slog.e(TAG, String.format("Error parsing code %s", tok[0]));
1392 return -1;
1393 }
1394 if ((rx && code != NetdResponseCode.InterfaceRxThrottleResult) || (
1395 !rx && code != NetdResponseCode.InterfaceTxThrottleResult)) {
1396 Slog.e(TAG, String.format("Unexpected response code %d", code));
1397 return -1;
1398 }
1399 return Integer.parseInt(tok[1]);
1400 } catch (Exception e) {
1401 Slog.e(TAG, String.format(
1402 "Failed to read interface %s throttle value", (rx ? "rx" : "tx")), e);
1403 }
1404 return -1;
1405 }
1406
1407 public int getInterfaceRxThrottle(String iface) {
1408 return getInterfaceThrottle(iface, true);
1409 }
1410
1411 public int getInterfaceTxThrottle(String iface) {
1412 return getInterfaceThrottle(iface, false);
1413 }
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001414
1415 /**
Jeff Sharkey4414cea2011-06-24 17:05:24 -07001416 * Split given line into {@link ArrayList}.
1417 */
1418 private static void splitLine(String line, ArrayList<String> outSplit) {
1419 outSplit.clear();
1420
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001421 final StringTokenizer t = new StringTokenizer(line, " \t\n\r\f:");
Jeff Sharkey4414cea2011-06-24 17:05:24 -07001422 while (t.hasMoreTokens()) {
1423 outSplit.add(t.nextToken());
1424 }
1425 }
1426
1427 /**
1428 * Zip the two given {@link ArrayList} as key and value pairs into
1429 * {@link HashMap}.
1430 */
1431 private static void parseLine(
1432 ArrayList<String> keys, ArrayList<String> values, HashMap<String, String> outParsed) {
1433 outParsed.clear();
1434
1435 final int size = Math.min(keys.size(), values.size());
1436 for (int i = 0; i < size; i++) {
1437 outParsed.put(keys.get(i), values.get(i));
1438 }
1439 }
1440
1441 /**
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001442 * Utility method to read a single plain-text {@link Long} from the given
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001443 * {@link File}, usually from a {@code /proc/} filesystem.
1444 */
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001445 private static long readSingleLongFromFile(File file) {
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001446 try {
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001447 final byte[] buffer = IoUtils.readFileAsByteArray(file.toString());
1448 return Long.parseLong(new String(buffer).trim());
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001449 } catch (NumberFormatException e) {
1450 return -1;
1451 } catch (IOException e) {
1452 return -1;
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001453 }
1454 }
Jean-Baptiste Querud5299ff2011-07-07 08:46:09 -07001455
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001456 /**
1457 * Wrapper for {@link File#list()} that returns empty array instead of
1458 * {@code null}.
1459 */
1460 private static String[] fileListWithoutNull(File file) {
1461 final String[] list = file.list();
1462 return list != null ? list : new String[0];
1463 }
1464
Mattias Falk7475c0c2011-04-04 16:10:36 +02001465 public void setDefaultInterfaceForDns(String iface) throws IllegalStateException {
1466 mContext.enforceCallingOrSelfPermission(
1467 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
1468 try {
1469 String cmd = "resolver setdefaultif " + iface;
1470
1471 mConnector.doCommand(cmd);
1472 } catch (NativeDaemonConnectorException e) {
1473 throw new IllegalStateException(
1474 "Error communicating with native daemon to set default interface", e);
1475 }
1476 }
1477
1478 public void setDnsServersForInterface(String iface, String[] servers)
1479 throws IllegalStateException {
1480 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_NETWORK_STATE,
1481 "NetworkManagementService");
1482 try {
1483 String cmd = "resolver setifdns " + iface;
1484 for (String s : servers) {
Robert Greenwalt572b7042011-07-25 17:00:13 -07001485 InetAddress a = NetworkUtils.numericToInetAddress(s);
1486 if (a.isAnyLocalAddress() == false) {
1487 cmd += " " + a.getHostAddress();
Mattias Falk7475c0c2011-04-04 16:10:36 +02001488 }
1489 }
Mattias Falk7475c0c2011-04-04 16:10:36 +02001490 mConnector.doCommand(cmd);
Robert Greenwalt572b7042011-07-25 17:00:13 -07001491 } catch (IllegalArgumentException e) {
1492 throw new IllegalStateException("Error setting dnsn for interface", e);
Mattias Falk7475c0c2011-04-04 16:10:36 +02001493 } catch (NativeDaemonConnectorException e) {
1494 throw new IllegalStateException(
Robert Greenwalt572b7042011-07-25 17:00:13 -07001495 "Error communicating with native daemon to set dns for interface", e);
Mattias Falk7475c0c2011-04-04 16:10:36 +02001496 }
1497 }
1498
1499 public void flushDefaultDnsCache() throws IllegalStateException {
1500 mContext.enforceCallingOrSelfPermission(
1501 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
1502 try {
1503 String cmd = "resolver flushdefaultif";
1504
1505 mConnector.doCommand(cmd);
1506 } catch (NativeDaemonConnectorException e) {
1507 throw new IllegalStateException(
1508 "Error communicating with native deamon to flush default interface", e);
1509 }
1510 }
1511
1512 public void flushInterfaceDnsCache(String iface) throws IllegalStateException {
1513 mContext.enforceCallingOrSelfPermission(
1514 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
1515 try {
1516 String cmd = "resolver flushif " + iface;
1517
1518 mConnector.doCommand(cmd);
1519 } catch (NativeDaemonConnectorException e) {
1520 throw new IllegalStateException(
Robert Greenwalt572b7042011-07-25 17:00:13 -07001521 "Error communicating with native daemon to flush interface " + iface, e);
Mattias Falk7475c0c2011-04-04 16:10:36 +02001522 }
1523 }
San Mehat873f2142010-01-14 10:25:07 -08001524}