blob: a854db00b83d9ff39cf9b58e5ae3d2b351f79ac6 [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;
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -070021import static android.net.NetworkStats.SET_DEFAULT;
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -070022import static android.net.NetworkStats.TAG_NONE;
23import static android.net.NetworkStats.UID_ALL;
Jeff Sharkey350083e2011-06-29 10:45:16 -070024import static android.provider.Settings.Secure.NETSTATS_ENABLED;
Jeff Sharkeya63ba592011-07-19 23:47:12 -070025import static com.android.server.NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED;
26import static com.android.server.NetworkManagementSocketTagger.kernelToTag;
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -070027
San Mehat873f2142010-01-14 10:25:07 -080028import android.content.Context;
San Mehat873f2142010-01-14 10:25:07 -080029import android.content.pm.PackageManager;
San Mehat4d02d002010-01-22 16:07:46 -080030import android.net.INetworkManagementEventObserver;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070031import android.net.InterfaceConfiguration;
Robert Greenwalted126402011-01-28 15:34:55 -080032import android.net.LinkAddress;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070033import android.net.NetworkStats;
Robert Greenwalted126402011-01-28 15:34:55 -080034import android.net.NetworkUtils;
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -070035import android.net.RouteInfo;
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -080036import android.net.wifi.WifiConfiguration;
37import android.net.wifi.WifiConfiguration.KeyMgmt;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070038import android.os.Binder;
San Mehat873f2142010-01-14 10:25:07 -080039import android.os.INetworkManagementService;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070040import android.os.SystemClock;
Marco Nelissen62dbb222010-02-18 10:56:30 -080041import android.os.SystemProperties;
Jeff Sharkey350083e2011-06-29 10:45:16 -070042import android.provider.Settings;
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -080043import android.util.Log;
Joe Onorato8a9b2202010-02-26 18:56:32 -080044import android.util.Slog;
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -070045import android.util.SparseBooleanArray;
San Mehat873f2142010-01-14 10:25:07 -080046
Jeff Sharkey4414cea2011-06-24 17:05:24 -070047import com.google.android.collect.Lists;
48import com.google.android.collect.Maps;
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -070049import com.google.android.collect.Sets;
Jeff Sharkey4414cea2011-06-24 17:05:24 -070050
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -070051import java.io.BufferedReader;
52import java.io.DataInputStream;
San Mehat873f2142010-01-14 10:25:07 -080053import java.io.File;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070054import java.io.FileInputStream;
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -070055import java.io.FileReader;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070056import java.io.IOException;
Jeff Sharkey9a13f362011-04-26 16:25:36 -070057import java.io.InputStreamReader;
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -070058import java.net.Inet4Address;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070059import java.net.InetAddress;
60import java.util.ArrayList;
Jeff Sharkey4414cea2011-06-24 17:05:24 -070061import java.util.HashMap;
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -070062import java.util.HashSet;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070063import java.util.NoSuchElementException;
64import java.util.StringTokenizer;
Robert Greenwalte5c3afb2010-09-22 14:32:35 -070065import java.util.concurrent.CountDownLatch;
San Mehat873f2142010-01-14 10:25:07 -080066
Jeff Sharkey9a13f362011-04-26 16:25:36 -070067import libcore.io.IoUtils;
68
San Mehat873f2142010-01-14 10:25:07 -080069/**
70 * @hide
71 */
72class NetworkManagementService extends INetworkManagementService.Stub {
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070073 private static final String TAG = "NetworkManagementService";
Dianne Hackborncef65ee2010-09-30 18:27:22 -070074 private static final boolean DBG = false;
Kenny Root305bcbf2010-09-03 07:56:38 -070075 private static final String NETD_TAG = "NetdConnector";
76
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -070077 private static final int ADD = 1;
78 private static final int REMOVE = 2;
79
Jeff Sharkey4414cea2011-06-24 17:05:24 -070080 /** Path to {@code /proc/uid_stat}. */
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -070081 @Deprecated
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -070082 private final File mStatsUid;
83 /** Path to {@code /proc/net/dev}. */
84 private final File mStatsIface;
Jeff Sharkey4414cea2011-06-24 17:05:24 -070085 /** Path to {@code /proc/net/xt_qtaguid/stats}. */
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -070086 private final File mStatsXtUid;
87 /** Path to {@code /proc/net/xt_qtaguid/iface_stat}. */
88 private final File mStatsXtIface;
Jeff Sharkey4414cea2011-06-24 17:05:24 -070089
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -070090 /** {@link #mStatsXtUid} headers. */
Jeff Sharkey4414cea2011-06-24 17:05:24 -070091 private static final String KEY_IFACE = "iface";
Jeff Sharkey4414cea2011-06-24 17:05:24 -070092 private static final String KEY_UID = "uid_tag_int";
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -070093 private static final String KEY_COUNTER_SET = "cnt_set";
94 private static final String KEY_TAG_HEX = "acct_tag_hex";
Jeff Sharkeya63ba592011-07-19 23:47:12 -070095 private static final String KEY_RX_BYTES = "rx_bytes";
96 private static final String KEY_RX_PACKETS = "rx_packets";
97 private static final String KEY_TX_BYTES = "tx_bytes";
98 private static final String KEY_TX_PACKETS = "tx_packets";
Jeff Sharkeyeedcb952011-05-17 14:55:15 -070099
San Mehat873f2142010-01-14 10:25:07 -0800100 class NetdResponseCode {
JP Abgrall12b933d2011-07-14 18:09:22 -0700101 /* Keep in sync with system/netd/ResponseCode.h */
San Mehat873f2142010-01-14 10:25:07 -0800102 public static final int InterfaceListResult = 110;
103 public static final int TetherInterfaceListResult = 111;
104 public static final int TetherDnsFwdTgtListResult = 112;
San Mehat72759df2010-01-19 13:50:37 -0800105 public static final int TtyListResult = 113;
San Mehat873f2142010-01-14 10:25:07 -0800106
107 public static final int TetherStatusResult = 210;
108 public static final int IpFwdStatusResult = 211;
San Mehated4fc8a2010-01-22 12:28:36 -0800109 public static final int InterfaceGetCfgResult = 213;
Robert Greenwalte3253922010-02-18 09:23:25 -0800110 public static final int SoftapStatusResult = 214;
San Mehat91cac642010-03-31 14:31:36 -0700111 public static final int InterfaceRxCounterResult = 216;
112 public static final int InterfaceTxCounterResult = 217;
113 public static final int InterfaceRxThrottleResult = 218;
114 public static final int InterfaceTxThrottleResult = 219;
Robert Greenwalte3253922010-02-18 09:23:25 -0800115
116 public static final int InterfaceChange = 600;
JP Abgrall12b933d2011-07-14 18:09:22 -0700117 public static final int BandwidthControl = 601;
San Mehat873f2142010-01-14 10:25:07 -0800118 }
119
120 /**
121 * Binder context for this service
122 */
123 private Context mContext;
124
125 /**
126 * connector object for communicating with netd
127 */
128 private NativeDaemonConnector mConnector;
129
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700130 private Thread mThread;
131 private final CountDownLatch mConnectedSignal = new CountDownLatch(1);
132
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -0700133 // TODO: replace with RemoteCallbackList
San Mehat4d02d002010-01-22 16:07:46 -0800134 private ArrayList<INetworkManagementEventObserver> mObservers;
135
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -0700136 private Object mQuotaLock = new Object();
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -0700137 /** Set of interfaces with active quotas. */
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -0700138 private HashSet<String> mActiveQuotaIfaces = Sets.newHashSet();
139 /** Set of interfaces with active alerts. */
140 private HashSet<String> mActiveAlertIfaces = Sets.newHashSet();
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -0700141 /** Set of UIDs with active reject rules. */
142 private SparseBooleanArray mUidRejectOnQuota = new SparseBooleanArray();
143
Jeff Sharkey350083e2011-06-29 10:45:16 -0700144 private boolean mBandwidthControlEnabled;
145
San Mehat873f2142010-01-14 10:25:07 -0800146 /**
147 * Constructs a new NetworkManagementService instance
148 *
149 * @param context Binder context for this service
150 */
Jeff Sharkey4414cea2011-06-24 17:05:24 -0700151 private NetworkManagementService(Context context, File procRoot) {
San Mehat873f2142010-01-14 10:25:07 -0800152 mContext = context;
San Mehat4d02d002010-01-22 16:07:46 -0800153 mObservers = new ArrayList<INetworkManagementEventObserver>();
154
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700155 mStatsUid = new File(procRoot, "uid_stat");
156 mStatsIface = new File(procRoot, "net/dev");
157 mStatsXtUid = new File(procRoot, "net/xt_qtaguid/stats");
158 mStatsXtIface = new File(procRoot, "net/xt_qtaguid/iface_stat");
Jeff Sharkey4414cea2011-06-24 17:05:24 -0700159
Marco Nelissen62dbb222010-02-18 10:56:30 -0800160 if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
161 return;
162 }
163
San Mehat873f2142010-01-14 10:25:07 -0800164 mConnector = new NativeDaemonConnector(
Kenny Root305bcbf2010-09-03 07:56:38 -0700165 new NetdCallbackReceiver(), "netd", 10, NETD_TAG);
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700166 mThread = new Thread(mConnector, NETD_TAG);
167 }
168
169 public static NetworkManagementService create(Context context) throws InterruptedException {
Jeff Sharkey4414cea2011-06-24 17:05:24 -0700170 NetworkManagementService service = new NetworkManagementService(
171 context, new File("/proc/"));
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700172 if (DBG) Slog.d(TAG, "Creating NetworkManagementService");
173 service.mThread.start();
174 if (DBG) Slog.d(TAG, "Awaiting socket connection");
175 service.mConnectedSignal.await();
176 if (DBG) Slog.d(TAG, "Connected");
177 return service;
San Mehat873f2142010-01-14 10:25:07 -0800178 }
179
Jeff Sharkey4414cea2011-06-24 17:05:24 -0700180 // @VisibleForTesting
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700181 public static NetworkManagementService createForTest(
182 Context context, File procRoot, boolean bandwidthControlEnabled) {
Jeff Sharkey4414cea2011-06-24 17:05:24 -0700183 // TODO: eventually connect with mock netd
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -0700184 final NetworkManagementService service = new NetworkManagementService(context, procRoot);
185 service.mBandwidthControlEnabled = bandwidthControlEnabled;
186 return service;
Jeff Sharkey4414cea2011-06-24 17:05:24 -0700187 }
188
Jeff Sharkey350083e2011-06-29 10:45:16 -0700189 public void systemReady() {
190
191 // only enable bandwidth control when support exists, and requested by
192 // system setting.
Jeff Sharkey350083e2011-06-29 10:45:16 -0700193 final boolean hasKernelSupport = new File("/proc/net/xt_qtaguid/ctrl").exists();
194 final boolean shouldEnable =
Jeff Sharkey05355c32011-08-09 14:44:19 -0700195 Settings.Secure.getInt(mContext.getContentResolver(), NETSTATS_ENABLED, 1) != 0;
Jeff Sharkey350083e2011-06-29 10:45:16 -0700196
197 mBandwidthControlEnabled = false;
198 if (hasKernelSupport && shouldEnable) {
199 Slog.d(TAG, "enabling bandwidth control");
200 try {
201 mConnector.doCommand("bandwidth enable");
202 mBandwidthControlEnabled = true;
203 } catch (NativeDaemonConnectorException e) {
204 Slog.e(TAG, "problem enabling bandwidth controls", e);
205 }
206 } else {
207 Slog.d(TAG, "not enabling bandwidth control");
208 }
Jeff Sharkey62a2c8f2011-07-13 15:24:02 -0700209
Jeff Sharkeya63ba592011-07-19 23:47:12 -0700210 SystemProperties.set(PROP_QTAGUID_ENABLED, mBandwidthControlEnabled ? "1" : "0");
Jeff Sharkey350083e2011-06-29 10:45:16 -0700211 }
212
San Mehat4d02d002010-01-22 16:07:46 -0800213 public void registerObserver(INetworkManagementEventObserver obs) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800214 Slog.d(TAG, "Registering observer");
San Mehat4d02d002010-01-22 16:07:46 -0800215 mObservers.add(obs);
216 }
217
218 public void unregisterObserver(INetworkManagementEventObserver obs) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800219 Slog.d(TAG, "Unregistering observer");
San Mehat4d02d002010-01-22 16:07:46 -0800220 mObservers.remove(mObservers.indexOf(obs));
221 }
222
223 /**
Mike J. Chen6143f5f2011-06-23 15:17:51 -0700224 * Notify our observers of an interface status change
San Mehat4d02d002010-01-22 16:07:46 -0800225 */
Mike J. Chen6143f5f2011-06-23 15:17:51 -0700226 private void notifyInterfaceStatusChanged(String iface, boolean up) {
San Mehat4d02d002010-01-22 16:07:46 -0800227 for (INetworkManagementEventObserver obs : mObservers) {
228 try {
Mike J. Chen6143f5f2011-06-23 15:17:51 -0700229 obs.interfaceStatusChanged(iface, up);
230 } catch (Exception ex) {
231 Slog.w(TAG, "Observer notifier failed", ex);
232 }
233 }
234 }
235
236 /**
Mike J. Chenf59c7d02011-06-23 15:33:15 -0700237 * Notify our observers of an interface link state change
Mike J. Chen6143f5f2011-06-23 15:17:51 -0700238 * (typically, an Ethernet cable has been plugged-in or unplugged).
239 */
240 private void notifyInterfaceLinkStateChanged(String iface, boolean up) {
241 for (INetworkManagementEventObserver obs : mObservers) {
242 try {
243 obs.interfaceLinkStateChanged(iface, up);
San Mehat4d02d002010-01-22 16:07:46 -0800244 } catch (Exception ex) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800245 Slog.w(TAG, "Observer notifier failed", ex);
San Mehat4d02d002010-01-22 16:07:46 -0800246 }
247 }
248 }
249
250 /**
251 * Notify our observers of an interface addition.
252 */
253 private void notifyInterfaceAdded(String iface) {
254 for (INetworkManagementEventObserver obs : mObservers) {
255 try {
256 obs.interfaceAdded(iface);
257 } catch (Exception ex) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800258 Slog.w(TAG, "Observer notifier failed", ex);
San Mehat4d02d002010-01-22 16:07:46 -0800259 }
260 }
261 }
262
263 /**
264 * Notify our observers of an interface removal.
265 */
266 private void notifyInterfaceRemoved(String iface) {
267 for (INetworkManagementEventObserver obs : mObservers) {
268 try {
269 obs.interfaceRemoved(iface);
270 } catch (Exception ex) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800271 Slog.w(TAG, "Observer notifier failed", ex);
San Mehat4d02d002010-01-22 16:07:46 -0800272 }
273 }
274 }
275
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700276 /**
JP Abgrall12b933d2011-07-14 18:09:22 -0700277 * Notify our observers of a limit reached.
278 */
279 private void notifyLimitReached(String limitName, String iface) {
280 for (INetworkManagementEventObserver obs : mObservers) {
281 try {
282 obs.limitReached(limitName, iface);
283 Slog.d(TAG, "Observer notified limit reached for " + limitName + " " + iface);
284 } catch (Exception ex) {
285 Slog.w(TAG, "Observer notifier failed", ex);
286 }
287 }
288 }
289
290 /**
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700291 * Let us know the daemon is connected
292 */
293 protected void onConnected() {
294 if (DBG) Slog.d(TAG, "onConnected");
295 mConnectedSignal.countDown();
296 }
297
San Mehat4d02d002010-01-22 16:07:46 -0800298
San Mehat873f2142010-01-14 10:25:07 -0800299 //
300 // Netd Callback handling
301 //
302
303 class NetdCallbackReceiver implements INativeDaemonConnectorCallbacks {
304 public void onDaemonConnected() {
Robert Greenwalte5c3afb2010-09-22 14:32:35 -0700305 NetworkManagementService.this.onConnected();
San Mehat873f2142010-01-14 10:25:07 -0800306 new Thread() {
307 public void run() {
San Mehat873f2142010-01-14 10:25:07 -0800308 }
309 }.start();
310 }
311 public boolean onEvent(int code, String raw, String[] cooked) {
JP Abgrall12b933d2011-07-14 18:09:22 -0700312 switch (code) {
313 case NetdResponseCode.InterfaceChange:
314 /*
315 * a network interface change occured
316 * Format: "NNN Iface added <name>"
317 * "NNN Iface removed <name>"
318 * "NNN Iface changed <name> <up/down>"
319 * "NNN Iface linkstatus <name> <up/down>"
320 */
321 if (cooked.length < 4 || !cooked[1].equals("Iface")) {
322 throw new IllegalStateException(
323 String.format("Invalid event from daemon (%s)", raw));
324 }
325 if (cooked[2].equals("added")) {
326 notifyInterfaceAdded(cooked[3]);
327 return true;
328 } else if (cooked[2].equals("removed")) {
329 notifyInterfaceRemoved(cooked[3]);
330 return true;
331 } else if (cooked[2].equals("changed") && cooked.length == 5) {
332 notifyInterfaceStatusChanged(cooked[3], cooked[4].equals("up"));
333 return true;
334 } else if (cooked[2].equals("linkstate") && cooked.length == 5) {
335 notifyInterfaceLinkStateChanged(cooked[3], cooked[4].equals("up"));
336 return true;
337 }
Robert Greenwalte3253922010-02-18 09:23:25 -0800338 throw new IllegalStateException(
339 String.format("Invalid event from daemon (%s)", raw));
JP Abgrall12b933d2011-07-14 18:09:22 -0700340 // break;
341 case NetdResponseCode.BandwidthControl:
342 /*
343 * Bandwidth control needs some attention
344 * Format: "NNN limit alert <alertName> <ifaceName>"
345 */
346 if (cooked.length < 5 || !cooked[1].equals("limit")) {
347 throw new IllegalStateException(
348 String.format("Invalid event from daemon (%s)", raw));
349 }
350 if (cooked[2].equals("alert")) {
351 notifyLimitReached(cooked[3], cooked[4]);
352 return true;
353 }
354 throw new IllegalStateException(
355 String.format("Invalid event from daemon (%s)", raw));
356 // break;
357 default: break;
Robert Greenwalte3253922010-02-18 09:23:25 -0800358 }
359 return false;
San Mehat873f2142010-01-14 10:25:07 -0800360 }
361 }
362
San Mehated4fc8a2010-01-22 12:28:36 -0800363
San Mehat873f2142010-01-14 10:25:07 -0800364 //
365 // INetworkManagementService members
366 //
367
368 public String[] listInterfaces() throws IllegalStateException {
369 mContext.enforceCallingOrSelfPermission(
370 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
371
Kenny Roota80ce062010-06-01 13:23:53 -0700372 try {
373 return mConnector.doListCommand("interface list", NetdResponseCode.InterfaceListResult);
374 } catch (NativeDaemonConnectorException e) {
375 throw new IllegalStateException(
376 "Cannot communicate with native daemon to list interfaces");
377 }
San Mehated4fc8a2010-01-22 12:28:36 -0800378 }
379
380 public InterfaceConfiguration getInterfaceConfig(String iface) throws IllegalStateException {
Kenny Roota80ce062010-06-01 13:23:53 -0700381 String rsp;
382 try {
383 rsp = mConnector.doCommand("interface getcfg " + iface).get(0);
384 } catch (NativeDaemonConnectorException e) {
385 throw new IllegalStateException(
386 "Cannot communicate with native daemon to get interface config");
387 }
Joe Onorato8a9b2202010-02-26 18:56:32 -0800388 Slog.d(TAG, String.format("rsp <%s>", rsp));
San Mehated4fc8a2010-01-22 12:28:36 -0800389
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800390 // Rsp: 213 xx:xx:xx:xx:xx:xx yyy.yyy.yyy.yyy zzz [flag1 flag2 flag3]
San Mehated4fc8a2010-01-22 12:28:36 -0800391 StringTokenizer st = new StringTokenizer(rsp);
392
Kenny Roota80ce062010-06-01 13:23:53 -0700393 InterfaceConfiguration cfg;
San Mehated4fc8a2010-01-22 12:28:36 -0800394 try {
Kenny Roota80ce062010-06-01 13:23:53 -0700395 try {
396 int code = Integer.parseInt(st.nextToken(" "));
397 if (code != NetdResponseCode.InterfaceGetCfgResult) {
398 throw new IllegalStateException(
399 String.format("Expected code %d, but got %d",
400 NetdResponseCode.InterfaceGetCfgResult, code));
401 }
402 } catch (NumberFormatException nfe) {
San Mehated4fc8a2010-01-22 12:28:36 -0800403 throw new IllegalStateException(
Kenny Roota80ce062010-06-01 13:23:53 -0700404 String.format("Invalid response from daemon (%s)", rsp));
San Mehated4fc8a2010-01-22 12:28:36 -0800405 }
Kenny Roota80ce062010-06-01 13:23:53 -0700406
407 cfg = new InterfaceConfiguration();
408 cfg.hwAddr = st.nextToken(" ");
Robert Greenwalted126402011-01-28 15:34:55 -0800409 InetAddress addr = null;
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800410 int prefixLength = 0;
Kenny Roota80ce062010-06-01 13:23:53 -0700411 try {
Robert Greenwalte5903732011-02-22 16:00:42 -0800412 addr = NetworkUtils.numericToInetAddress(st.nextToken(" "));
413 } catch (IllegalArgumentException iae) {
414 Slog.e(TAG, "Failed to parse ipaddr", iae);
Kenny Roota80ce062010-06-01 13:23:53 -0700415 }
416
417 try {
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800418 prefixLength = Integer.parseInt(st.nextToken(" "));
419 } catch (NumberFormatException nfe) {
420 Slog.e(TAG, "Failed to parse prefixLength", nfe);
Kenny Roota80ce062010-06-01 13:23:53 -0700421 }
Robert Greenwalt04808c22010-12-13 17:01:41 -0800422
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800423 cfg.addr = new LinkAddress(addr, prefixLength);
Kenny Roota80ce062010-06-01 13:23:53 -0700424 cfg.interfaceFlags = st.nextToken("]").trim() +"]";
425 } catch (NoSuchElementException nsee) {
San Mehated4fc8a2010-01-22 12:28:36 -0800426 throw new IllegalStateException(
427 String.format("Invalid response from daemon (%s)", rsp));
428 }
Joe Onorato8a9b2202010-02-26 18:56:32 -0800429 Slog.d(TAG, String.format("flags <%s>", cfg.interfaceFlags));
San Mehated4fc8a2010-01-22 12:28:36 -0800430 return cfg;
431 }
432
433 public void setInterfaceConfig(
434 String iface, InterfaceConfiguration cfg) throws IllegalStateException {
Robert Greenwalted126402011-01-28 15:34:55 -0800435 LinkAddress linkAddr = cfg.addr;
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800436 if (linkAddr == null || linkAddr.getAddress() == null) {
437 throw new IllegalStateException("Null LinkAddress given");
Robert Greenwalted126402011-01-28 15:34:55 -0800438 }
Robert Greenwalt2d2afd12011-02-01 15:30:46 -0800439 String cmd = String.format("interface setcfg %s %s %d %s", iface,
440 linkAddr.getAddress().getHostAddress(),
441 linkAddr.getNetworkPrefixLength(),
442 cfg.interfaceFlags);
Kenny Roota80ce062010-06-01 13:23:53 -0700443 try {
444 mConnector.doCommand(cmd);
445 } catch (NativeDaemonConnectorException e) {
446 throw new IllegalStateException(
Robert Greenwalt81d5ad52010-12-16 11:27:38 -0800447 "Unable to communicate with native daemon to interface setcfg - " + e);
Kenny Roota80ce062010-06-01 13:23:53 -0700448 }
San Mehat873f2142010-01-14 10:25:07 -0800449 }
450
Irfan Sheriff7244c972011-08-05 20:40:45 -0700451 public void setInterfaceDown(String iface) throws IllegalStateException {
452 try {
453 InterfaceConfiguration ifcg = getInterfaceConfig(iface);
454 ifcg.interfaceFlags = ifcg.interfaceFlags.replace("up", "down");
455 setInterfaceConfig(iface, ifcg);
456 } catch (NativeDaemonConnectorException e) {
457 throw new IllegalStateException(
458 "Unable to communicate with native daemon for interface down - " + e);
459 }
460 }
461
462 public void setInterfaceUp(String iface) throws IllegalStateException {
463 try {
464 InterfaceConfiguration ifcg = getInterfaceConfig(iface);
465 ifcg.interfaceFlags = ifcg.interfaceFlags.replace("down", "up");
466 setInterfaceConfig(iface, ifcg);
467 } catch (NativeDaemonConnectorException e) {
468 throw new IllegalStateException(
469 "Unable to communicate with native daemon for interface up - " + e);
470 }
471 }
472
Irfan Sherifff5600612011-06-16 10:26:28 -0700473 /* TODO: This is right now a IPv4 only function. Works for wifi which loses its
474 IPv6 addresses on interface down, but we need to do full clean up here */
475 public void clearInterfaceAddresses(String iface) throws IllegalStateException {
476 String cmd = String.format("interface clearaddrs %s", iface);
477 try {
478 mConnector.doCommand(cmd);
479 } catch (NativeDaemonConnectorException e) {
480 throw new IllegalStateException(
481 "Unable to communicate with native daemon to interface clearallips - " + e);
482 }
483 }
484
Robert Greenwalt59b1a4e2011-05-10 15:05:02 -0700485 public void addRoute(String interfaceName, RouteInfo route) {
486 modifyRoute(interfaceName, ADD, route);
487 }
488
489 public void removeRoute(String interfaceName, RouteInfo route) {
490 modifyRoute(interfaceName, REMOVE, route);
491 }
492
493 private void modifyRoute(String interfaceName, int action, RouteInfo route) {
494 ArrayList<String> rsp;
495
496 StringBuilder cmd;
497
498 switch (action) {
499 case ADD:
500 {
501 cmd = new StringBuilder("interface route add " + interfaceName);
502 break;
503 }
504 case REMOVE:
505 {
506 cmd = new StringBuilder("interface route remove " + interfaceName);
507 break;
508 }
509 default:
510 throw new IllegalStateException("Unknown action type " + action);
511 }
512
513 // create triplet: dest-ip-addr prefixlength gateway-ip-addr
514 LinkAddress la = route.getDestination();
515 cmd.append(' ');
516 cmd.append(la.getAddress().getHostAddress());
517 cmd.append(' ');
518 cmd.append(la.getNetworkPrefixLength());
519 cmd.append(' ');
520 if (route.getGateway() == null) {
521 if (la.getAddress() instanceof Inet4Address) {
522 cmd.append("0.0.0.0");
523 } else {
524 cmd.append ("::0");
525 }
526 } else {
527 cmd.append(route.getGateway().getHostAddress());
528 }
529 try {
530 rsp = mConnector.doCommand(cmd.toString());
531 } catch (NativeDaemonConnectorException e) {
532 throw new IllegalStateException(
533 "Unable to communicate with native dameon to add routes - "
534 + e);
535 }
536
537 for (String line : rsp) {
538 Log.v(TAG, "add route response is " + line);
539 }
540 }
541
542 private ArrayList<String> readRouteList(String filename) {
543 FileInputStream fstream = null;
544 ArrayList<String> list = new ArrayList<String>();
545
546 try {
547 fstream = new FileInputStream(filename);
548 DataInputStream in = new DataInputStream(fstream);
549 BufferedReader br = new BufferedReader(new InputStreamReader(in));
550 String s;
551
552 // throw away the title line
553
554 while (((s = br.readLine()) != null) && (s.length() != 0)) {
555 list.add(s);
556 }
557 } catch (IOException ex) {
558 // return current list, possibly empty
559 } finally {
560 if (fstream != null) {
561 try {
562 fstream.close();
563 } catch (IOException ex) {}
564 }
565 }
566
567 return list;
568 }
569
570 public RouteInfo[] getRoutes(String interfaceName) {
571 ArrayList<RouteInfo> routes = new ArrayList<RouteInfo>();
572
573 // v4 routes listed as:
574 // iface dest-addr gateway-addr flags refcnt use metric netmask mtu window IRTT
575 for (String s : readRouteList("/proc/net/route")) {
576 String[] fields = s.split("\t");
577
578 if (fields.length > 7) {
579 String iface = fields[0];
580
581 if (interfaceName.equals(iface)) {
582 String dest = fields[1];
583 String gate = fields[2];
584 String flags = fields[3]; // future use?
585 String mask = fields[7];
586 try {
587 // address stored as a hex string, ex: 0014A8C0
588 InetAddress destAddr =
589 NetworkUtils.intToInetAddress((int)Long.parseLong(dest, 16));
590 int prefixLength =
591 NetworkUtils.netmaskIntToPrefixLength(
592 (int)Long.parseLong(mask, 16));
593 LinkAddress linkAddress = new LinkAddress(destAddr, prefixLength);
594
595 // address stored as a hex string, ex 0014A8C0
596 InetAddress gatewayAddr =
597 NetworkUtils.intToInetAddress((int)Long.parseLong(gate, 16));
598
599 RouteInfo route = new RouteInfo(linkAddress, gatewayAddr);
600 routes.add(route);
601 } catch (Exception e) {
602 Log.e(TAG, "Error parsing route " + s + " : " + e);
603 continue;
604 }
605 }
606 }
607 }
608
609 // v6 routes listed as:
610 // dest-addr prefixlength ?? ?? gateway-addr ?? ?? ?? ?? iface
611 for (String s : readRouteList("/proc/net/ipv6_route")) {
612 String[]fields = s.split("\\s+");
613 if (fields.length > 9) {
614 String iface = fields[9].trim();
615 if (interfaceName.equals(iface)) {
616 String dest = fields[0];
617 String prefix = fields[1];
618 String gate = fields[4];
619
620 try {
621 // prefix length stored as a hex string, ex 40
622 int prefixLength = Integer.parseInt(prefix, 16);
623
624 // address stored as a 32 char hex string
625 // ex fe800000000000000000000000000000
626 InetAddress destAddr = NetworkUtils.hexToInet6Address(dest);
627 LinkAddress linkAddress = new LinkAddress(destAddr, prefixLength);
628
629 InetAddress gateAddr = NetworkUtils.hexToInet6Address(gate);
630
631 RouteInfo route = new RouteInfo(linkAddress, gateAddr);
632 routes.add(route);
633 } catch (Exception e) {
634 Log.e(TAG, "Error parsing route " + s + " : " + e);
635 continue;
636 }
637 }
638 }
639 }
640 return (RouteInfo[]) routes.toArray(new RouteInfo[0]);
641 }
642
San Mehat873f2142010-01-14 10:25:07 -0800643 public void shutdown() {
644 if (mContext.checkCallingOrSelfPermission(
645 android.Manifest.permission.SHUTDOWN)
646 != PackageManager.PERMISSION_GRANTED) {
647 throw new SecurityException("Requires SHUTDOWN permission");
648 }
649
Joe Onorato8a9b2202010-02-26 18:56:32 -0800650 Slog.d(TAG, "Shutting down");
San Mehat873f2142010-01-14 10:25:07 -0800651 }
652
653 public boolean getIpForwardingEnabled() throws IllegalStateException{
654 mContext.enforceCallingOrSelfPermission(
655 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
656
Kenny Roota80ce062010-06-01 13:23:53 -0700657 ArrayList<String> rsp;
658 try {
659 rsp = mConnector.doCommand("ipfwd status");
660 } catch (NativeDaemonConnectorException e) {
661 throw new IllegalStateException(
662 "Unable to communicate with native daemon to ipfwd status");
663 }
San Mehat873f2142010-01-14 10:25:07 -0800664
665 for (String line : rsp) {
Kenny Roota80ce062010-06-01 13:23:53 -0700666 String[] tok = line.split(" ");
667 if (tok.length < 3) {
668 Slog.e(TAG, "Malformed response from native daemon: " + line);
669 return false;
670 }
671
San Mehat873f2142010-01-14 10:25:07 -0800672 int code = Integer.parseInt(tok[0]);
673 if (code == NetdResponseCode.IpFwdStatusResult) {
674 // 211 Forwarding <enabled/disabled>
Kenny Roota80ce062010-06-01 13:23:53 -0700675 return "enabled".equals(tok[2]);
San Mehat873f2142010-01-14 10:25:07 -0800676 } else {
677 throw new IllegalStateException(String.format("Unexpected response code %d", code));
678 }
679 }
680 throw new IllegalStateException("Got an empty response");
681 }
682
683 public void setIpForwardingEnabled(boolean enable) throws IllegalStateException {
684 mContext.enforceCallingOrSelfPermission(
685 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
686 mConnector.doCommand(String.format("ipfwd %sable", (enable ? "en" : "dis")));
687 }
688
Robert Greenwaltbfb7bfa2010-03-24 16:03:21 -0700689 public void startTethering(String[] dhcpRange)
San Mehat873f2142010-01-14 10:25:07 -0800690 throws IllegalStateException {
691 mContext.enforceCallingOrSelfPermission(
692 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Robert Greenwaltbfb7bfa2010-03-24 16:03:21 -0700693 // cmd is "tether start first_start first_stop second_start second_stop ..."
694 // an odd number of addrs will fail
695 String cmd = "tether start";
696 for (String d : dhcpRange) {
697 cmd += " " + d;
698 }
Kenny Roota80ce062010-06-01 13:23:53 -0700699
700 try {
701 mConnector.doCommand(cmd);
702 } catch (NativeDaemonConnectorException e) {
703 throw new IllegalStateException("Unable to communicate to native daemon");
704 }
San Mehat873f2142010-01-14 10:25:07 -0800705 }
706
707 public void stopTethering() throws IllegalStateException {
708 mContext.enforceCallingOrSelfPermission(
709 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700710 try {
711 mConnector.doCommand("tether stop");
712 } catch (NativeDaemonConnectorException e) {
713 throw new IllegalStateException("Unable to communicate to native daemon to stop tether");
714 }
San Mehat873f2142010-01-14 10:25:07 -0800715 }
716
717 public boolean isTetheringStarted() throws IllegalStateException {
718 mContext.enforceCallingOrSelfPermission(
719 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
720
Kenny Roota80ce062010-06-01 13:23:53 -0700721 ArrayList<String> rsp;
722 try {
723 rsp = mConnector.doCommand("tether status");
724 } catch (NativeDaemonConnectorException e) {
725 throw new IllegalStateException(
726 "Unable to communicate to native daemon to get tether status");
727 }
San Mehat873f2142010-01-14 10:25:07 -0800728
729 for (String line : rsp) {
Kenny Roota80ce062010-06-01 13:23:53 -0700730 String[] tok = line.split(" ");
731 if (tok.length < 3) {
732 throw new IllegalStateException("Malformed response for tether status: " + line);
733 }
San Mehat873f2142010-01-14 10:25:07 -0800734 int code = Integer.parseInt(tok[0]);
735 if (code == NetdResponseCode.TetherStatusResult) {
736 // XXX: Tethering services <started/stopped> <TBD>...
Kenny Roota80ce062010-06-01 13:23:53 -0700737 return "started".equals(tok[2]);
San Mehat873f2142010-01-14 10:25:07 -0800738 } else {
739 throw new IllegalStateException(String.format("Unexpected response code %d", code));
740 }
741 }
742 throw new IllegalStateException("Got an empty response");
743 }
744
745 public void tetherInterface(String iface) throws IllegalStateException {
746 mContext.enforceCallingOrSelfPermission(
747 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700748 try {
749 mConnector.doCommand("tether interface add " + iface);
750 } catch (NativeDaemonConnectorException e) {
751 throw new IllegalStateException(
752 "Unable to communicate to native daemon for adding tether interface");
753 }
San Mehat873f2142010-01-14 10:25:07 -0800754 }
755
756 public void untetherInterface(String iface) {
757 mContext.enforceCallingOrSelfPermission(
758 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700759 try {
760 mConnector.doCommand("tether interface remove " + iface);
761 } catch (NativeDaemonConnectorException e) {
762 throw new IllegalStateException(
763 "Unable to communicate to native daemon for removing tether interface");
764 }
San Mehat873f2142010-01-14 10:25:07 -0800765 }
766
767 public String[] listTetheredInterfaces() throws IllegalStateException {
768 mContext.enforceCallingOrSelfPermission(
769 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700770 try {
771 return mConnector.doListCommand(
772 "tether interface list", NetdResponseCode.TetherInterfaceListResult);
773 } catch (NativeDaemonConnectorException e) {
774 throw new IllegalStateException(
775 "Unable to communicate to native daemon for listing tether interfaces");
776 }
San Mehat873f2142010-01-14 10:25:07 -0800777 }
778
779 public void setDnsForwarders(String[] dns) throws IllegalStateException {
780 mContext.enforceCallingOrSelfPermission(
781 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
782 try {
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800783 String cmd = "tether dns set";
San Mehat873f2142010-01-14 10:25:07 -0800784 for (String s : dns) {
Robert Greenwalte5903732011-02-22 16:00:42 -0800785 cmd += " " + NetworkUtils.numericToInetAddress(s).getHostAddress();
San Mehat873f2142010-01-14 10:25:07 -0800786 }
Kenny Roota80ce062010-06-01 13:23:53 -0700787 try {
788 mConnector.doCommand(cmd);
789 } catch (NativeDaemonConnectorException e) {
790 throw new IllegalStateException(
791 "Unable to communicate to native daemon for setting tether dns");
792 }
Robert Greenwalte5903732011-02-22 16:00:42 -0800793 } catch (IllegalArgumentException e) {
San Mehat873f2142010-01-14 10:25:07 -0800794 throw new IllegalStateException("Error resolving dns name", e);
795 }
796 }
797
798 public String[] getDnsForwarders() throws IllegalStateException {
799 mContext.enforceCallingOrSelfPermission(
800 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700801 try {
802 return mConnector.doListCommand(
803 "tether dns list", NetdResponseCode.TetherDnsFwdTgtListResult);
804 } catch (NativeDaemonConnectorException e) {
805 throw new IllegalStateException(
806 "Unable to communicate to native daemon for listing tether dns");
807 }
San Mehat873f2142010-01-14 10:25:07 -0800808 }
809
810 public void enableNat(String internalInterface, String externalInterface)
811 throws IllegalStateException {
812 mContext.enforceCallingOrSelfPermission(
813 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700814 try {
815 mConnector.doCommand(
816 String.format("nat enable %s %s", internalInterface, externalInterface));
817 } catch (NativeDaemonConnectorException e) {
818 throw new IllegalStateException(
819 "Unable to communicate to native daemon for enabling NAT interface");
820 }
San Mehat873f2142010-01-14 10:25:07 -0800821 }
822
823 public void disableNat(String internalInterface, String externalInterface)
824 throws IllegalStateException {
825 mContext.enforceCallingOrSelfPermission(
826 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700827 try {
828 mConnector.doCommand(
829 String.format("nat disable %s %s", internalInterface, externalInterface));
830 } catch (NativeDaemonConnectorException e) {
831 throw new IllegalStateException(
832 "Unable to communicate to native daemon for disabling NAT interface");
833 }
San Mehat873f2142010-01-14 10:25:07 -0800834 }
San Mehat72759df2010-01-19 13:50:37 -0800835
836 public String[] listTtys() throws IllegalStateException {
837 mContext.enforceCallingOrSelfPermission(
838 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700839 try {
840 return mConnector.doListCommand("list_ttys", NetdResponseCode.TtyListResult);
841 } catch (NativeDaemonConnectorException e) {
842 throw new IllegalStateException(
843 "Unable to communicate to native daemon for listing TTYs");
844 }
San Mehat72759df2010-01-19 13:50:37 -0800845 }
846
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800847 public void attachPppd(String tty, String localAddr, String remoteAddr, String dns1Addr,
848 String dns2Addr) throws IllegalStateException {
San Mehat72759df2010-01-19 13:50:37 -0800849 try {
850 mContext.enforceCallingOrSelfPermission(
851 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Robert Greenwaltd0e18ff2010-01-26 11:40:34 -0800852 mConnector.doCommand(String.format("pppd attach %s %s %s %s %s", tty,
Robert Greenwalte5903732011-02-22 16:00:42 -0800853 NetworkUtils.numericToInetAddress(localAddr).getHostAddress(),
854 NetworkUtils.numericToInetAddress(remoteAddr).getHostAddress(),
855 NetworkUtils.numericToInetAddress(dns1Addr).getHostAddress(),
856 NetworkUtils.numericToInetAddress(dns2Addr).getHostAddress()));
857 } catch (IllegalArgumentException e) {
San Mehat72759df2010-01-19 13:50:37 -0800858 throw new IllegalStateException("Error resolving addr", e);
Kenny Roota80ce062010-06-01 13:23:53 -0700859 } catch (NativeDaemonConnectorException e) {
860 throw new IllegalStateException("Error communicating to native daemon to attach pppd", e);
San Mehat72759df2010-01-19 13:50:37 -0800861 }
862 }
863
864 public void detachPppd(String tty) throws IllegalStateException {
865 mContext.enforceCallingOrSelfPermission(
866 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700867 try {
868 mConnector.doCommand(String.format("pppd detach %s", tty));
869 } catch (NativeDaemonConnectorException e) {
870 throw new IllegalStateException("Error communicating to native daemon to detach pppd", e);
871 }
San Mehat72759df2010-01-19 13:50:37 -0800872 }
Robert Greenwaltce1200d2010-02-18 11:25:54 -0800873
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700874 public void startAccessPoint(WifiConfiguration wifiConfig, String wlanIface, String softapIface)
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800875 throws IllegalStateException {
876 mContext.enforceCallingOrSelfPermission(
877 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
878 mContext.enforceCallingOrSelfPermission(
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700879 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700880 try {
Irfan Sheriffcb30b222011-07-29 20:54:52 -0700881 wifiFirmwareReload(wlanIface, "AP");
Kenny Roota80ce062010-06-01 13:23:53 -0700882 mConnector.doCommand(String.format("softap start " + wlanIface));
883 if (wifiConfig == null) {
884 mConnector.doCommand(String.format("softap set " + wlanIface + " " + softapIface));
885 } else {
886 /**
887 * softap set arg1 arg2 arg3 [arg4 arg5 arg6 arg7 arg8]
888 * argv1 - wlan interface
889 * argv2 - softap interface
890 * argv3 - SSID
891 * argv4 - Security
892 * argv5 - Key
893 * argv6 - Channel
894 * argv7 - Preamble
895 * argv8 - Max SCB
896 */
Irfan Sheriffec8d23a2011-02-16 17:00:33 -0800897 String str = String.format("softap set " + wlanIface + " " + softapIface +
898 " %s %s %s", convertQuotedString(wifiConfig.SSID),
899 getSecurityType(wifiConfig),
900 convertQuotedString(wifiConfig.preSharedKey));
Kenny Roota80ce062010-06-01 13:23:53 -0700901 mConnector.doCommand(str);
902 }
903 mConnector.doCommand(String.format("softap startap"));
904 } catch (NativeDaemonConnectorException e) {
905 throw new IllegalStateException("Error communicating to native daemon to start softap", e);
Irfan Sheriff9ab518ad2010-03-12 15:48:17 -0800906 }
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800907 }
908
Irfan Sheriffa6e559e2010-05-24 14:55:42 -0700909 private String convertQuotedString(String s) {
Irfan Sheriff7baec0f2010-05-26 17:16:47 -0700910 if (s == null) {
911 return s;
912 }
913 /* Replace \ with \\, then " with \" and add quotes at end */
914 return '"' + s.replaceAll("\\\\","\\\\\\\\").replaceAll("\"","\\\\\"") + '"';
Irfan Sheriffa6e559e2010-05-24 14:55:42 -0700915 }
916
Irfan Sheriffec8d23a2011-02-16 17:00:33 -0800917 private String getSecurityType(WifiConfiguration wifiConfig) {
918 switch (wifiConfig.getAuthType()) {
919 case KeyMgmt.WPA_PSK:
920 return "wpa-psk";
921 case KeyMgmt.WPA2_PSK:
922 return "wpa2-psk";
923 default:
924 return "open";
925 }
926 }
927
Irfan Sheriffcb30b222011-07-29 20:54:52 -0700928 /* @param mode can be "AP", "STA" or "P2P" */
929 public void wifiFirmwareReload(String wlanIface, String mode) throws IllegalStateException {
930 mContext.enforceCallingOrSelfPermission(
931 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
932 mContext.enforceCallingOrSelfPermission(
933 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
934
935 try {
936 mConnector.doCommand(String.format("softap fwreload " + wlanIface + " " + mode));
937 } catch (NativeDaemonConnectorException e) {
938 throw new IllegalStateException("Error communicating to native daemon ", e);
939 }
940 }
941
Irfan Sheriff23eb2972011-07-22 15:21:10 -0700942 public void stopAccessPoint(String wlanIface) throws IllegalStateException {
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800943 mContext.enforceCallingOrSelfPermission(
944 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
945 mContext.enforceCallingOrSelfPermission(
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700946 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700947 try {
948 mConnector.doCommand("softap stopap");
Irfan Sheriff23eb2972011-07-22 15:21:10 -0700949 mConnector.doCommand("softap stop " + wlanIface);
Irfan Sheriffcb30b222011-07-29 20:54:52 -0700950 wifiFirmwareReload(wlanIface, "STA");
Kenny Roota80ce062010-06-01 13:23:53 -0700951 } catch (NativeDaemonConnectorException e) {
952 throw new IllegalStateException("Error communicating to native daemon to stop soft AP",
953 e);
954 }
Irfan Sheriff5321aef2010-02-12 12:35:59 -0800955 }
956
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700957 public void setAccessPoint(WifiConfiguration wifiConfig, String wlanIface, String softapIface)
958 throws IllegalStateException {
959 mContext.enforceCallingOrSelfPermission(
960 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
961 mContext.enforceCallingOrSelfPermission(
962 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -0700963 try {
964 if (wifiConfig == null) {
965 mConnector.doCommand(String.format("softap set " + wlanIface + " " + softapIface));
966 } else {
967 String str = String.format("softap set " + wlanIface + " " + softapIface
968 + " %s %s %s", convertQuotedString(wifiConfig.SSID),
Irfan Sheriffec8d23a2011-02-16 17:00:33 -0800969 getSecurityType(wifiConfig),
Kenny Roota80ce062010-06-01 13:23:53 -0700970 convertQuotedString(wifiConfig.preSharedKey));
971 mConnector.doCommand(str);
972 }
973 } catch (NativeDaemonConnectorException e) {
974 throw new IllegalStateException("Error communicating to native daemon to set soft AP",
975 e);
Irfan Sheriffc2f54c22010-03-18 14:02:22 -0700976 }
977 }
San Mehat91cac642010-03-31 14:31:36 -0700978
979 private long getInterfaceCounter(String iface, boolean rx) {
980 mContext.enforceCallingOrSelfPermission(
981 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
982 try {
Kenny Roota80ce062010-06-01 13:23:53 -0700983 String rsp;
984 try {
985 rsp = mConnector.doCommand(
986 String.format("interface read%scounter %s", (rx ? "rx" : "tx"), iface)).get(0);
987 } catch (NativeDaemonConnectorException e1) {
988 Slog.e(TAG, "Error communicating with native daemon", e1);
989 return -1;
990 }
991
992 String[] tok = rsp.split(" ");
993 if (tok.length < 2) {
994 Slog.e(TAG, String.format("Malformed response for reading %s interface",
995 (rx ? "rx" : "tx")));
996 return -1;
997 }
998
San Mehat91cac642010-03-31 14:31:36 -0700999 int code;
1000 try {
1001 code = Integer.parseInt(tok[0]);
1002 } catch (NumberFormatException nfe) {
1003 Slog.e(TAG, String.format("Error parsing code %s", tok[0]));
1004 return -1;
1005 }
1006 if ((rx && code != NetdResponseCode.InterfaceRxCounterResult) || (
1007 !rx && code != NetdResponseCode.InterfaceTxCounterResult)) {
1008 Slog.e(TAG, String.format("Unexpected response code %d", code));
1009 return -1;
1010 }
1011 return Long.parseLong(tok[1]);
1012 } catch (Exception e) {
1013 Slog.e(TAG, String.format(
1014 "Failed to read interface %s counters", (rx ? "rx" : "tx")), e);
1015 }
1016 return -1;
1017 }
1018
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001019 @Override
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001020 public NetworkStats getNetworkStatsSummary() {
1021 mContext.enforceCallingOrSelfPermission(
1022 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
1023
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001024 final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6);
1025 final NetworkStats.Entry entry = new NetworkStats.Entry();
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001026
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001027 final HashSet<String> activeIfaces = Sets.newHashSet();
1028 final ArrayList<String> values = Lists.newArrayList();
1029
1030 BufferedReader reader = null;
1031 try {
1032 reader = new BufferedReader(new FileReader(mStatsIface));
1033
1034 // skip first two header lines
1035 reader.readLine();
1036 reader.readLine();
1037
1038 // parse remaining lines
1039 String line;
1040 while ((line = reader.readLine()) != null) {
1041 splitLine(line, values);
1042
1043 try {
1044 entry.iface = values.get(0);
1045 entry.uid = UID_ALL;
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -07001046 entry.set = SET_DEFAULT;
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001047 entry.tag = TAG_NONE;
1048 entry.rxBytes = Long.parseLong(values.get(1));
1049 entry.rxPackets = Long.parseLong(values.get(2));
1050 entry.txBytes = Long.parseLong(values.get(9));
1051 entry.txPackets = Long.parseLong(values.get(10));
1052
1053 activeIfaces.add(entry.iface);
1054 stats.addValues(entry);
1055 } catch (NumberFormatException e) {
1056 Slog.w(TAG, "problem parsing stats row '" + line + "': " + e);
1057 }
1058 }
1059 } catch (IOException e) {
1060 Slog.w(TAG, "problem parsing stats: " + e);
1061 } finally {
1062 IoUtils.closeQuietly(reader);
1063 }
1064
1065 if (DBG) Slog.d(TAG, "recorded active stats from " + activeIfaces);
1066
1067 // splice in stats from any disabled ifaces
1068 if (mBandwidthControlEnabled) {
1069 final HashSet<String> xtIfaces = Sets.newHashSet(fileListWithoutNull(mStatsXtIface));
1070 xtIfaces.removeAll(activeIfaces);
1071
1072 for (String iface : xtIfaces) {
1073 final File ifacePath = new File(mStatsXtIface, iface);
1074
1075 entry.iface = iface;
1076 entry.uid = UID_ALL;
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -07001077 entry.set = SET_DEFAULT;
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001078 entry.tag = TAG_NONE;
1079 entry.rxBytes = readSingleLongFromFile(new File(ifacePath, "rx_bytes"));
1080 entry.rxPackets = readSingleLongFromFile(new File(ifacePath, "rx_packets"));
1081 entry.txBytes = readSingleLongFromFile(new File(ifacePath, "tx_bytes"));
1082 entry.txPackets = readSingleLongFromFile(new File(ifacePath, "tx_packets"));
1083
1084 stats.addValues(entry);
1085 }
1086
1087 if (DBG) Slog.d(TAG, "recorded stale stats from " + xtIfaces);
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001088 }
1089
Jeff Sharkey4a971222011-06-11 22:16:55 -07001090 return stats;
San Mehat91cac642010-03-31 14:31:36 -07001091 }
1092
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001093 @Override
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001094 public NetworkStats getNetworkStatsDetail() {
1095 mContext.enforceCallingOrSelfPermission(
1096 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
1097
Jeff Sharkey350083e2011-06-29 10:45:16 -07001098 if (mBandwidthControlEnabled) {
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001099 return getNetworkStatsDetailNetfilter(UID_ALL);
1100 } else {
1101 return getNetworkStatsDetailUidstat(UID_ALL);
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001102 }
San Mehat91cac642010-03-31 14:31:36 -07001103 }
1104
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001105 @Override
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001106 public void setInterfaceQuota(String iface, long quotaBytes) {
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001107 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1108
Jeff Sharkey350083e2011-06-29 10:45:16 -07001109 // silently discard when control disabled
1110 // TODO: eventually migrate to be always enabled
1111 if (!mBandwidthControlEnabled) return;
1112
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001113 synchronized (mQuotaLock) {
1114 if (mActiveQuotaIfaces.contains(iface)) {
1115 throw new IllegalStateException("iface " + iface + " already has quota");
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001116 }
1117
1118 final StringBuilder command = new StringBuilder();
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001119 command.append("bandwidth setiquota ").append(iface).append(" ").append(quotaBytes);
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001120
1121 try {
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001122 // TODO: support quota shared across interfaces
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001123 mConnector.doCommand(command.toString());
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001124 mActiveQuotaIfaces.add(iface);
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001125 } catch (NativeDaemonConnectorException e) {
1126 throw new IllegalStateException("Error communicating to native daemon", e);
1127 }
Ashish Sharma50fd36d2011-06-15 19:34:53 -07001128 }
1129 }
1130
1131 @Override
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001132 public void removeInterfaceQuota(String iface) {
1133 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1134
Jeff Sharkey350083e2011-06-29 10:45:16 -07001135 // silently discard when control disabled
1136 // TODO: eventually migrate to be always enabled
1137 if (!mBandwidthControlEnabled) return;
1138
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001139 synchronized (mQuotaLock) {
1140 if (!mActiveQuotaIfaces.contains(iface)) {
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001141 // TODO: eventually consider throwing
1142 return;
1143 }
1144
1145 final StringBuilder command = new StringBuilder();
1146 command.append("bandwidth removeiquota ").append(iface);
1147
1148 try {
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001149 // TODO: support quota shared across interfaces
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001150 mConnector.doCommand(command.toString());
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001151 mActiveQuotaIfaces.remove(iface);
1152 mActiveAlertIfaces.remove(iface);
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001153 } catch (NativeDaemonConnectorException e) {
1154 throw new IllegalStateException("Error communicating to native daemon", e);
1155 }
1156 }
1157 }
1158
1159 @Override
Jeff Sharkey41ff7ec2011-07-25 15:21:22 -07001160 public void setInterfaceAlert(String iface, long alertBytes) {
1161 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1162
1163 // silently discard when control disabled
1164 // TODO: eventually migrate to be always enabled
1165 if (!mBandwidthControlEnabled) return;
1166
1167 // quick sanity check
1168 if (!mActiveQuotaIfaces.contains(iface)) {
1169 throw new IllegalStateException("setting alert requires existing quota on iface");
1170 }
1171
1172 synchronized (mQuotaLock) {
1173 if (mActiveAlertIfaces.contains(iface)) {
1174 throw new IllegalStateException("iface " + iface + " already has alert");
1175 }
1176
1177 final StringBuilder command = new StringBuilder();
1178 command.append("bandwidth setinterfacealert ").append(iface).append(" ").append(
1179 alertBytes);
1180
1181 try {
1182 // TODO: support alert shared across interfaces
1183 mConnector.doCommand(command.toString());
1184 mActiveAlertIfaces.add(iface);
1185 } catch (NativeDaemonConnectorException e) {
1186 throw new IllegalStateException("Error communicating to native daemon", e);
1187 }
1188 }
1189 }
1190
1191 @Override
1192 public void removeInterfaceAlert(String iface) {
1193 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1194
1195 // silently discard when control disabled
1196 // TODO: eventually migrate to be always enabled
1197 if (!mBandwidthControlEnabled) return;
1198
1199 synchronized (mQuotaLock) {
1200 if (!mActiveAlertIfaces.contains(iface)) {
1201 // TODO: eventually consider throwing
1202 return;
1203 }
1204
1205 final StringBuilder command = new StringBuilder();
1206 command.append("bandwidth removeinterfacealert ").append(iface);
1207
1208 try {
1209 // TODO: support alert shared across interfaces
1210 mConnector.doCommand(command.toString());
1211 mActiveAlertIfaces.remove(iface);
1212 } catch (NativeDaemonConnectorException e) {
1213 throw new IllegalStateException("Error communicating to native daemon", e);
1214 }
1215 }
1216 }
1217
1218 @Override
1219 public void setGlobalAlert(long alertBytes) {
1220 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1221
1222 // silently discard when control disabled
1223 // TODO: eventually migrate to be always enabled
1224 if (!mBandwidthControlEnabled) return;
1225
1226 final StringBuilder command = new StringBuilder();
1227 command.append("bandwidth setglobalalert ").append(alertBytes);
1228
1229 try {
1230 mConnector.doCommand(command.toString());
1231 } catch (NativeDaemonConnectorException e) {
1232 throw new IllegalStateException("Error communicating to native daemon", e);
1233 }
1234 }
1235
1236 @Override
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001237 public void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces) {
1238 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1239
Jeff Sharkey350083e2011-06-29 10:45:16 -07001240 // silently discard when control disabled
1241 // TODO: eventually migrate to be always enabled
1242 if (!mBandwidthControlEnabled) return;
1243
Jeff Sharkeyb3f19ca2011-06-29 23:54:13 -07001244 synchronized (mUidRejectOnQuota) {
1245 final boolean oldRejectOnQuota = mUidRejectOnQuota.get(uid, false);
1246 if (oldRejectOnQuota == rejectOnQuotaInterfaces) {
1247 // TODO: eventually consider throwing
1248 return;
1249 }
1250
1251 final StringBuilder command = new StringBuilder();
1252 command.append("bandwidth");
1253 if (rejectOnQuotaInterfaces) {
1254 command.append(" addnaughtyapps");
1255 } else {
1256 command.append(" removenaughtyapps");
1257 }
1258 command.append(" ").append(uid);
1259
1260 try {
1261 mConnector.doCommand(command.toString());
1262 if (rejectOnQuotaInterfaces) {
1263 mUidRejectOnQuota.put(uid, true);
1264 } else {
1265 mUidRejectOnQuota.delete(uid);
1266 }
1267 } catch (NativeDaemonConnectorException e) {
1268 throw new IllegalStateException("Error communicating to native daemon", e);
1269 }
Ashish Sharma50fd36d2011-06-15 19:34:53 -07001270 }
1271 }
1272
Jeff Sharkey63d27a92011-08-03 17:04:22 -07001273 @Override
1274 public boolean isBandwidthControlEnabled() {
1275 mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
1276 return mBandwidthControlEnabled;
1277 }
1278
1279 @Override
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001280 public NetworkStats getNetworkStatsUidDetail(int uid) {
1281 if (Binder.getCallingUid() != uid) {
1282 mContext.enforceCallingOrSelfPermission(
1283 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
1284 }
1285
Jeff Sharkey350083e2011-06-29 10:45:16 -07001286 if (mBandwidthControlEnabled) {
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001287 return getNetworkStatsDetailNetfilter(uid);
1288 } else {
1289 return getNetworkStatsDetailUidstat(uid);
1290 }
1291 }
1292
1293 /**
1294 * Build {@link NetworkStats} with detailed UID statistics.
1295 */
1296 private NetworkStats getNetworkStatsDetailNetfilter(int limitUid) {
1297 final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 24);
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001298 final NetworkStats.Entry entry = new NetworkStats.Entry();
1299
Jeff Sharkeya63ba592011-07-19 23:47:12 -07001300 // TODO: remove knownLines check once 5087722 verified
1301 final HashSet<String> knownLines = Sets.newHashSet();
1302
Jeff Sharkey4414cea2011-06-24 17:05:24 -07001303 final ArrayList<String> keys = Lists.newArrayList();
1304 final ArrayList<String> values = Lists.newArrayList();
1305 final HashMap<String, String> parsed = Maps.newHashMap();
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001306
1307 BufferedReader reader = null;
1308 try {
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001309 reader = new BufferedReader(new FileReader(mStatsXtUid));
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001310
Jeff Sharkey4414cea2011-06-24 17:05:24 -07001311 // parse first line as header
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001312 String line = reader.readLine();
Jeff Sharkey4414cea2011-06-24 17:05:24 -07001313 splitLine(line, keys);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001314
Jeff Sharkey4414cea2011-06-24 17:05:24 -07001315 // parse remaining lines
1316 while ((line = reader.readLine()) != null) {
1317 splitLine(line, values);
1318 parseLine(keys, values, parsed);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001319
Jeff Sharkeya63ba592011-07-19 23:47:12 -07001320 if (!knownLines.add(line)) {
1321 throw new IllegalStateException("encountered duplicate proc entry");
1322 }
1323
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001324 try {
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001325 entry.iface = parsed.get(KEY_IFACE);
Jeff Sharkeya63ba592011-07-19 23:47:12 -07001326 entry.uid = getParsedInt(parsed, KEY_UID);
Jeff Sharkeyb5d55e32011-08-10 17:53:27 -07001327 entry.set = getParsedInt(parsed, KEY_COUNTER_SET);
1328 entry.tag = kernelToTag(parsed.get(KEY_TAG_HEX));
Jeff Sharkeya63ba592011-07-19 23:47:12 -07001329 entry.rxBytes = getParsedLong(parsed, KEY_RX_BYTES);
1330 entry.rxPackets = getParsedLong(parsed, KEY_RX_PACKETS);
1331 entry.txBytes = getParsedLong(parsed, KEY_TX_BYTES);
1332 entry.txPackets = getParsedLong(parsed, KEY_TX_PACKETS);
Jeff Sharkeyd03fd3f2011-06-19 20:55:09 -07001333
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001334 if (limitUid == UID_ALL || limitUid == entry.uid) {
1335 stats.addValues(entry);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001336 }
1337 } catch (NumberFormatException e) {
Jeff Sharkey4414cea2011-06-24 17:05:24 -07001338 Slog.w(TAG, "problem parsing stats row '" + line + "': " + e);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001339 }
1340 }
1341 } catch (IOException e) {
1342 Slog.w(TAG, "problem parsing stats: " + e);
1343 } finally {
1344 IoUtils.closeQuietly(reader);
1345 }
1346
Jeff Sharkey4a971222011-06-11 22:16:55 -07001347 return stats;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001348 }
1349
Jeff Sharkeya63ba592011-07-19 23:47:12 -07001350 private static int getParsedInt(HashMap<String, String> parsed, String key) {
1351 final String value = parsed.get(key);
1352 return value != null ? Integer.parseInt(value) : 0;
1353 }
1354
1355 private static long getParsedLong(HashMap<String, String> parsed, String key) {
1356 final String value = parsed.get(key);
1357 return value != null ? Long.parseLong(value) : 0;
1358 }
1359
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001360 /**
1361 * Build {@link NetworkStats} with detailed UID statistics.
1362 *
1363 * @deprecated since this uses older "uid_stat" data, and doesn't provide
1364 * tag-level granularity or additional variables.
1365 */
1366 @Deprecated
1367 private NetworkStats getNetworkStatsDetailUidstat(int limitUid) {
1368 final String[] knownUids;
1369 if (limitUid == UID_ALL) {
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001370 knownUids = fileListWithoutNull(mStatsUid);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001371 } else {
1372 knownUids = new String[] { String.valueOf(limitUid) };
1373 }
1374
1375 final NetworkStats stats = new NetworkStats(
1376 SystemClock.elapsedRealtime(), knownUids.length);
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001377 final NetworkStats.Entry entry = new NetworkStats.Entry();
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001378 for (String uid : knownUids) {
1379 final int uidInt = Integer.parseInt(uid);
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001380 final File uidPath = new File(mStatsUid, uid);
1381
1382 entry.iface = IFACE_ALL;
1383 entry.uid = uidInt;
1384 entry.tag = TAG_NONE;
1385 entry.rxBytes = readSingleLongFromFile(new File(uidPath, "tcp_rcv"));
1386 entry.rxPackets = readSingleLongFromFile(new File(uidPath, "tcp_rcv_pkt"));
1387 entry.txBytes = readSingleLongFromFile(new File(uidPath, "tcp_snd"));
1388 entry.txPackets = readSingleLongFromFile(new File(uidPath, "tcp_snd_pkt"));
1389
1390 stats.addValues(entry);
Jeff Sharkey1b5a2a92011-06-18 18:34:16 -07001391 }
1392
1393 return stats;
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001394 }
1395
San Mehatf0db6e12010-04-07 15:22:10 -07001396 public void setInterfaceThrottle(String iface, int rxKbps, int txKbps) {
San Mehat91cac642010-03-31 14:31:36 -07001397 mContext.enforceCallingOrSelfPermission(
1398 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
Kenny Roota80ce062010-06-01 13:23:53 -07001399 try {
1400 mConnector.doCommand(String.format(
1401 "interface setthrottle %s %d %d", iface, rxKbps, txKbps));
1402 } catch (NativeDaemonConnectorException e) {
1403 Slog.e(TAG, "Error communicating with native daemon to set throttle", e);
1404 }
San Mehat91cac642010-03-31 14:31:36 -07001405 }
1406
1407 private int getInterfaceThrottle(String iface, boolean rx) {
1408 mContext.enforceCallingOrSelfPermission(
1409 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
1410 try {
Kenny Roota80ce062010-06-01 13:23:53 -07001411 String rsp;
1412 try {
1413 rsp = mConnector.doCommand(
1414 String.format("interface getthrottle %s %s", iface,
1415 (rx ? "rx" : "tx"))).get(0);
1416 } catch (NativeDaemonConnectorException e) {
1417 Slog.e(TAG, "Error communicating with native daemon to getthrottle", e);
1418 return -1;
1419 }
1420
1421 String[] tok = rsp.split(" ");
1422 if (tok.length < 2) {
1423 Slog.e(TAG, "Malformed response to getthrottle command");
1424 return -1;
1425 }
1426
San Mehat91cac642010-03-31 14:31:36 -07001427 int code;
1428 try {
1429 code = Integer.parseInt(tok[0]);
1430 } catch (NumberFormatException nfe) {
1431 Slog.e(TAG, String.format("Error parsing code %s", tok[0]));
1432 return -1;
1433 }
1434 if ((rx && code != NetdResponseCode.InterfaceRxThrottleResult) || (
1435 !rx && code != NetdResponseCode.InterfaceTxThrottleResult)) {
1436 Slog.e(TAG, String.format("Unexpected response code %d", code));
1437 return -1;
1438 }
1439 return Integer.parseInt(tok[1]);
1440 } catch (Exception e) {
1441 Slog.e(TAG, String.format(
1442 "Failed to read interface %s throttle value", (rx ? "rx" : "tx")), e);
1443 }
1444 return -1;
1445 }
1446
1447 public int getInterfaceRxThrottle(String iface) {
1448 return getInterfaceThrottle(iface, true);
1449 }
1450
1451 public int getInterfaceTxThrottle(String iface) {
1452 return getInterfaceThrottle(iface, false);
1453 }
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001454
1455 /**
Jeff Sharkey4414cea2011-06-24 17:05:24 -07001456 * Split given line into {@link ArrayList}.
1457 */
1458 private static void splitLine(String line, ArrayList<String> outSplit) {
1459 outSplit.clear();
1460
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001461 final StringTokenizer t = new StringTokenizer(line, " \t\n\r\f:");
Jeff Sharkey4414cea2011-06-24 17:05:24 -07001462 while (t.hasMoreTokens()) {
1463 outSplit.add(t.nextToken());
1464 }
1465 }
1466
1467 /**
1468 * Zip the two given {@link ArrayList} as key and value pairs into
1469 * {@link HashMap}.
1470 */
1471 private static void parseLine(
1472 ArrayList<String> keys, ArrayList<String> values, HashMap<String, String> outParsed) {
1473 outParsed.clear();
1474
1475 final int size = Math.min(keys.size(), values.size());
1476 for (int i = 0; i < size; i++) {
1477 outParsed.put(keys.get(i), values.get(i));
1478 }
1479 }
1480
1481 /**
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001482 * Utility method to read a single plain-text {@link Long} from the given
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001483 * {@link File}, usually from a {@code /proc/} filesystem.
1484 */
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001485 private static long readSingleLongFromFile(File file) {
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001486 try {
Jeff Sharkeyeedcb952011-05-17 14:55:15 -07001487 final byte[] buffer = IoUtils.readFileAsByteArray(file.toString());
1488 return Long.parseLong(new String(buffer).trim());
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001489 } catch (NumberFormatException e) {
1490 return -1;
1491 } catch (IOException e) {
1492 return -1;
Jeff Sharkey9a13f362011-04-26 16:25:36 -07001493 }
1494 }
Jean-Baptiste Querud5299ff2011-07-07 08:46:09 -07001495
Jeff Sharkeyfd8be3e2011-07-11 14:36:15 -07001496 /**
1497 * Wrapper for {@link File#list()} that returns empty array instead of
1498 * {@code null}.
1499 */
1500 private static String[] fileListWithoutNull(File file) {
1501 final String[] list = file.list();
1502 return list != null ? list : new String[0];
1503 }
1504
Mattias Falk7475c0c2011-04-04 16:10:36 +02001505 public void setDefaultInterfaceForDns(String iface) throws IllegalStateException {
1506 mContext.enforceCallingOrSelfPermission(
1507 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
1508 try {
1509 String cmd = "resolver setdefaultif " + iface;
1510
1511 mConnector.doCommand(cmd);
1512 } catch (NativeDaemonConnectorException e) {
1513 throw new IllegalStateException(
1514 "Error communicating with native daemon to set default interface", e);
1515 }
1516 }
1517
1518 public void setDnsServersForInterface(String iface, String[] servers)
1519 throws IllegalStateException {
1520 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_NETWORK_STATE,
1521 "NetworkManagementService");
1522 try {
1523 String cmd = "resolver setifdns " + iface;
1524 for (String s : servers) {
Robert Greenwalt572b7042011-07-25 17:00:13 -07001525 InetAddress a = NetworkUtils.numericToInetAddress(s);
1526 if (a.isAnyLocalAddress() == false) {
1527 cmd += " " + a.getHostAddress();
Mattias Falk7475c0c2011-04-04 16:10:36 +02001528 }
1529 }
Mattias Falk7475c0c2011-04-04 16:10:36 +02001530 mConnector.doCommand(cmd);
Robert Greenwalt572b7042011-07-25 17:00:13 -07001531 } catch (IllegalArgumentException e) {
1532 throw new IllegalStateException("Error setting dnsn for interface", e);
Mattias Falk7475c0c2011-04-04 16:10:36 +02001533 } catch (NativeDaemonConnectorException e) {
1534 throw new IllegalStateException(
Robert Greenwalt572b7042011-07-25 17:00:13 -07001535 "Error communicating with native daemon to set dns for interface", e);
Mattias Falk7475c0c2011-04-04 16:10:36 +02001536 }
1537 }
1538
1539 public void flushDefaultDnsCache() throws IllegalStateException {
1540 mContext.enforceCallingOrSelfPermission(
1541 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
1542 try {
1543 String cmd = "resolver flushdefaultif";
1544
1545 mConnector.doCommand(cmd);
1546 } catch (NativeDaemonConnectorException e) {
1547 throw new IllegalStateException(
1548 "Error communicating with native deamon to flush default interface", e);
1549 }
1550 }
1551
1552 public void flushInterfaceDnsCache(String iface) throws IllegalStateException {
1553 mContext.enforceCallingOrSelfPermission(
1554 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
1555 try {
1556 String cmd = "resolver flushif " + iface;
1557
1558 mConnector.doCommand(cmd);
1559 } catch (NativeDaemonConnectorException e) {
1560 throw new IllegalStateException(
Robert Greenwalt572b7042011-07-25 17:00:13 -07001561 "Error communicating with native daemon to flush interface " + iface, e);
Mattias Falk7475c0c2011-04-04 16:10:36 +02001562 }
1563 }
San Mehat873f2142010-01-14 10:25:07 -08001564}