2 * Copyright (C) 2007 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.server;
19 import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
20 import static android.Manifest.permission.DUMP;
21 import static android.Manifest.permission.SHUTDOWN;
22 import static android.net.NetworkStats.SET_DEFAULT;
23 import static android.net.NetworkStats.TAG_ALL;
24 import static android.net.NetworkStats.TAG_NONE;
25 import static android.net.NetworkStats.UID_ALL;
26 import static android.net.TrafficStats.UID_TETHERING;
27 import static android.net.RouteInfo.RTN_THROW;
28 import static android.net.RouteInfo.RTN_UNICAST;
29 import static android.net.RouteInfo.RTN_UNREACHABLE;
30 import static com.android.server.NetworkManagementService.NetdResponseCode.ClatdStatusResult;
31 import static com.android.server.NetworkManagementService.NetdResponseCode.InterfaceGetCfgResult;
32 import static com.android.server.NetworkManagementService.NetdResponseCode.InterfaceListResult;
33 import static com.android.server.NetworkManagementService.NetdResponseCode.IpFwdStatusResult;
34 import static com.android.server.NetworkManagementService.NetdResponseCode.TetherDnsFwdTgtListResult;
35 import static com.android.server.NetworkManagementService.NetdResponseCode.TetherInterfaceListResult;
36 import static com.android.server.NetworkManagementService.NetdResponseCode.TetherStatusResult;
37 import static com.android.server.NetworkManagementService.NetdResponseCode.TetheringStatsListResult;
38 import static com.android.server.NetworkManagementService.NetdResponseCode.TtyListResult;
39 import static com.android.server.NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED;
41 import android.content.Context;
42 import android.net.ConnectivityManager;
43 import android.net.INetworkManagementEventObserver;
44 import android.net.InterfaceConfiguration;
45 import android.net.IpPrefix;
46 import android.net.LinkAddress;
47 import android.net.Network;
48 import android.net.NetworkStats;
49 import android.net.NetworkUtils;
50 import android.net.RouteInfo;
51 import android.net.UidRange;
52 import android.net.wifi.WifiConfiguration;
53 import android.net.wifi.WifiConfiguration.KeyMgmt;
54 import android.os.BatteryStats;
55 import android.os.Binder;
56 import android.os.Handler;
57 import android.os.INetworkActivityListener;
58 import android.os.INetworkManagementService;
59 import android.os.PowerManager;
60 import android.os.Process;
61 import android.os.RemoteCallbackList;
62 import android.os.RemoteException;
63 import android.os.ServiceManager;
64 import android.os.SystemClock;
65 import android.os.SystemProperties;
66 import android.telephony.DataConnectionRealTimeInfo;
67 import android.telephony.PhoneStateListener;
68 import android.telephony.SubscriptionManager;
69 import android.telephony.TelephonyManager;
70 import android.util.Log;
71 import android.util.Slog;
72 import android.util.SparseBooleanArray;
74 import com.android.internal.app.IBatteryStats;
75 import com.android.internal.net.NetworkStatsFactory;
76 import com.android.internal.util.Preconditions;
77 import com.android.server.NativeDaemonConnector.Command;
78 import com.android.server.NativeDaemonConnector.SensitiveArg;
79 import com.android.server.net.LockdownVpnTracker;
80 import com.google.android.collect.Maps;
82 import java.io.BufferedReader;
83 import java.io.DataInputStream;
85 import java.io.FileDescriptor;
86 import java.io.FileInputStream;
87 import java.io.IOException;
88 import java.io.InputStreamReader;
89 import java.io.PrintWriter;
90 import java.net.Inet4Address;
91 import java.net.Inet6Address;
92 import java.net.InetAddress;
93 import java.net.InterfaceAddress;
94 import java.net.NetworkInterface;
95 import java.net.SocketException;
96 import java.util.ArrayList;
97 import java.util.Arrays;
98 import java.util.HashMap;
99 import java.util.List;
100 import java.util.Map;
101 import java.util.NoSuchElementException;
102 import java.util.StringTokenizer;
103 import java.util.concurrent.CountDownLatch;
108 public class NetworkManagementService extends INetworkManagementService.Stub
109 implements Watchdog.Monitor {
110 private static final String TAG = "NetworkManagementService";
111 private static final boolean DBG = false;
112 private static final String NETD_TAG = "NetdConnector";
113 private static final String NETD_SOCKET_NAME = "netd";
115 private static final int MAX_UID_RANGES_PER_COMMAND = 10;
118 * Name representing {@link #setGlobalAlert(long)} limit when delivered to
119 * {@link INetworkManagementEventObserver#limitReached(String, String)}.
121 public static final String LIMIT_GLOBAL_ALERT = "globalAlert";
123 class NetdResponseCode {
124 /* Keep in sync with system/netd/server/ResponseCode.h */
125 public static final int InterfaceListResult = 110;
126 public static final int TetherInterfaceListResult = 111;
127 public static final int TetherDnsFwdTgtListResult = 112;
128 public static final int TtyListResult = 113;
129 public static final int TetheringStatsListResult = 114;
131 public static final int TetherStatusResult = 210;
132 public static final int IpFwdStatusResult = 211;
133 public static final int InterfaceGetCfgResult = 213;
134 public static final int SoftapStatusResult = 214;
135 public static final int InterfaceRxCounterResult = 216;
136 public static final int InterfaceTxCounterResult = 217;
137 public static final int QuotaCounterResult = 220;
138 public static final int TetheringStatsResult = 221;
139 public static final int DnsProxyQueryResult = 222;
140 public static final int ClatdStatusResult = 223;
142 public static final int InterfaceChange = 600;
143 public static final int BandwidthControl = 601;
144 public static final int InterfaceClassActivity = 613;
145 public static final int InterfaceAddressChange = 614;
146 public static final int InterfaceDnsServerInfo = 615;
147 public static final int RouteChange = 616;
150 static final int DAEMON_MSG_MOBILE_CONN_REAL_TIME_INFO = 1;
153 * Binder context for this service
155 private final Context mContext;
158 * connector object for communicating with netd
160 private final NativeDaemonConnector mConnector;
162 private final Handler mFgHandler;
163 private final Handler mDaemonHandler;
164 private final PhoneStateListener mPhoneStateListener;
166 private IBatteryStats mBatteryStats;
168 private final Thread mThread;
169 private CountDownLatch mConnectedSignal = new CountDownLatch(1);
171 private final RemoteCallbackList<INetworkManagementEventObserver> mObservers =
172 new RemoteCallbackList<INetworkManagementEventObserver>();
174 private final NetworkStatsFactory mStatsFactory = new NetworkStatsFactory();
176 private Object mQuotaLock = new Object();
177 /** Set of interfaces with active quotas. */
178 private HashMap<String, Long> mActiveQuotas = Maps.newHashMap();
179 /** Set of interfaces with active alerts. */
180 private HashMap<String, Long> mActiveAlerts = Maps.newHashMap();
181 /** Set of UIDs with active reject rules. */
182 private SparseBooleanArray mUidRejectOnQuota = new SparseBooleanArray();
184 private Object mIdleTimerLock = new Object();
185 /** Set of interfaces with active idle timers. */
186 private static class IdleTimerParams {
187 public final int timeout;
188 public final int type;
189 public int networkCount;
191 IdleTimerParams(int timeout, int type) {
192 this.timeout = timeout;
194 this.networkCount = 1;
197 private HashMap<String, IdleTimerParams> mActiveIdleTimers = Maps.newHashMap();
199 private volatile boolean mBandwidthControlEnabled;
200 private volatile boolean mFirewallEnabled;
202 private boolean mMobileActivityFromRadio = false;
203 private int mLastPowerStateFromRadio = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
205 private final RemoteCallbackList<INetworkActivityListener> mNetworkActivityListeners =
206 new RemoteCallbackList<INetworkActivityListener>();
207 private boolean mNetworkActive;
210 * Constructs a new NetworkManagementService instance
212 * @param context Binder context for this service
214 private NetworkManagementService(Context context, String socket) {
217 // make sure this is on the same looper as our NativeDaemonConnector for sync purposes
218 mFgHandler = new Handler(FgThread.get().getLooper());
220 if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
223 mDaemonHandler = null;
224 mPhoneStateListener = null;
228 // Don't need this wake lock, since we now have a time stamp for when
229 // the network actually went inactive. (It might be nice to still do this,
230 // but I don't want to do it through the power manager because that pollutes the
231 // battery stats history with pointless noise.)
232 //PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
233 PowerManager.WakeLock wl = null; //pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, NETD_TAG);
235 mConnector = new NativeDaemonConnector(
236 new NetdCallbackReceiver(), socket, 10, NETD_TAG, 160, wl,
237 FgThread.get().getLooper());
238 mThread = new Thread(mConnector, NETD_TAG);
240 mDaemonHandler = new Handler(FgThread.get().getLooper());
242 mPhoneStateListener = new PhoneStateListener(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
243 mDaemonHandler.getLooper()) {
245 public void onDataConnectionRealTimeInfoChanged(
246 DataConnectionRealTimeInfo dcRtInfo) {
247 if (DBG) Slog.d(TAG, "onDataConnectionRealTimeInfoChanged: " + dcRtInfo);
248 notifyInterfaceClassActivity(ConnectivityManager.TYPE_MOBILE,
249 dcRtInfo.getDcPowerState(), dcRtInfo.getTime(), true);
252 TelephonyManager tm = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
254 tm.listen(mPhoneStateListener,
255 PhoneStateListener.LISTEN_DATA_CONNECTION_REAL_TIME_INFO);
258 // Add ourself to the Watchdog monitors.
259 Watchdog.getInstance().addMonitor(this);
262 static NetworkManagementService create(Context context,
263 String socket) throws InterruptedException {
264 final NetworkManagementService service = new NetworkManagementService(context, socket);
265 final CountDownLatch connectedSignal = service.mConnectedSignal;
266 if (DBG) Slog.d(TAG, "Creating NetworkManagementService");
267 service.mThread.start();
268 if (DBG) Slog.d(TAG, "Awaiting socket connection");
269 connectedSignal.await();
270 if (DBG) Slog.d(TAG, "Connected");
274 public static NetworkManagementService create(Context context) throws InterruptedException {
275 return create(context, NETD_SOCKET_NAME);
278 public void systemReady() {
279 prepareNativeDaemon();
280 if (DBG) Slog.d(TAG, "Prepared");
283 private IBatteryStats getBatteryStats() {
284 synchronized (this) {
285 if (mBatteryStats != null) {
286 return mBatteryStats;
288 mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService(
289 BatteryStats.SERVICE_NAME));
290 return mBatteryStats;
295 public void registerObserver(INetworkManagementEventObserver observer) {
296 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
297 mObservers.register(observer);
301 public void unregisterObserver(INetworkManagementEventObserver observer) {
302 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
303 mObservers.unregister(observer);
307 * Notify our observers of an interface status change
309 private void notifyInterfaceStatusChanged(String iface, boolean up) {
310 final int length = mObservers.beginBroadcast();
312 for (int i = 0; i < length; i++) {
314 mObservers.getBroadcastItem(i).interfaceStatusChanged(iface, up);
315 } catch (RemoteException e) {
316 } catch (RuntimeException e) {
320 mObservers.finishBroadcast();
325 * Notify our observers of an interface link state change
326 * (typically, an Ethernet cable has been plugged-in or unplugged).
328 private void notifyInterfaceLinkStateChanged(String iface, boolean up) {
329 final int length = mObservers.beginBroadcast();
331 for (int i = 0; i < length; i++) {
333 mObservers.getBroadcastItem(i).interfaceLinkStateChanged(iface, up);
334 } catch (RemoteException e) {
335 } catch (RuntimeException e) {
339 mObservers.finishBroadcast();
344 * Notify our observers of an interface addition.
346 private void notifyInterfaceAdded(String iface) {
347 final int length = mObservers.beginBroadcast();
349 for (int i = 0; i < length; i++) {
351 mObservers.getBroadcastItem(i).interfaceAdded(iface);
352 } catch (RemoteException e) {
353 } catch (RuntimeException e) {
357 mObservers.finishBroadcast();
362 * Notify our observers of an interface removal.
364 private void notifyInterfaceRemoved(String iface) {
365 // netd already clears out quota and alerts for removed ifaces; update
366 // our sanity-checking state.
367 mActiveAlerts.remove(iface);
368 mActiveQuotas.remove(iface);
370 final int length = mObservers.beginBroadcast();
372 for (int i = 0; i < length; i++) {
374 mObservers.getBroadcastItem(i).interfaceRemoved(iface);
375 } catch (RemoteException e) {
376 } catch (RuntimeException e) {
380 mObservers.finishBroadcast();
385 * Notify our observers of a limit reached.
387 private void notifyLimitReached(String limitName, String iface) {
388 final int length = mObservers.beginBroadcast();
390 for (int i = 0; i < length; i++) {
392 mObservers.getBroadcastItem(i).limitReached(limitName, iface);
393 } catch (RemoteException e) {
394 } catch (RuntimeException e) {
398 mObservers.finishBroadcast();
403 * Notify our observers of a change in the data activity state of the interface
405 private void notifyInterfaceClassActivity(int type, int powerState, long tsNanos,
407 final boolean isMobile = ConnectivityManager.isNetworkTypeMobile(type);
410 if (mMobileActivityFromRadio) {
411 // If this call is not coming from a report from the radio itself, but we
412 // have previously received reports from the radio, then we will take the
413 // power state to just be whatever the radio last reported.
414 powerState = mLastPowerStateFromRadio;
417 mMobileActivityFromRadio = true;
419 if (mLastPowerStateFromRadio != powerState) {
420 mLastPowerStateFromRadio = powerState;
422 getBatteryStats().noteMobileRadioPowerState(powerState, tsNanos);
423 } catch (RemoteException e) {
428 boolean isActive = powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_MEDIUM
429 || powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH;
431 if (!isMobile || fromRadio || !mMobileActivityFromRadio) {
432 // Report the change in data activity. We don't do this if this is a change
433 // on the mobile network, that is not coming from the radio itself, and we
434 // have previously seen change reports from the radio. In that case only
435 // the radio is the authority for the current state.
436 final int length = mObservers.beginBroadcast();
438 for (int i = 0; i < length; i++) {
440 mObservers.getBroadcastItem(i).interfaceClassDataActivityChanged(
441 Integer.toString(type), isActive, tsNanos);
442 } catch (RemoteException e) {
443 } catch (RuntimeException e) {
447 mObservers.finishBroadcast();
451 boolean report = false;
452 synchronized (mIdleTimerLock) {
453 if (mActiveIdleTimers.isEmpty()) {
454 // If there are no idle timers, we are not monitoring activity, so we
455 // are always considered active.
458 if (mNetworkActive != isActive) {
459 mNetworkActive = isActive;
464 reportNetworkActive();
469 * Prepare native daemon once connected, enabling modules and pushing any
470 * existing in-memory rules.
472 private void prepareNativeDaemon() {
473 mBandwidthControlEnabled = false;
475 // only enable bandwidth control when support exists
476 final boolean hasKernelSupport = new File("/proc/net/xt_qtaguid/ctrl").exists();
477 if (hasKernelSupport) {
478 Slog.d(TAG, "enabling bandwidth control");
480 mConnector.execute("bandwidth", "enable");
481 mBandwidthControlEnabled = true;
482 } catch (NativeDaemonConnectorException e) {
483 Log.wtf(TAG, "problem enabling bandwidth controls", e);
486 Slog.d(TAG, "not enabling bandwidth control");
489 SystemProperties.set(PROP_QTAGUID_ENABLED, mBandwidthControlEnabled ? "1" : "0");
491 if (mBandwidthControlEnabled) {
493 getBatteryStats().noteNetworkStatsEnabled();
494 } catch (RemoteException e) {
498 // push any existing quota or UID rules
499 synchronized (mQuotaLock) {
500 int size = mActiveQuotas.size();
502 Slog.d(TAG, "pushing " + size + " active quota rules");
503 final HashMap<String, Long> activeQuotas = mActiveQuotas;
504 mActiveQuotas = Maps.newHashMap();
505 for (Map.Entry<String, Long> entry : activeQuotas.entrySet()) {
506 setInterfaceQuota(entry.getKey(), entry.getValue());
510 size = mActiveAlerts.size();
512 Slog.d(TAG, "pushing " + size + " active alert rules");
513 final HashMap<String, Long> activeAlerts = mActiveAlerts;
514 mActiveAlerts = Maps.newHashMap();
515 for (Map.Entry<String, Long> entry : activeAlerts.entrySet()) {
516 setInterfaceAlert(entry.getKey(), entry.getValue());
520 size = mUidRejectOnQuota.size();
522 Slog.d(TAG, "pushing " + size + " active uid rules");
523 final SparseBooleanArray uidRejectOnQuota = mUidRejectOnQuota;
524 mUidRejectOnQuota = new SparseBooleanArray();
525 for (int i = 0; i < uidRejectOnQuota.size(); i++) {
526 setUidNetworkRules(uidRejectOnQuota.keyAt(i), uidRejectOnQuota.valueAt(i));
531 // TODO: Push any existing firewall state
532 setFirewallEnabled(mFirewallEnabled || LockdownVpnTracker.isEnabled());
536 * Notify our observers of a new or updated interface address.
538 private void notifyAddressUpdated(String iface, LinkAddress address) {
539 final int length = mObservers.beginBroadcast();
541 for (int i = 0; i < length; i++) {
543 mObservers.getBroadcastItem(i).addressUpdated(iface, address);
544 } catch (RemoteException e) {
545 } catch (RuntimeException e) {
549 mObservers.finishBroadcast();
554 * Notify our observers of a deleted interface address.
556 private void notifyAddressRemoved(String iface, LinkAddress address) {
557 final int length = mObservers.beginBroadcast();
559 for (int i = 0; i < length; i++) {
561 mObservers.getBroadcastItem(i).addressRemoved(iface, address);
562 } catch (RemoteException e) {
563 } catch (RuntimeException e) {
567 mObservers.finishBroadcast();
572 * Notify our observers of DNS server information received.
574 private void notifyInterfaceDnsServerInfo(String iface, long lifetime, String[] addresses) {
575 final int length = mObservers.beginBroadcast();
577 for (int i = 0; i < length; i++) {
579 mObservers.getBroadcastItem(i).interfaceDnsServerInfo(iface, lifetime,
581 } catch (RemoteException e) {
582 } catch (RuntimeException e) {
586 mObservers.finishBroadcast();
591 * Notify our observers of a route change.
593 private void notifyRouteChange(String action, RouteInfo route) {
594 final int length = mObservers.beginBroadcast();
596 for (int i = 0; i < length; i++) {
598 if (action.equals("updated")) {
599 mObservers.getBroadcastItem(i).routeUpdated(route);
601 mObservers.getBroadcastItem(i).routeRemoved(route);
603 } catch (RemoteException e) {
604 } catch (RuntimeException e) {
608 mObservers.finishBroadcast();
613 // Netd Callback handling
616 private class NetdCallbackReceiver implements INativeDaemonConnectorCallbacks {
618 public void onDaemonConnected() {
619 // event is dispatched from internal NDC thread, so we prepare the
620 // daemon back on main thread.
621 if (mConnectedSignal != null) {
622 mConnectedSignal.countDown();
623 mConnectedSignal = null;
625 mFgHandler.post(new Runnable() {
628 prepareNativeDaemon();
635 public boolean onCheckHoldWakeLock(int code) {
636 return code == NetdResponseCode.InterfaceClassActivity;
640 public boolean onEvent(int code, String raw, String[] cooked) {
641 String errorMessage = String.format("Invalid event from daemon (%s)", raw);
643 case NetdResponseCode.InterfaceChange:
645 * a network interface change occured
646 * Format: "NNN Iface added <name>"
647 * "NNN Iface removed <name>"
648 * "NNN Iface changed <name> <up/down>"
649 * "NNN Iface linkstatus <name> <up/down>"
651 if (cooked.length < 4 || !cooked[1].equals("Iface")) {
652 throw new IllegalStateException(errorMessage);
654 if (cooked[2].equals("added")) {
655 notifyInterfaceAdded(cooked[3]);
657 } else if (cooked[2].equals("removed")) {
658 notifyInterfaceRemoved(cooked[3]);
660 } else if (cooked[2].equals("changed") && cooked.length == 5) {
661 notifyInterfaceStatusChanged(cooked[3], cooked[4].equals("up"));
663 } else if (cooked[2].equals("linkstate") && cooked.length == 5) {
664 notifyInterfaceLinkStateChanged(cooked[3], cooked[4].equals("up"));
667 throw new IllegalStateException(errorMessage);
669 case NetdResponseCode.BandwidthControl:
671 * Bandwidth control needs some attention
672 * Format: "NNN limit alert <alertName> <ifaceName>"
674 if (cooked.length < 5 || !cooked[1].equals("limit")) {
675 throw new IllegalStateException(errorMessage);
677 if (cooked[2].equals("alert")) {
678 notifyLimitReached(cooked[3], cooked[4]);
681 throw new IllegalStateException(errorMessage);
683 case NetdResponseCode.InterfaceClassActivity:
685 * An network interface class state changed (active/idle)
686 * Format: "NNN IfaceClass <active/idle> <label>"
688 if (cooked.length < 4 || !cooked[1].equals("IfaceClass")) {
689 throw new IllegalStateException(errorMessage);
691 long timestampNanos = 0;
692 if (cooked.length == 5) {
694 timestampNanos = Long.parseLong(cooked[4]);
695 } catch(NumberFormatException ne) {}
697 timestampNanos = SystemClock.elapsedRealtimeNanos();
699 boolean isActive = cooked[2].equals("active");
700 notifyInterfaceClassActivity(Integer.parseInt(cooked[3]),
701 isActive ? DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH
702 : DataConnectionRealTimeInfo.DC_POWER_STATE_LOW, timestampNanos, false);
705 case NetdResponseCode.InterfaceAddressChange:
707 * A network address change occurred
708 * Format: "NNN Address updated <addr> <iface> <flags> <scope>"
709 * "NNN Address removed <addr> <iface> <flags> <scope>"
711 if (cooked.length < 7 || !cooked[1].equals("Address")) {
712 throw new IllegalStateException(errorMessage);
715 String iface = cooked[4];
718 int flags = Integer.parseInt(cooked[5]);
719 int scope = Integer.parseInt(cooked[6]);
720 address = new LinkAddress(cooked[3], flags, scope);
721 } catch(NumberFormatException e) { // Non-numeric lifetime or scope.
722 throw new IllegalStateException(errorMessage, e);
723 } catch(IllegalArgumentException e) { // Malformed/invalid IP address.
724 throw new IllegalStateException(errorMessage, e);
727 if (cooked[2].equals("updated")) {
728 notifyAddressUpdated(iface, address);
730 notifyAddressRemoved(iface, address);
734 case NetdResponseCode.InterfaceDnsServerInfo:
736 * Information about available DNS servers has been received.
737 * Format: "NNN DnsInfo servers <interface> <lifetime> <servers>"
739 long lifetime; // Actually a 32-bit unsigned integer.
741 if (cooked.length == 6 &&
742 cooked[1].equals("DnsInfo") &&
743 cooked[2].equals("servers")) {
745 lifetime = Long.parseLong(cooked[4]);
746 } catch (NumberFormatException e) {
747 throw new IllegalStateException(errorMessage);
749 String[] servers = cooked[5].split(",");
750 notifyInterfaceDnsServerInfo(cooked[3], lifetime, servers);
754 case NetdResponseCode.RouteChange:
756 * A route has been updated or removed.
757 * Format: "NNN Route <updated|removed> <dst> [via <gateway] [dev <iface>]"
759 if (!cooked[1].equals("Route") || cooked.length < 6) {
760 throw new IllegalStateException(errorMessage);
765 boolean valid = true;
766 for (int i = 4; (i + 1) < cooked.length && valid; i += 2) {
767 if (cooked[i].equals("dev")) {
771 valid = false; // Duplicate interface.
773 } else if (cooked[i].equals("via")) {
777 valid = false; // Duplicate gateway.
780 valid = false; // Unknown syntax.
785 // InetAddress.parseNumericAddress(null) inexplicably returns ::1.
786 InetAddress gateway = null;
787 if (via != null) gateway = InetAddress.parseNumericAddress(via);
788 RouteInfo route = new RouteInfo(new IpPrefix(cooked[3]), gateway, dev);
789 notifyRouteChange(cooked[2], route);
791 } catch (IllegalArgumentException e) {}
793 throw new IllegalStateException(errorMessage);
803 // INetworkManagementService members
807 public String[] listInterfaces() {
808 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
810 return NativeDaemonEvent.filterMessageList(
811 mConnector.executeForList("interface", "list"), InterfaceListResult);
812 } catch (NativeDaemonConnectorException e) {
813 throw e.rethrowAsParcelableException();
818 public InterfaceConfiguration getInterfaceConfig(String iface) {
819 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
821 final NativeDaemonEvent event;
823 event = mConnector.execute("interface", "getcfg", iface);
824 } catch (NativeDaemonConnectorException e) {
825 throw e.rethrowAsParcelableException();
828 event.checkCode(InterfaceGetCfgResult);
830 // Rsp: 213 xx:xx:xx:xx:xx:xx yyy.yyy.yyy.yyy zzz flag1 flag2 flag3
831 final StringTokenizer st = new StringTokenizer(event.getMessage());
833 InterfaceConfiguration cfg;
835 cfg = new InterfaceConfiguration();
836 cfg.setHardwareAddress(st.nextToken(" "));
837 InetAddress addr = null;
838 int prefixLength = 0;
840 addr = NetworkUtils.numericToInetAddress(st.nextToken());
841 } catch (IllegalArgumentException iae) {
842 Slog.e(TAG, "Failed to parse ipaddr", iae);
846 prefixLength = Integer.parseInt(st.nextToken());
847 } catch (NumberFormatException nfe) {
848 Slog.e(TAG, "Failed to parse prefixLength", nfe);
851 cfg.setLinkAddress(new LinkAddress(addr, prefixLength));
852 while (st.hasMoreTokens()) {
853 cfg.setFlag(st.nextToken());
855 } catch (NoSuchElementException nsee) {
856 throw new IllegalStateException("Invalid response from daemon: " + event);
862 public void setInterfaceConfig(String iface, InterfaceConfiguration cfg) {
863 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
864 LinkAddress linkAddr = cfg.getLinkAddress();
865 if (linkAddr == null || linkAddr.getAddress() == null) {
866 throw new IllegalStateException("Null LinkAddress given");
869 final Command cmd = new Command("interface", "setcfg", iface,
870 linkAddr.getAddress().getHostAddress(),
871 linkAddr.getPrefixLength());
872 for (String flag : cfg.getFlags()) {
877 mConnector.execute(cmd);
878 } catch (NativeDaemonConnectorException e) {
879 throw e.rethrowAsParcelableException();
884 public void setInterfaceDown(String iface) {
885 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
886 final InterfaceConfiguration ifcg = getInterfaceConfig(iface);
887 ifcg.setInterfaceDown();
888 setInterfaceConfig(iface, ifcg);
892 public void setInterfaceUp(String iface) {
893 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
894 final InterfaceConfiguration ifcg = getInterfaceConfig(iface);
895 ifcg.setInterfaceUp();
896 setInterfaceConfig(iface, ifcg);
900 public void setInterfaceIpv6PrivacyExtensions(String iface, boolean enable) {
901 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
904 "interface", "ipv6privacyextensions", iface, enable ? "enable" : "disable");
905 } catch (NativeDaemonConnectorException e) {
906 throw e.rethrowAsParcelableException();
910 /* TODO: This is right now a IPv4 only function. Works for wifi which loses its
911 IPv6 addresses on interface down, but we need to do full clean up here */
913 public void clearInterfaceAddresses(String iface) {
914 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
916 mConnector.execute("interface", "clearaddrs", iface);
917 } catch (NativeDaemonConnectorException e) {
918 throw e.rethrowAsParcelableException();
923 public void enableIpv6(String iface) {
924 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
926 mConnector.execute("interface", "ipv6", iface, "enable");
927 } catch (NativeDaemonConnectorException e) {
928 throw e.rethrowAsParcelableException();
933 public void disableIpv6(String iface) {
934 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
936 mConnector.execute("interface", "ipv6", iface, "disable");
937 } catch (NativeDaemonConnectorException e) {
938 throw e.rethrowAsParcelableException();
943 public void setInterfaceIpv6NdOffload(String iface, boolean enable) {
944 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
947 "interface", "ipv6ndoffload", iface, (enable ? "enable" : "disable"));
948 } catch (NativeDaemonConnectorException e) {
949 throw e.rethrowAsParcelableException();
954 public void addRoute(int netId, RouteInfo route) {
955 modifyRoute("add", "" + netId, route);
959 public void removeRoute(int netId, RouteInfo route) {
960 modifyRoute("remove", "" + netId, route);
963 private void modifyRoute(String action, String netId, RouteInfo route) {
964 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
966 final Command cmd = new Command("network", "route", action, netId);
968 // create triplet: interface dest-ip-addr/prefixlength gateway-ip-addr
969 cmd.appendArg(route.getInterface());
970 cmd.appendArg(route.getDestination().toString());
972 switch (route.getType()) {
973 case RouteInfo.RTN_UNICAST:
974 if (route.hasGateway()) {
975 cmd.appendArg(route.getGateway().getHostAddress());
978 case RouteInfo.RTN_UNREACHABLE:
979 cmd.appendArg("unreachable");
981 case RouteInfo.RTN_THROW:
982 cmd.appendArg("throw");
987 mConnector.execute(cmd);
988 } catch (NativeDaemonConnectorException e) {
989 throw e.rethrowAsParcelableException();
993 private ArrayList<String> readRouteList(String filename) {
994 FileInputStream fstream = null;
995 ArrayList<String> list = new ArrayList<String>();
998 fstream = new FileInputStream(filename);
999 DataInputStream in = new DataInputStream(fstream);
1000 BufferedReader br = new BufferedReader(new InputStreamReader(in));
1003 // throw away the title line
1005 while (((s = br.readLine()) != null) && (s.length() != 0)) {
1008 } catch (IOException ex) {
1009 // return current list, possibly empty
1011 if (fstream != null) {
1014 } catch (IOException ex) {}
1022 public RouteInfo[] getRoutes(String interfaceName) {
1023 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1024 ArrayList<RouteInfo> routes = new ArrayList<RouteInfo>();
1026 // v4 routes listed as:
1027 // iface dest-addr gateway-addr flags refcnt use metric netmask mtu window IRTT
1028 for (String s : readRouteList("/proc/net/route")) {
1029 String[] fields = s.split("\t");
1031 if (fields.length > 7) {
1032 String iface = fields[0];
1034 if (interfaceName.equals(iface)) {
1035 String dest = fields[1];
1036 String gate = fields[2];
1037 String flags = fields[3]; // future use?
1038 String mask = fields[7];
1040 // address stored as a hex string, ex: 0014A8C0
1041 InetAddress destAddr =
1042 NetworkUtils.intToInetAddress((int)Long.parseLong(dest, 16));
1044 NetworkUtils.netmaskIntToPrefixLength(
1045 (int)Long.parseLong(mask, 16));
1046 LinkAddress linkAddress = new LinkAddress(destAddr, prefixLength);
1048 // address stored as a hex string, ex 0014A8C0
1049 InetAddress gatewayAddr =
1050 NetworkUtils.intToInetAddress((int)Long.parseLong(gate, 16));
1052 RouteInfo route = new RouteInfo(linkAddress, gatewayAddr);
1054 } catch (Exception e) {
1055 Log.e(TAG, "Error parsing route " + s + " : " + e);
1062 // v6 routes listed as:
1063 // dest-addr prefixlength ?? ?? gateway-addr ?? ?? ?? ?? iface
1064 for (String s : readRouteList("/proc/net/ipv6_route")) {
1065 String[]fields = s.split("\\s+");
1066 if (fields.length > 9) {
1067 String iface = fields[9].trim();
1068 if (interfaceName.equals(iface)) {
1069 String dest = fields[0];
1070 String prefix = fields[1];
1071 String gate = fields[4];
1074 // prefix length stored as a hex string, ex 40
1075 int prefixLength = Integer.parseInt(prefix, 16);
1077 // address stored as a 32 char hex string
1078 // ex fe800000000000000000000000000000
1079 InetAddress destAddr = NetworkUtils.hexToInet6Address(dest);
1080 LinkAddress linkAddress = new LinkAddress(destAddr, prefixLength);
1082 InetAddress gateAddr = NetworkUtils.hexToInet6Address(gate);
1084 RouteInfo route = new RouteInfo(linkAddress, gateAddr);
1086 } catch (Exception e) {
1087 Log.e(TAG, "Error parsing route " + s + " : " + e);
1093 return routes.toArray(new RouteInfo[routes.size()]);
1097 public void setMtu(String iface, int mtu) {
1098 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1100 final NativeDaemonEvent event;
1102 event = mConnector.execute("interface", "setmtu", iface, mtu);
1103 } catch (NativeDaemonConnectorException e) {
1104 throw e.rethrowAsParcelableException();
1109 public void shutdown() {
1110 // TODO: remove from aidl if nobody calls externally
1111 mContext.enforceCallingOrSelfPermission(SHUTDOWN, TAG);
1113 Slog.d(TAG, "Shutting down");
1117 public boolean getIpForwardingEnabled() throws IllegalStateException{
1118 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1120 final NativeDaemonEvent event;
1122 event = mConnector.execute("ipfwd", "status");
1123 } catch (NativeDaemonConnectorException e) {
1124 throw e.rethrowAsParcelableException();
1127 // 211 Forwarding enabled
1128 event.checkCode(IpFwdStatusResult);
1129 return event.getMessage().endsWith("enabled");
1133 public void setIpForwardingEnabled(boolean enable) {
1134 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1136 mConnector.execute("ipfwd", enable ? "enable" : "disable");
1137 } catch (NativeDaemonConnectorException e) {
1138 throw e.rethrowAsParcelableException();
1143 public void startTethering(String[] dhcpRange) {
1144 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1145 // cmd is "tether start first_start first_stop second_start second_stop ..."
1146 // an odd number of addrs will fail
1148 final Command cmd = new Command("tether", "start");
1149 for (String d : dhcpRange) {
1154 mConnector.execute(cmd);
1155 } catch (NativeDaemonConnectorException e) {
1156 throw e.rethrowAsParcelableException();
1161 public void stopTethering() {
1162 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1164 mConnector.execute("tether", "stop");
1165 } catch (NativeDaemonConnectorException e) {
1166 throw e.rethrowAsParcelableException();
1171 public boolean isTetheringStarted() {
1172 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1174 final NativeDaemonEvent event;
1176 event = mConnector.execute("tether", "status");
1177 } catch (NativeDaemonConnectorException e) {
1178 throw e.rethrowAsParcelableException();
1181 // 210 Tethering services started
1182 event.checkCode(TetherStatusResult);
1183 return event.getMessage().endsWith("started");
1187 public void tetherInterface(String iface) {
1188 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1190 mConnector.execute("tether", "interface", "add", iface);
1191 } catch (NativeDaemonConnectorException e) {
1192 throw e.rethrowAsParcelableException();
1194 List<RouteInfo> routes = new ArrayList<RouteInfo>();
1195 // The RouteInfo constructor truncates the LinkAddress to a network prefix, thus making it
1196 // suitable to use as a route destination.
1197 routes.add(new RouteInfo(getInterfaceConfig(iface).getLinkAddress(), null, iface));
1198 addInterfaceToLocalNetwork(iface, routes);
1202 public void untetherInterface(String iface) {
1203 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1205 mConnector.execute("tether", "interface", "remove", iface);
1206 } catch (NativeDaemonConnectorException e) {
1207 throw e.rethrowAsParcelableException();
1209 removeInterfaceFromLocalNetwork(iface);
1213 public String[] listTetheredInterfaces() {
1214 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1216 return NativeDaemonEvent.filterMessageList(
1217 mConnector.executeForList("tether", "interface", "list"),
1218 TetherInterfaceListResult);
1219 } catch (NativeDaemonConnectorException e) {
1220 throw e.rethrowAsParcelableException();
1225 public void setDnsForwarders(Network network, String[] dns) {
1226 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1228 int netId = (network != null) ? network.netId : ConnectivityManager.NETID_UNSET;
1229 final Command cmd = new Command("tether", "dns", "set", netId);
1231 for (String s : dns) {
1232 cmd.appendArg(NetworkUtils.numericToInetAddress(s).getHostAddress());
1236 mConnector.execute(cmd);
1237 } catch (NativeDaemonConnectorException e) {
1238 throw e.rethrowAsParcelableException();
1243 public String[] getDnsForwarders() {
1244 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1246 return NativeDaemonEvent.filterMessageList(
1247 mConnector.executeForList("tether", "dns", "list"), TetherDnsFwdTgtListResult);
1248 } catch (NativeDaemonConnectorException e) {
1249 throw e.rethrowAsParcelableException();
1253 private List<InterfaceAddress> excludeLinkLocal(List<InterfaceAddress> addresses) {
1254 ArrayList<InterfaceAddress> filtered = new ArrayList<InterfaceAddress>(addresses.size());
1255 for (InterfaceAddress ia : addresses) {
1256 if (!ia.getAddress().isLinkLocalAddress())
1262 private void modifyNat(String action, String internalInterface, String externalInterface)
1263 throws SocketException {
1264 final Command cmd = new Command("nat", action, internalInterface, externalInterface);
1266 final NetworkInterface internalNetworkInterface = NetworkInterface.getByName(
1268 if (internalNetworkInterface == null) {
1271 // Don't touch link-local routes, as link-local addresses aren't routable,
1272 // kernel creates link-local routes on all interfaces automatically
1273 List<InterfaceAddress> interfaceAddresses = excludeLinkLocal(
1274 internalNetworkInterface.getInterfaceAddresses());
1275 cmd.appendArg(interfaceAddresses.size());
1276 for (InterfaceAddress ia : interfaceAddresses) {
1277 InetAddress addr = NetworkUtils.getNetworkPart(
1278 ia.getAddress(), ia.getNetworkPrefixLength());
1279 cmd.appendArg(addr.getHostAddress() + "/" + ia.getNetworkPrefixLength());
1284 mConnector.execute(cmd);
1285 } catch (NativeDaemonConnectorException e) {
1286 throw e.rethrowAsParcelableException();
1291 public void enableNat(String internalInterface, String externalInterface) {
1292 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1294 modifyNat("enable", internalInterface, externalInterface);
1295 } catch (SocketException e) {
1296 throw new IllegalStateException(e);
1301 public void disableNat(String internalInterface, String externalInterface) {
1302 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1304 modifyNat("disable", internalInterface, externalInterface);
1305 } catch (SocketException e) {
1306 throw new IllegalStateException(e);
1311 public String[] listTtys() {
1312 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1314 return NativeDaemonEvent.filterMessageList(
1315 mConnector.executeForList("list_ttys"), TtyListResult);
1316 } catch (NativeDaemonConnectorException e) {
1317 throw e.rethrowAsParcelableException();
1322 public void attachPppd(
1323 String tty, String localAddr, String remoteAddr, String dns1Addr, String dns2Addr) {
1324 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1326 mConnector.execute("pppd", "attach", tty,
1327 NetworkUtils.numericToInetAddress(localAddr).getHostAddress(),
1328 NetworkUtils.numericToInetAddress(remoteAddr).getHostAddress(),
1329 NetworkUtils.numericToInetAddress(dns1Addr).getHostAddress(),
1330 NetworkUtils.numericToInetAddress(dns2Addr).getHostAddress());
1331 } catch (NativeDaemonConnectorException e) {
1332 throw e.rethrowAsParcelableException();
1337 public void detachPppd(String tty) {
1338 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1340 mConnector.execute("pppd", "detach", tty);
1341 } catch (NativeDaemonConnectorException e) {
1342 throw e.rethrowAsParcelableException();
1347 public void startAccessPoint(
1348 WifiConfiguration wifiConfig, String wlanIface) {
1349 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1351 wifiFirmwareReload(wlanIface, "AP");
1352 if (wifiConfig == null) {
1353 mConnector.execute("softap", "set", wlanIface);
1355 mConnector.execute("softap", "set", wlanIface, wifiConfig.SSID,
1356 "broadcast", "6", getSecurityType(wifiConfig),
1357 new SensitiveArg(wifiConfig.preSharedKey));
1359 mConnector.execute("softap", "startap");
1360 } catch (NativeDaemonConnectorException e) {
1361 throw e.rethrowAsParcelableException();
1365 private static String getSecurityType(WifiConfiguration wifiConfig) {
1366 switch (wifiConfig.getAuthType()) {
1367 case KeyMgmt.WPA_PSK:
1369 case KeyMgmt.WPA2_PSK:
1376 /* @param mode can be "AP", "STA" or "P2P" */
1378 public void wifiFirmwareReload(String wlanIface, String mode) {
1379 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1381 mConnector.execute("softap", "fwreload", wlanIface, mode);
1382 } catch (NativeDaemonConnectorException e) {
1383 throw e.rethrowAsParcelableException();
1388 public void stopAccessPoint(String wlanIface) {
1389 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1391 mConnector.execute("softap", "stopap");
1392 wifiFirmwareReload(wlanIface, "STA");
1393 } catch (NativeDaemonConnectorException e) {
1394 throw e.rethrowAsParcelableException();
1399 public void setAccessPoint(WifiConfiguration wifiConfig, String wlanIface) {
1400 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1402 if (wifiConfig == null) {
1403 mConnector.execute("softap", "set", wlanIface);
1405 mConnector.execute("softap", "set", wlanIface, wifiConfig.SSID,
1406 "broadcast", "6", getSecurityType(wifiConfig),
1407 new SensitiveArg(wifiConfig.preSharedKey));
1409 } catch (NativeDaemonConnectorException e) {
1410 throw e.rethrowAsParcelableException();
1415 public void addIdleTimer(String iface, int timeout, final int type) {
1416 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1418 if (DBG) Slog.d(TAG, "Adding idletimer");
1420 synchronized (mIdleTimerLock) {
1421 IdleTimerParams params = mActiveIdleTimers.get(iface);
1422 if (params != null) {
1423 // the interface already has idletimer, update network count
1424 params.networkCount++;
1429 mConnector.execute("idletimer", "add", iface, Integer.toString(timeout),
1430 Integer.toString(type));
1431 } catch (NativeDaemonConnectorException e) {
1432 throw e.rethrowAsParcelableException();
1434 mActiveIdleTimers.put(iface, new IdleTimerParams(timeout, type));
1436 // Networks start up.
1437 if (ConnectivityManager.isNetworkTypeMobile(type)) {
1438 mNetworkActive = false;
1440 mDaemonHandler.post(new Runnable() {
1441 @Override public void run() {
1442 notifyInterfaceClassActivity(type,
1443 DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH,
1444 SystemClock.elapsedRealtimeNanos(), false);
1451 public void removeIdleTimer(String iface) {
1452 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1454 if (DBG) Slog.d(TAG, "Removing idletimer");
1456 synchronized (mIdleTimerLock) {
1457 final IdleTimerParams params = mActiveIdleTimers.get(iface);
1458 if (params == null || --(params.networkCount) > 0) {
1463 mConnector.execute("idletimer", "remove", iface,
1464 Integer.toString(params.timeout), Integer.toString(params.type));
1465 } catch (NativeDaemonConnectorException e) {
1466 throw e.rethrowAsParcelableException();
1468 mActiveIdleTimers.remove(iface);
1469 mDaemonHandler.post(new Runnable() {
1470 @Override public void run() {
1471 notifyInterfaceClassActivity(params.type,
1472 DataConnectionRealTimeInfo.DC_POWER_STATE_LOW,
1473 SystemClock.elapsedRealtimeNanos(), false);
1480 public NetworkStats getNetworkStatsSummaryDev() {
1481 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1483 return mStatsFactory.readNetworkStatsSummaryDev();
1484 } catch (IOException e) {
1485 throw new IllegalStateException(e);
1490 public NetworkStats getNetworkStatsSummaryXt() {
1491 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1493 return mStatsFactory.readNetworkStatsSummaryXt();
1494 } catch (IOException e) {
1495 throw new IllegalStateException(e);
1500 public NetworkStats getNetworkStatsDetail() {
1501 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1503 return mStatsFactory.readNetworkStatsDetail(UID_ALL, null, TAG_ALL, null);
1504 } catch (IOException e) {
1505 throw new IllegalStateException(e);
1510 public void setInterfaceQuota(String iface, long quotaBytes) {
1511 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1513 // silently discard when control disabled
1514 // TODO: eventually migrate to be always enabled
1515 if (!mBandwidthControlEnabled) return;
1517 synchronized (mQuotaLock) {
1518 if (mActiveQuotas.containsKey(iface)) {
1519 throw new IllegalStateException("iface " + iface + " already has quota");
1523 // TODO: support quota shared across interfaces
1524 mConnector.execute("bandwidth", "setiquota", iface, quotaBytes);
1525 mActiveQuotas.put(iface, quotaBytes);
1526 } catch (NativeDaemonConnectorException e) {
1527 throw e.rethrowAsParcelableException();
1533 public void removeInterfaceQuota(String iface) {
1534 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1536 // silently discard when control disabled
1537 // TODO: eventually migrate to be always enabled
1538 if (!mBandwidthControlEnabled) return;
1540 synchronized (mQuotaLock) {
1541 if (!mActiveQuotas.containsKey(iface)) {
1542 // TODO: eventually consider throwing
1546 mActiveQuotas.remove(iface);
1547 mActiveAlerts.remove(iface);
1550 // TODO: support quota shared across interfaces
1551 mConnector.execute("bandwidth", "removeiquota", iface);
1552 } catch (NativeDaemonConnectorException e) {
1553 throw e.rethrowAsParcelableException();
1559 public void setInterfaceAlert(String iface, long alertBytes) {
1560 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1562 // silently discard when control disabled
1563 // TODO: eventually migrate to be always enabled
1564 if (!mBandwidthControlEnabled) return;
1566 // quick sanity check
1567 if (!mActiveQuotas.containsKey(iface)) {
1568 throw new IllegalStateException("setting alert requires existing quota on iface");
1571 synchronized (mQuotaLock) {
1572 if (mActiveAlerts.containsKey(iface)) {
1573 throw new IllegalStateException("iface " + iface + " already has alert");
1577 // TODO: support alert shared across interfaces
1578 mConnector.execute("bandwidth", "setinterfacealert", iface, alertBytes);
1579 mActiveAlerts.put(iface, alertBytes);
1580 } catch (NativeDaemonConnectorException e) {
1581 throw e.rethrowAsParcelableException();
1587 public void removeInterfaceAlert(String iface) {
1588 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1590 // silently discard when control disabled
1591 // TODO: eventually migrate to be always enabled
1592 if (!mBandwidthControlEnabled) return;
1594 synchronized (mQuotaLock) {
1595 if (!mActiveAlerts.containsKey(iface)) {
1596 // TODO: eventually consider throwing
1601 // TODO: support alert shared across interfaces
1602 mConnector.execute("bandwidth", "removeinterfacealert", iface);
1603 mActiveAlerts.remove(iface);
1604 } catch (NativeDaemonConnectorException e) {
1605 throw e.rethrowAsParcelableException();
1611 public void setGlobalAlert(long alertBytes) {
1612 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1614 // silently discard when control disabled
1615 // TODO: eventually migrate to be always enabled
1616 if (!mBandwidthControlEnabled) return;
1619 mConnector.execute("bandwidth", "setglobalalert", alertBytes);
1620 } catch (NativeDaemonConnectorException e) {
1621 throw e.rethrowAsParcelableException();
1626 public void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces) {
1627 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1629 // silently discard when control disabled
1630 // TODO: eventually migrate to be always enabled
1631 if (!mBandwidthControlEnabled) return;
1633 synchronized (mQuotaLock) {
1634 final boolean oldRejectOnQuota = mUidRejectOnQuota.get(uid, false);
1635 if (oldRejectOnQuota == rejectOnQuotaInterfaces) {
1636 // TODO: eventually consider throwing
1641 mConnector.execute("bandwidth",
1642 rejectOnQuotaInterfaces ? "addnaughtyapps" : "removenaughtyapps", uid);
1643 if (rejectOnQuotaInterfaces) {
1644 mUidRejectOnQuota.put(uid, true);
1646 mUidRejectOnQuota.delete(uid);
1648 } catch (NativeDaemonConnectorException e) {
1649 throw e.rethrowAsParcelableException();
1655 public boolean isBandwidthControlEnabled() {
1656 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1657 return mBandwidthControlEnabled;
1661 public NetworkStats getNetworkStatsUidDetail(int uid) {
1662 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1664 return mStatsFactory.readNetworkStatsDetail(uid, null, TAG_ALL, null);
1665 } catch (IOException e) {
1666 throw new IllegalStateException(e);
1671 public NetworkStats getNetworkStatsTethering() {
1672 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1674 final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1);
1676 final NativeDaemonEvent[] events = mConnector.executeForList(
1677 "bandwidth", "gettetherstats");
1678 for (NativeDaemonEvent event : events) {
1679 if (event.getCode() != TetheringStatsListResult) continue;
1681 // 114 ifaceIn ifaceOut rx_bytes rx_packets tx_bytes tx_packets
1682 final StringTokenizer tok = new StringTokenizer(event.getMessage());
1684 final String ifaceIn = tok.nextToken();
1685 final String ifaceOut = tok.nextToken();
1687 final NetworkStats.Entry entry = new NetworkStats.Entry();
1688 entry.iface = ifaceOut;
1689 entry.uid = UID_TETHERING;
1690 entry.set = SET_DEFAULT;
1691 entry.tag = TAG_NONE;
1692 entry.rxBytes = Long.parseLong(tok.nextToken());
1693 entry.rxPackets = Long.parseLong(tok.nextToken());
1694 entry.txBytes = Long.parseLong(tok.nextToken());
1695 entry.txPackets = Long.parseLong(tok.nextToken());
1696 stats.combineValues(entry);
1697 } catch (NoSuchElementException e) {
1698 throw new IllegalStateException("problem parsing tethering stats: " + event);
1699 } catch (NumberFormatException e) {
1700 throw new IllegalStateException("problem parsing tethering stats: " + event);
1703 } catch (NativeDaemonConnectorException e) {
1704 throw e.rethrowAsParcelableException();
1710 public void setDnsServersForNetwork(int netId, String[] servers, String domains) {
1711 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1713 final Command cmd = new Command("resolver", "setnetdns", netId,
1714 (domains == null ? "" : domains));
1716 for (String s : servers) {
1717 InetAddress a = NetworkUtils.numericToInetAddress(s);
1718 if (a.isAnyLocalAddress() == false) {
1719 cmd.appendArg(a.getHostAddress());
1724 mConnector.execute(cmd);
1725 } catch (NativeDaemonConnectorException e) {
1726 throw e.rethrowAsParcelableException();
1731 public void addVpnUidRanges(int netId, UidRange[] ranges) {
1732 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1733 Object[] argv = new Object[3 + MAX_UID_RANGES_PER_COMMAND];
1738 // Avoid overly long commands by limiting number of UID ranges per command.
1739 for (int i = 0; i < ranges.length; i++) {
1740 argv[argc++] = ranges[i].toString();
1741 if (i == (ranges.length - 1) || argc == argv.length) {
1743 mConnector.execute("network", Arrays.copyOf(argv, argc));
1744 } catch (NativeDaemonConnectorException e) {
1745 throw e.rethrowAsParcelableException();
1753 public void removeVpnUidRanges(int netId, UidRange[] ranges) {
1754 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1755 Object[] argv = new Object[3 + MAX_UID_RANGES_PER_COMMAND];
1760 // Avoid overly long commands by limiting number of UID ranges per command.
1761 for (int i = 0; i < ranges.length; i++) {
1762 argv[argc++] = ranges[i].toString();
1763 if (i == (ranges.length - 1) || argc == argv.length) {
1765 mConnector.execute("network", Arrays.copyOf(argv, argc));
1766 } catch (NativeDaemonConnectorException e) {
1767 throw e.rethrowAsParcelableException();
1775 public void flushNetworkDnsCache(int netId) {
1776 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1778 mConnector.execute("resolver", "flushnet", netId);
1779 } catch (NativeDaemonConnectorException e) {
1780 throw e.rethrowAsParcelableException();
1785 public void setFirewallEnabled(boolean enabled) {
1788 mConnector.execute("firewall", enabled ? "enable" : "disable");
1789 mFirewallEnabled = enabled;
1790 } catch (NativeDaemonConnectorException e) {
1791 throw e.rethrowAsParcelableException();
1796 public boolean isFirewallEnabled() {
1798 return mFirewallEnabled;
1802 public void setFirewallInterfaceRule(String iface, boolean allow) {
1804 Preconditions.checkState(mFirewallEnabled);
1805 final String rule = allow ? "allow" : "deny";
1807 mConnector.execute("firewall", "set_interface_rule", iface, rule);
1808 } catch (NativeDaemonConnectorException e) {
1809 throw e.rethrowAsParcelableException();
1814 public void setFirewallEgressSourceRule(String addr, boolean allow) {
1816 Preconditions.checkState(mFirewallEnabled);
1817 final String rule = allow ? "allow" : "deny";
1819 mConnector.execute("firewall", "set_egress_source_rule", addr, rule);
1820 } catch (NativeDaemonConnectorException e) {
1821 throw e.rethrowAsParcelableException();
1826 public void setFirewallEgressDestRule(String addr, int port, boolean allow) {
1828 Preconditions.checkState(mFirewallEnabled);
1829 final String rule = allow ? "allow" : "deny";
1831 mConnector.execute("firewall", "set_egress_dest_rule", addr, port, rule);
1832 } catch (NativeDaemonConnectorException e) {
1833 throw e.rethrowAsParcelableException();
1838 public void setFirewallUidRule(int uid, boolean allow) {
1840 Preconditions.checkState(mFirewallEnabled);
1841 final String rule = allow ? "allow" : "deny";
1843 mConnector.execute("firewall", "set_uid_rule", uid, rule);
1844 } catch (NativeDaemonConnectorException e) {
1845 throw e.rethrowAsParcelableException();
1849 private static void enforceSystemUid() {
1850 final int uid = Binder.getCallingUid();
1851 if (uid != Process.SYSTEM_UID) {
1852 throw new SecurityException("Only available to AID_SYSTEM");
1857 public void startClatd(String interfaceName) throws IllegalStateException {
1858 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1861 mConnector.execute("clatd", "start", interfaceName);
1862 } catch (NativeDaemonConnectorException e) {
1863 throw e.rethrowAsParcelableException();
1868 public void stopClatd(String interfaceName) throws IllegalStateException {
1869 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1872 mConnector.execute("clatd", "stop", interfaceName);
1873 } catch (NativeDaemonConnectorException e) {
1874 throw e.rethrowAsParcelableException();
1879 public boolean isClatdStarted(String interfaceName) {
1880 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1882 final NativeDaemonEvent event;
1884 event = mConnector.execute("clatd", "status", interfaceName);
1885 } catch (NativeDaemonConnectorException e) {
1886 throw e.rethrowAsParcelableException();
1889 event.checkCode(ClatdStatusResult);
1890 return event.getMessage().endsWith("started");
1894 public void registerNetworkActivityListener(INetworkActivityListener listener) {
1895 mNetworkActivityListeners.register(listener);
1899 public void unregisterNetworkActivityListener(INetworkActivityListener listener) {
1900 mNetworkActivityListeners.unregister(listener);
1904 public boolean isNetworkActive() {
1905 synchronized (mNetworkActivityListeners) {
1906 return mNetworkActive || mActiveIdleTimers.isEmpty();
1910 private void reportNetworkActive() {
1911 final int length = mNetworkActivityListeners.beginBroadcast();
1913 for (int i = 0; i < length; i++) {
1915 mNetworkActivityListeners.getBroadcastItem(i).onNetworkActive();
1916 } catch (RemoteException e) {
1917 } catch (RuntimeException e) {
1921 mNetworkActivityListeners.finishBroadcast();
1925 /** {@inheritDoc} */
1927 public void monitor() {
1928 if (mConnector != null) {
1929 mConnector.monitor();
1934 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1935 mContext.enforceCallingOrSelfPermission(DUMP, TAG);
1937 pw.println("NetworkManagementService NativeDaemonConnector Log:");
1938 mConnector.dump(fd, pw, args);
1941 pw.print("Bandwidth control enabled: "); pw.println(mBandwidthControlEnabled);
1942 pw.print("mMobileActivityFromRadio="); pw.print(mMobileActivityFromRadio);
1943 pw.print(" mLastPowerStateFromRadio="); pw.println(mLastPowerStateFromRadio);
1944 pw.print("mNetworkActive="); pw.println(mNetworkActive);
1946 synchronized (mQuotaLock) {
1947 pw.print("Active quota ifaces: "); pw.println(mActiveQuotas.toString());
1948 pw.print("Active alert ifaces: "); pw.println(mActiveAlerts.toString());
1951 synchronized (mUidRejectOnQuota) {
1952 pw.print("UID reject on quota ifaces: [");
1953 final int size = mUidRejectOnQuota.size();
1954 for (int i = 0; i < size; i++) {
1955 pw.print(mUidRejectOnQuota.keyAt(i));
1956 if (i < size - 1) pw.print(",");
1961 synchronized (mIdleTimerLock) {
1962 pw.println("Idle timers:");
1963 for (HashMap.Entry<String, IdleTimerParams> ent : mActiveIdleTimers.entrySet()) {
1964 pw.print(" "); pw.print(ent.getKey()); pw.println(":");
1965 IdleTimerParams params = ent.getValue();
1966 pw.print(" timeout="); pw.print(params.timeout);
1967 pw.print(" type="); pw.print(params.type);
1968 pw.print(" networkCount="); pw.println(params.networkCount);
1972 pw.print("Firewall enabled: "); pw.println(mFirewallEnabled);
1976 public void createPhysicalNetwork(int netId) {
1977 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1980 mConnector.execute("network", "create", netId);
1981 } catch (NativeDaemonConnectorException e) {
1982 throw e.rethrowAsParcelableException();
1987 public void createVirtualNetwork(int netId, boolean hasDNS, boolean secure) {
1988 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1991 mConnector.execute("network", "create", netId, "vpn", hasDNS ? "1" : "0",
1992 secure ? "1" : "0");
1993 } catch (NativeDaemonConnectorException e) {
1994 throw e.rethrowAsParcelableException();
1999 public void removeNetwork(int netId) {
2000 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2003 mConnector.execute("network", "destroy", netId);
2004 } catch (NativeDaemonConnectorException e) {
2005 throw e.rethrowAsParcelableException();
2010 public void addInterfaceToNetwork(String iface, int netId) {
2011 modifyInterfaceInNetwork("add", "" + netId, iface);
2015 public void removeInterfaceFromNetwork(String iface, int netId) {
2016 modifyInterfaceInNetwork("remove", "" + netId, iface);
2019 private void modifyInterfaceInNetwork(String action, String netId, String iface) {
2020 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2022 mConnector.execute("network", "interface", action, netId, iface);
2023 } catch (NativeDaemonConnectorException e) {
2024 throw e.rethrowAsParcelableException();
2029 public void addLegacyRouteForNetId(int netId, RouteInfo routeInfo, int uid) {
2030 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2032 final Command cmd = new Command("network", "route", "legacy", uid, "add", netId);
2034 // create triplet: interface dest-ip-addr/prefixlength gateway-ip-addr
2035 final LinkAddress la = routeInfo.getDestinationLinkAddress();
2036 cmd.appendArg(routeInfo.getInterface());
2037 cmd.appendArg(la.getAddress().getHostAddress() + "/" + la.getPrefixLength());
2038 if (routeInfo.hasGateway()) {
2039 cmd.appendArg(routeInfo.getGateway().getHostAddress());
2043 mConnector.execute(cmd);
2044 } catch (NativeDaemonConnectorException e) {
2045 throw e.rethrowAsParcelableException();
2050 public void setDefaultNetId(int netId) {
2051 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2054 mConnector.execute("network", "default", "set", netId);
2055 } catch (NativeDaemonConnectorException e) {
2056 throw e.rethrowAsParcelableException();
2061 public void clearDefaultNetId() {
2062 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2065 mConnector.execute("network", "default", "clear");
2066 } catch (NativeDaemonConnectorException e) {
2067 throw e.rethrowAsParcelableException();
2072 public void setPermission(String permission, int[] uids) {
2073 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2075 Object[] argv = new Object[4 + MAX_UID_RANGES_PER_COMMAND];
2076 argv[0] = "permission";
2079 argv[3] = permission;
2081 // Avoid overly long commands by limiting number of UIDs per command.
2082 for (int i = 0; i < uids.length; ++i) {
2083 argv[argc++] = uids[i];
2084 if (i == uids.length - 1 || argc == argv.length) {
2086 mConnector.execute("network", Arrays.copyOf(argv, argc));
2087 } catch (NativeDaemonConnectorException e) {
2088 throw e.rethrowAsParcelableException();
2096 public void clearPermission(int[] uids) {
2097 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2099 Object[] argv = new Object[3 + MAX_UID_RANGES_PER_COMMAND];
2100 argv[0] = "permission";
2104 // Avoid overly long commands by limiting number of UIDs per command.
2105 for (int i = 0; i < uids.length; ++i) {
2106 argv[argc++] = uids[i];
2107 if (i == uids.length - 1 || argc == argv.length) {
2109 mConnector.execute("network", Arrays.copyOf(argv, argc));
2110 } catch (NativeDaemonConnectorException e) {
2111 throw e.rethrowAsParcelableException();
2119 public void allowProtect(int uid) {
2120 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2123 mConnector.execute("network", "protect", "allow", uid);
2124 } catch (NativeDaemonConnectorException e) {
2125 throw e.rethrowAsParcelableException();
2130 public void denyProtect(int uid) {
2131 mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2134 mConnector.execute("network", "protect", "deny", uid);
2135 } catch (NativeDaemonConnectorException e) {
2136 throw e.rethrowAsParcelableException();
2141 public void addInterfaceToLocalNetwork(String iface, List<RouteInfo> routes) {
2142 modifyInterfaceInNetwork("add", "local", iface);
2144 for (RouteInfo route : routes) {
2145 if (!route.isDefaultRoute()) {
2146 modifyRoute("add", "local", route);
2152 public void removeInterfaceFromLocalNetwork(String iface) {
2153 modifyInterfaceInNetwork("remove", "local", iface);