OSDN Git Service

Additional changes to SubscriptionManager API as per API council.
[android-x86/frameworks-base.git] / services / core / java / com / android / server / NetworkManagementService.java
1 /*
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
17 package com.android.server;
18
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;
40
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;
73
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;
81
82 import java.io.BufferedReader;
83 import java.io.DataInputStream;
84 import java.io.File;
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;
104
105 /**
106  * @hide
107  */
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";
114
115     private static final int MAX_UID_RANGES_PER_COMMAND = 10;
116
117     /**
118      * Name representing {@link #setGlobalAlert(long)} limit when delivered to
119      * {@link INetworkManagementEventObserver#limitReached(String, String)}.
120      */
121     public static final String LIMIT_GLOBAL_ALERT = "globalAlert";
122
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;
130
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;
141
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;
148     }
149
150     static final int DAEMON_MSG_MOBILE_CONN_REAL_TIME_INFO = 1;
151
152     /**
153      * Binder context for this service
154      */
155     private final Context mContext;
156
157     /**
158      * connector object for communicating with netd
159      */
160     private final NativeDaemonConnector mConnector;
161
162     private final Handler mFgHandler;
163     private final Handler mDaemonHandler;
164     private final PhoneStateListener mPhoneStateListener;
165
166     private IBatteryStats mBatteryStats;
167
168     private final Thread mThread;
169     private CountDownLatch mConnectedSignal = new CountDownLatch(1);
170
171     private final RemoteCallbackList<INetworkManagementEventObserver> mObservers =
172             new RemoteCallbackList<INetworkManagementEventObserver>();
173
174     private final NetworkStatsFactory mStatsFactory = new NetworkStatsFactory();
175
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();
183
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;
190
191         IdleTimerParams(int timeout, int type) {
192             this.timeout = timeout;
193             this.type = type;
194             this.networkCount = 1;
195         }
196     }
197     private HashMap<String, IdleTimerParams> mActiveIdleTimers = Maps.newHashMap();
198
199     private volatile boolean mBandwidthControlEnabled;
200     private volatile boolean mFirewallEnabled;
201
202     private boolean mMobileActivityFromRadio = false;
203     private int mLastPowerStateFromRadio = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
204
205     private final RemoteCallbackList<INetworkActivityListener> mNetworkActivityListeners =
206             new RemoteCallbackList<INetworkActivityListener>();
207     private boolean mNetworkActive;
208
209     /**
210      * Constructs a new NetworkManagementService instance
211      *
212      * @param context  Binder context for this service
213      */
214     private NetworkManagementService(Context context, String socket) {
215         mContext = context;
216
217         // make sure this is on the same looper as our NativeDaemonConnector for sync purposes
218         mFgHandler = new Handler(FgThread.get().getLooper());
219
220         if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
221             mConnector = null;
222             mThread = null;
223             mDaemonHandler = null;
224             mPhoneStateListener = null;
225             return;
226         }
227
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);
234
235         mConnector = new NativeDaemonConnector(
236                 new NetdCallbackReceiver(), socket, 10, NETD_TAG, 160, wl,
237                 FgThread.get().getLooper());
238         mThread = new Thread(mConnector, NETD_TAG);
239
240         mDaemonHandler = new Handler(FgThread.get().getLooper());
241
242         mPhoneStateListener = new PhoneStateListener(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
243                 mDaemonHandler.getLooper()) {
244             @Override
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);
250             }
251         };
252         TelephonyManager tm = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
253         if (tm != null) {
254             tm.listen(mPhoneStateListener,
255                     PhoneStateListener.LISTEN_DATA_CONNECTION_REAL_TIME_INFO);
256         }
257
258         // Add ourself to the Watchdog monitors.
259         Watchdog.getInstance().addMonitor(this);
260     }
261
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");
271         return service;
272     }
273
274     public static NetworkManagementService create(Context context) throws InterruptedException {
275         return create(context, NETD_SOCKET_NAME);
276     }
277
278     public void systemReady() {
279         prepareNativeDaemon();
280         if (DBG) Slog.d(TAG, "Prepared");
281     }
282
283     private IBatteryStats getBatteryStats() {
284         synchronized (this) {
285             if (mBatteryStats != null) {
286                 return mBatteryStats;
287             }
288             mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService(
289                     BatteryStats.SERVICE_NAME));
290             return mBatteryStats;
291         }
292     }
293
294     @Override
295     public void registerObserver(INetworkManagementEventObserver observer) {
296         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
297         mObservers.register(observer);
298     }
299
300     @Override
301     public void unregisterObserver(INetworkManagementEventObserver observer) {
302         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
303         mObservers.unregister(observer);
304     }
305
306     /**
307      * Notify our observers of an interface status change
308      */
309     private void notifyInterfaceStatusChanged(String iface, boolean up) {
310         final int length = mObservers.beginBroadcast();
311         try {
312             for (int i = 0; i < length; i++) {
313                 try {
314                     mObservers.getBroadcastItem(i).interfaceStatusChanged(iface, up);
315                 } catch (RemoteException e) {
316                 } catch (RuntimeException e) {
317                 }
318             }
319         } finally {
320             mObservers.finishBroadcast();
321         }
322     }
323
324     /**
325      * Notify our observers of an interface link state change
326      * (typically, an Ethernet cable has been plugged-in or unplugged).
327      */
328     private void notifyInterfaceLinkStateChanged(String iface, boolean up) {
329         final int length = mObservers.beginBroadcast();
330         try {
331             for (int i = 0; i < length; i++) {
332                 try {
333                     mObservers.getBroadcastItem(i).interfaceLinkStateChanged(iface, up);
334                 } catch (RemoteException e) {
335                 } catch (RuntimeException e) {
336                 }
337             }
338         } finally {
339             mObservers.finishBroadcast();
340         }
341     }
342
343     /**
344      * Notify our observers of an interface addition.
345      */
346     private void notifyInterfaceAdded(String iface) {
347         final int length = mObservers.beginBroadcast();
348         try {
349             for (int i = 0; i < length; i++) {
350                 try {
351                     mObservers.getBroadcastItem(i).interfaceAdded(iface);
352                 } catch (RemoteException e) {
353                 } catch (RuntimeException e) {
354                 }
355             }
356         } finally {
357             mObservers.finishBroadcast();
358         }
359     }
360
361     /**
362      * Notify our observers of an interface removal.
363      */
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);
369
370         final int length = mObservers.beginBroadcast();
371         try {
372             for (int i = 0; i < length; i++) {
373                 try {
374                     mObservers.getBroadcastItem(i).interfaceRemoved(iface);
375                 } catch (RemoteException e) {
376                 } catch (RuntimeException e) {
377                 }
378             }
379         } finally {
380             mObservers.finishBroadcast();
381         }
382     }
383
384     /**
385      * Notify our observers of a limit reached.
386      */
387     private void notifyLimitReached(String limitName, String iface) {
388         final int length = mObservers.beginBroadcast();
389         try {
390             for (int i = 0; i < length; i++) {
391                 try {
392                     mObservers.getBroadcastItem(i).limitReached(limitName, iface);
393                 } catch (RemoteException e) {
394                 } catch (RuntimeException e) {
395                 }
396             }
397         } finally {
398             mObservers.finishBroadcast();
399         }
400     }
401
402     /**
403      * Notify our observers of a change in the data activity state of the interface
404      */
405     private void notifyInterfaceClassActivity(int type, int powerState, long tsNanos,
406             boolean fromRadio) {
407         final boolean isMobile = ConnectivityManager.isNetworkTypeMobile(type);
408         if (isMobile) {
409             if (!fromRadio) {
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;
415                 }
416             } else {
417                 mMobileActivityFromRadio = true;
418             }
419             if (mLastPowerStateFromRadio != powerState) {
420                 mLastPowerStateFromRadio = powerState;
421                 try {
422                     getBatteryStats().noteMobileRadioPowerState(powerState, tsNanos);
423                 } catch (RemoteException e) {
424                 }
425             }
426         }
427
428         boolean isActive = powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_MEDIUM
429                 || powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH;
430
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();
437             try {
438                 for (int i = 0; i < length; i++) {
439                     try {
440                         mObservers.getBroadcastItem(i).interfaceClassDataActivityChanged(
441                                 Integer.toString(type), isActive, tsNanos);
442                     } catch (RemoteException e) {
443                     } catch (RuntimeException e) {
444                     }
445                 }
446             } finally {
447                 mObservers.finishBroadcast();
448             }
449         }
450
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.
456                 isActive = true;
457             }
458             if (mNetworkActive != isActive) {
459                 mNetworkActive = isActive;
460                 report = isActive;
461             }
462         }
463         if (report) {
464             reportNetworkActive();
465         }
466     }
467
468     /**
469      * Prepare native daemon once connected, enabling modules and pushing any
470      * existing in-memory rules.
471      */
472     private void prepareNativeDaemon() {
473         mBandwidthControlEnabled = false;
474
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");
479             try {
480                 mConnector.execute("bandwidth", "enable");
481                 mBandwidthControlEnabled = true;
482             } catch (NativeDaemonConnectorException e) {
483                 Log.wtf(TAG, "problem enabling bandwidth controls", e);
484             }
485         } else {
486             Slog.d(TAG, "not enabling bandwidth control");
487         }
488
489         SystemProperties.set(PROP_QTAGUID_ENABLED, mBandwidthControlEnabled ? "1" : "0");
490
491         if (mBandwidthControlEnabled) {
492             try {
493                 getBatteryStats().noteNetworkStatsEnabled();
494             } catch (RemoteException e) {
495             }
496         }
497
498         // push any existing quota or UID rules
499         synchronized (mQuotaLock) {
500             int size = mActiveQuotas.size();
501             if (size > 0) {
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());
507                 }
508             }
509
510             size = mActiveAlerts.size();
511             if (size > 0) {
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());
517                 }
518             }
519
520             size = mUidRejectOnQuota.size();
521             if (size > 0) {
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));
527                 }
528             }
529         }
530
531         // TODO: Push any existing firewall state
532         setFirewallEnabled(mFirewallEnabled || LockdownVpnTracker.isEnabled());
533     }
534
535     /**
536      * Notify our observers of a new or updated interface address.
537      */
538     private void notifyAddressUpdated(String iface, LinkAddress address) {
539         final int length = mObservers.beginBroadcast();
540         try {
541             for (int i = 0; i < length; i++) {
542                 try {
543                     mObservers.getBroadcastItem(i).addressUpdated(iface, address);
544                 } catch (RemoteException e) {
545                 } catch (RuntimeException e) {
546                 }
547             }
548         } finally {
549             mObservers.finishBroadcast();
550         }
551     }
552
553     /**
554      * Notify our observers of a deleted interface address.
555      */
556     private void notifyAddressRemoved(String iface, LinkAddress address) {
557         final int length = mObservers.beginBroadcast();
558         try {
559             for (int i = 0; i < length; i++) {
560                 try {
561                     mObservers.getBroadcastItem(i).addressRemoved(iface, address);
562                 } catch (RemoteException e) {
563                 } catch (RuntimeException e) {
564                 }
565             }
566         } finally {
567             mObservers.finishBroadcast();
568         }
569     }
570
571     /**
572      * Notify our observers of DNS server information received.
573      */
574     private void notifyInterfaceDnsServerInfo(String iface, long lifetime, String[] addresses) {
575         final int length = mObservers.beginBroadcast();
576         try {
577             for (int i = 0; i < length; i++) {
578                 try {
579                     mObservers.getBroadcastItem(i).interfaceDnsServerInfo(iface, lifetime,
580                         addresses);
581                 } catch (RemoteException e) {
582                 } catch (RuntimeException e) {
583                 }
584             }
585         } finally {
586             mObservers.finishBroadcast();
587         }
588     }
589
590     /**
591      * Notify our observers of a route change.
592      */
593     private void notifyRouteChange(String action, RouteInfo route) {
594         final int length = mObservers.beginBroadcast();
595         try {
596             for (int i = 0; i < length; i++) {
597                 try {
598                     if (action.equals("updated")) {
599                         mObservers.getBroadcastItem(i).routeUpdated(route);
600                     } else {
601                         mObservers.getBroadcastItem(i).routeRemoved(route);
602                     }
603                 } catch (RemoteException e) {
604                 } catch (RuntimeException e) {
605                 }
606             }
607         } finally {
608             mObservers.finishBroadcast();
609         }
610     }
611
612     //
613     // Netd Callback handling
614     //
615
616     private class NetdCallbackReceiver implements INativeDaemonConnectorCallbacks {
617         @Override
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;
624             } else {
625                 mFgHandler.post(new Runnable() {
626                     @Override
627                     public void run() {
628                         prepareNativeDaemon();
629                     }
630                 });
631             }
632         }
633
634         @Override
635         public boolean onCheckHoldWakeLock(int code) {
636             return code == NetdResponseCode.InterfaceClassActivity;
637         }
638
639         @Override
640         public boolean onEvent(int code, String raw, String[] cooked) {
641             String errorMessage = String.format("Invalid event from daemon (%s)", raw);
642             switch (code) {
643             case NetdResponseCode.InterfaceChange:
644                     /*
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>"
650                      */
651                     if (cooked.length < 4 || !cooked[1].equals("Iface")) {
652                         throw new IllegalStateException(errorMessage);
653                     }
654                     if (cooked[2].equals("added")) {
655                         notifyInterfaceAdded(cooked[3]);
656                         return true;
657                     } else if (cooked[2].equals("removed")) {
658                         notifyInterfaceRemoved(cooked[3]);
659                         return true;
660                     } else if (cooked[2].equals("changed") && cooked.length == 5) {
661                         notifyInterfaceStatusChanged(cooked[3], cooked[4].equals("up"));
662                         return true;
663                     } else if (cooked[2].equals("linkstate") && cooked.length == 5) {
664                         notifyInterfaceLinkStateChanged(cooked[3], cooked[4].equals("up"));
665                         return true;
666                     }
667                     throw new IllegalStateException(errorMessage);
668                     // break;
669             case NetdResponseCode.BandwidthControl:
670                     /*
671                      * Bandwidth control needs some attention
672                      * Format: "NNN limit alert <alertName> <ifaceName>"
673                      */
674                     if (cooked.length < 5 || !cooked[1].equals("limit")) {
675                         throw new IllegalStateException(errorMessage);
676                     }
677                     if (cooked[2].equals("alert")) {
678                         notifyLimitReached(cooked[3], cooked[4]);
679                         return true;
680                     }
681                     throw new IllegalStateException(errorMessage);
682                     // break;
683             case NetdResponseCode.InterfaceClassActivity:
684                     /*
685                      * An network interface class state changed (active/idle)
686                      * Format: "NNN IfaceClass <active/idle> <label>"
687                      */
688                     if (cooked.length < 4 || !cooked[1].equals("IfaceClass")) {
689                         throw new IllegalStateException(errorMessage);
690                     }
691                     long timestampNanos = 0;
692                     if (cooked.length == 5) {
693                         try {
694                             timestampNanos = Long.parseLong(cooked[4]);
695                         } catch(NumberFormatException ne) {}
696                     } else {
697                         timestampNanos = SystemClock.elapsedRealtimeNanos();
698                     }
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);
703                     return true;
704                     // break;
705             case NetdResponseCode.InterfaceAddressChange:
706                     /*
707                      * A network address change occurred
708                      * Format: "NNN Address updated <addr> <iface> <flags> <scope>"
709                      *         "NNN Address removed <addr> <iface> <flags> <scope>"
710                      */
711                     if (cooked.length < 7 || !cooked[1].equals("Address")) {
712                         throw new IllegalStateException(errorMessage);
713                     }
714
715                     String iface = cooked[4];
716                     LinkAddress address;
717                     try {
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);
725                     }
726
727                     if (cooked[2].equals("updated")) {
728                         notifyAddressUpdated(iface, address);
729                     } else {
730                         notifyAddressRemoved(iface, address);
731                     }
732                     return true;
733                     // break;
734             case NetdResponseCode.InterfaceDnsServerInfo:
735                     /*
736                      * Information about available DNS servers has been received.
737                      * Format: "NNN DnsInfo servers <interface> <lifetime> <servers>"
738                      */
739                     long lifetime;  // Actually a 32-bit unsigned integer.
740
741                     if (cooked.length == 6 &&
742                         cooked[1].equals("DnsInfo") &&
743                         cooked[2].equals("servers")) {
744                         try {
745                             lifetime = Long.parseLong(cooked[4]);
746                         } catch (NumberFormatException e) {
747                             throw new IllegalStateException(errorMessage);
748                         }
749                         String[] servers = cooked[5].split(",");
750                         notifyInterfaceDnsServerInfo(cooked[3], lifetime, servers);
751                     }
752                     return true;
753                     // break;
754             case NetdResponseCode.RouteChange:
755                     /*
756                      * A route has been updated or removed.
757                      * Format: "NNN Route <updated|removed> <dst> [via <gateway] [dev <iface>]"
758                      */
759                     if (!cooked[1].equals("Route") || cooked.length < 6) {
760                         throw new IllegalStateException(errorMessage);
761                     }
762
763                     String via = null;
764                     String dev = null;
765                     boolean valid = true;
766                     for (int i = 4; (i + 1) < cooked.length && valid; i += 2) {
767                         if (cooked[i].equals("dev")) {
768                             if (dev == null) {
769                                 dev = cooked[i+1];
770                             } else {
771                                 valid = false;  // Duplicate interface.
772                             }
773                         } else if (cooked[i].equals("via")) {
774                             if (via == null) {
775                                 via = cooked[i+1];
776                             } else {
777                                 valid = false;  // Duplicate gateway.
778                             }
779                         } else {
780                             valid = false;      // Unknown syntax.
781                         }
782                     }
783                     if (valid) {
784                         try {
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);
790                             return true;
791                         } catch (IllegalArgumentException e) {}
792                     }
793                     throw new IllegalStateException(errorMessage);
794                     // break;
795             default: break;
796             }
797             return false;
798         }
799     }
800
801
802     //
803     // INetworkManagementService members
804     //
805
806     @Override
807     public String[] listInterfaces() {
808         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
809         try {
810             return NativeDaemonEvent.filterMessageList(
811                     mConnector.executeForList("interface", "list"), InterfaceListResult);
812         } catch (NativeDaemonConnectorException e) {
813             throw e.rethrowAsParcelableException();
814         }
815     }
816
817     @Override
818     public InterfaceConfiguration getInterfaceConfig(String iface) {
819         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
820
821         final NativeDaemonEvent event;
822         try {
823             event = mConnector.execute("interface", "getcfg", iface);
824         } catch (NativeDaemonConnectorException e) {
825             throw e.rethrowAsParcelableException();
826         }
827
828         event.checkCode(InterfaceGetCfgResult);
829
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());
832
833         InterfaceConfiguration cfg;
834         try {
835             cfg = new InterfaceConfiguration();
836             cfg.setHardwareAddress(st.nextToken(" "));
837             InetAddress addr = null;
838             int prefixLength = 0;
839             try {
840                 addr = NetworkUtils.numericToInetAddress(st.nextToken());
841             } catch (IllegalArgumentException iae) {
842                 Slog.e(TAG, "Failed to parse ipaddr", iae);
843             }
844
845             try {
846                 prefixLength = Integer.parseInt(st.nextToken());
847             } catch (NumberFormatException nfe) {
848                 Slog.e(TAG, "Failed to parse prefixLength", nfe);
849             }
850
851             cfg.setLinkAddress(new LinkAddress(addr, prefixLength));
852             while (st.hasMoreTokens()) {
853                 cfg.setFlag(st.nextToken());
854             }
855         } catch (NoSuchElementException nsee) {
856             throw new IllegalStateException("Invalid response from daemon: " + event);
857         }
858         return cfg;
859     }
860
861     @Override
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");
867         }
868
869         final Command cmd = new Command("interface", "setcfg", iface,
870                 linkAddr.getAddress().getHostAddress(),
871                 linkAddr.getPrefixLength());
872         for (String flag : cfg.getFlags()) {
873             cmd.appendArg(flag);
874         }
875
876         try {
877             mConnector.execute(cmd);
878         } catch (NativeDaemonConnectorException e) {
879             throw e.rethrowAsParcelableException();
880         }
881     }
882
883     @Override
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);
889     }
890
891     @Override
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);
897     }
898
899     @Override
900     public void setInterfaceIpv6PrivacyExtensions(String iface, boolean enable) {
901         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
902         try {
903             mConnector.execute(
904                     "interface", "ipv6privacyextensions", iface, enable ? "enable" : "disable");
905         } catch (NativeDaemonConnectorException e) {
906             throw e.rethrowAsParcelableException();
907         }
908     }
909
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 */
912     @Override
913     public void clearInterfaceAddresses(String iface) {
914         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
915         try {
916             mConnector.execute("interface", "clearaddrs", iface);
917         } catch (NativeDaemonConnectorException e) {
918             throw e.rethrowAsParcelableException();
919         }
920     }
921
922     @Override
923     public void enableIpv6(String iface) {
924         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
925         try {
926             mConnector.execute("interface", "ipv6", iface, "enable");
927         } catch (NativeDaemonConnectorException e) {
928             throw e.rethrowAsParcelableException();
929         }
930     }
931
932     @Override
933     public void disableIpv6(String iface) {
934         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
935         try {
936             mConnector.execute("interface", "ipv6", iface, "disable");
937         } catch (NativeDaemonConnectorException e) {
938             throw e.rethrowAsParcelableException();
939         }
940     }
941
942     @Override
943     public void setInterfaceIpv6NdOffload(String iface, boolean enable) {
944         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
945         try {
946             mConnector.execute(
947                     "interface", "ipv6ndoffload", iface, (enable ? "enable" : "disable"));
948         } catch (NativeDaemonConnectorException e) {
949             throw e.rethrowAsParcelableException();
950         }
951     }
952
953     @Override
954     public void addRoute(int netId, RouteInfo route) {
955         modifyRoute("add", "" + netId, route);
956     }
957
958     @Override
959     public void removeRoute(int netId, RouteInfo route) {
960         modifyRoute("remove", "" + netId, route);
961     }
962
963     private void modifyRoute(String action, String netId, RouteInfo route) {
964         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
965
966         final Command cmd = new Command("network", "route", action, netId);
967
968         // create triplet: interface dest-ip-addr/prefixlength gateway-ip-addr
969         cmd.appendArg(route.getInterface());
970         cmd.appendArg(route.getDestination().toString());
971
972         switch (route.getType()) {
973             case RouteInfo.RTN_UNICAST:
974                 if (route.hasGateway()) {
975                     cmd.appendArg(route.getGateway().getHostAddress());
976                 }
977                 break;
978             case RouteInfo.RTN_UNREACHABLE:
979                 cmd.appendArg("unreachable");
980                 break;
981             case RouteInfo.RTN_THROW:
982                 cmd.appendArg("throw");
983                 break;
984         }
985
986         try {
987             mConnector.execute(cmd);
988         } catch (NativeDaemonConnectorException e) {
989             throw e.rethrowAsParcelableException();
990         }
991     }
992
993     private ArrayList<String> readRouteList(String filename) {
994         FileInputStream fstream = null;
995         ArrayList<String> list = new ArrayList<String>();
996
997         try {
998             fstream = new FileInputStream(filename);
999             DataInputStream in = new DataInputStream(fstream);
1000             BufferedReader br = new BufferedReader(new InputStreamReader(in));
1001             String s;
1002
1003             // throw away the title line
1004
1005             while (((s = br.readLine()) != null) && (s.length() != 0)) {
1006                 list.add(s);
1007             }
1008         } catch (IOException ex) {
1009             // return current list, possibly empty
1010         } finally {
1011             if (fstream != null) {
1012                 try {
1013                     fstream.close();
1014                 } catch (IOException ex) {}
1015             }
1016         }
1017
1018         return list;
1019     }
1020
1021     @Override
1022     public RouteInfo[] getRoutes(String interfaceName) {
1023         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1024         ArrayList<RouteInfo> routes = new ArrayList<RouteInfo>();
1025
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");
1030
1031             if (fields.length > 7) {
1032                 String iface = fields[0];
1033
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];
1039                     try {
1040                         // address stored as a hex string, ex: 0014A8C0
1041                         InetAddress destAddr =
1042                                 NetworkUtils.intToInetAddress((int)Long.parseLong(dest, 16));
1043                         int prefixLength =
1044                                 NetworkUtils.netmaskIntToPrefixLength(
1045                                 (int)Long.parseLong(mask, 16));
1046                         LinkAddress linkAddress = new LinkAddress(destAddr, prefixLength);
1047
1048                         // address stored as a hex string, ex 0014A8C0
1049                         InetAddress gatewayAddr =
1050                                 NetworkUtils.intToInetAddress((int)Long.parseLong(gate, 16));
1051
1052                         RouteInfo route = new RouteInfo(linkAddress, gatewayAddr);
1053                         routes.add(route);
1054                     } catch (Exception e) {
1055                         Log.e(TAG, "Error parsing route " + s + " : " + e);
1056                         continue;
1057                     }
1058                 }
1059             }
1060         }
1061
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];
1072
1073                     try {
1074                         // prefix length stored as a hex string, ex 40
1075                         int prefixLength = Integer.parseInt(prefix, 16);
1076
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);
1081
1082                         InetAddress gateAddr = NetworkUtils.hexToInet6Address(gate);
1083
1084                         RouteInfo route = new RouteInfo(linkAddress, gateAddr);
1085                         routes.add(route);
1086                     } catch (Exception e) {
1087                         Log.e(TAG, "Error parsing route " + s + " : " + e);
1088                         continue;
1089                     }
1090                 }
1091             }
1092         }
1093         return routes.toArray(new RouteInfo[routes.size()]);
1094     }
1095
1096     @Override
1097     public void setMtu(String iface, int mtu) {
1098         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1099
1100         final NativeDaemonEvent event;
1101         try {
1102             event = mConnector.execute("interface", "setmtu", iface, mtu);
1103         } catch (NativeDaemonConnectorException e) {
1104             throw e.rethrowAsParcelableException();
1105         }
1106     }
1107
1108     @Override
1109     public void shutdown() {
1110         // TODO: remove from aidl if nobody calls externally
1111         mContext.enforceCallingOrSelfPermission(SHUTDOWN, TAG);
1112
1113         Slog.d(TAG, "Shutting down");
1114     }
1115
1116     @Override
1117     public boolean getIpForwardingEnabled() throws IllegalStateException{
1118         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1119
1120         final NativeDaemonEvent event;
1121         try {
1122             event = mConnector.execute("ipfwd", "status");
1123         } catch (NativeDaemonConnectorException e) {
1124             throw e.rethrowAsParcelableException();
1125         }
1126
1127         // 211 Forwarding enabled
1128         event.checkCode(IpFwdStatusResult);
1129         return event.getMessage().endsWith("enabled");
1130     }
1131
1132     @Override
1133     public void setIpForwardingEnabled(boolean enable) {
1134         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1135         try {
1136             mConnector.execute("ipfwd", enable ? "enable" : "disable");
1137         } catch (NativeDaemonConnectorException e) {
1138             throw e.rethrowAsParcelableException();
1139         }
1140     }
1141
1142     @Override
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
1147
1148         final Command cmd = new Command("tether", "start");
1149         for (String d : dhcpRange) {
1150             cmd.appendArg(d);
1151         }
1152
1153         try {
1154             mConnector.execute(cmd);
1155         } catch (NativeDaemonConnectorException e) {
1156             throw e.rethrowAsParcelableException();
1157         }
1158     }
1159
1160     @Override
1161     public void stopTethering() {
1162         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1163         try {
1164             mConnector.execute("tether", "stop");
1165         } catch (NativeDaemonConnectorException e) {
1166             throw e.rethrowAsParcelableException();
1167         }
1168     }
1169
1170     @Override
1171     public boolean isTetheringStarted() {
1172         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1173
1174         final NativeDaemonEvent event;
1175         try {
1176             event = mConnector.execute("tether", "status");
1177         } catch (NativeDaemonConnectorException e) {
1178             throw e.rethrowAsParcelableException();
1179         }
1180
1181         // 210 Tethering services started
1182         event.checkCode(TetherStatusResult);
1183         return event.getMessage().endsWith("started");
1184     }
1185
1186     @Override
1187     public void tetherInterface(String iface) {
1188         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1189         try {
1190             mConnector.execute("tether", "interface", "add", iface);
1191         } catch (NativeDaemonConnectorException e) {
1192             throw e.rethrowAsParcelableException();
1193         }
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);
1199     }
1200
1201     @Override
1202     public void untetherInterface(String iface) {
1203         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1204         try {
1205             mConnector.execute("tether", "interface", "remove", iface);
1206         } catch (NativeDaemonConnectorException e) {
1207             throw e.rethrowAsParcelableException();
1208         }
1209         removeInterfaceFromLocalNetwork(iface);
1210     }
1211
1212     @Override
1213     public String[] listTetheredInterfaces() {
1214         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1215         try {
1216             return NativeDaemonEvent.filterMessageList(
1217                     mConnector.executeForList("tether", "interface", "list"),
1218                     TetherInterfaceListResult);
1219         } catch (NativeDaemonConnectorException e) {
1220             throw e.rethrowAsParcelableException();
1221         }
1222     }
1223
1224     @Override
1225     public void setDnsForwarders(Network network, String[] dns) {
1226         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1227
1228         int netId = (network != null) ? network.netId : ConnectivityManager.NETID_UNSET;
1229         final Command cmd = new Command("tether", "dns", "set", netId);
1230
1231         for (String s : dns) {
1232             cmd.appendArg(NetworkUtils.numericToInetAddress(s).getHostAddress());
1233         }
1234
1235         try {
1236             mConnector.execute(cmd);
1237         } catch (NativeDaemonConnectorException e) {
1238             throw e.rethrowAsParcelableException();
1239         }
1240     }
1241
1242     @Override
1243     public String[] getDnsForwarders() {
1244         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1245         try {
1246             return NativeDaemonEvent.filterMessageList(
1247                     mConnector.executeForList("tether", "dns", "list"), TetherDnsFwdTgtListResult);
1248         } catch (NativeDaemonConnectorException e) {
1249             throw e.rethrowAsParcelableException();
1250         }
1251     }
1252
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())
1257                 filtered.add(ia);
1258         }
1259         return filtered;
1260     }
1261
1262     private void modifyNat(String action, String internalInterface, String externalInterface)
1263             throws SocketException {
1264         final Command cmd = new Command("nat", action, internalInterface, externalInterface);
1265
1266         final NetworkInterface internalNetworkInterface = NetworkInterface.getByName(
1267                 internalInterface);
1268         if (internalNetworkInterface == null) {
1269             cmd.appendArg("0");
1270         } else {
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());
1280             }
1281         }
1282
1283         try {
1284             mConnector.execute(cmd);
1285         } catch (NativeDaemonConnectorException e) {
1286             throw e.rethrowAsParcelableException();
1287         }
1288     }
1289
1290     @Override
1291     public void enableNat(String internalInterface, String externalInterface) {
1292         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1293         try {
1294             modifyNat("enable", internalInterface, externalInterface);
1295         } catch (SocketException e) {
1296             throw new IllegalStateException(e);
1297         }
1298     }
1299
1300     @Override
1301     public void disableNat(String internalInterface, String externalInterface) {
1302         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1303         try {
1304             modifyNat("disable", internalInterface, externalInterface);
1305         } catch (SocketException e) {
1306             throw new IllegalStateException(e);
1307         }
1308     }
1309
1310     @Override
1311     public String[] listTtys() {
1312         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1313         try {
1314             return NativeDaemonEvent.filterMessageList(
1315                     mConnector.executeForList("list_ttys"), TtyListResult);
1316         } catch (NativeDaemonConnectorException e) {
1317             throw e.rethrowAsParcelableException();
1318         }
1319     }
1320
1321     @Override
1322     public void attachPppd(
1323             String tty, String localAddr, String remoteAddr, String dns1Addr, String dns2Addr) {
1324         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1325         try {
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();
1333         }
1334     }
1335
1336     @Override
1337     public void detachPppd(String tty) {
1338         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1339         try {
1340             mConnector.execute("pppd", "detach", tty);
1341         } catch (NativeDaemonConnectorException e) {
1342             throw e.rethrowAsParcelableException();
1343         }
1344     }
1345
1346     @Override
1347     public void startAccessPoint(
1348             WifiConfiguration wifiConfig, String wlanIface) {
1349         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1350         try {
1351             wifiFirmwareReload(wlanIface, "AP");
1352             if (wifiConfig == null) {
1353                 mConnector.execute("softap", "set", wlanIface);
1354             } else {
1355                 mConnector.execute("softap", "set", wlanIface, wifiConfig.SSID,
1356                                    "broadcast", "6", getSecurityType(wifiConfig),
1357                                    new SensitiveArg(wifiConfig.preSharedKey));
1358             }
1359             mConnector.execute("softap", "startap");
1360         } catch (NativeDaemonConnectorException e) {
1361             throw e.rethrowAsParcelableException();
1362         }
1363     }
1364
1365     private static String getSecurityType(WifiConfiguration wifiConfig) {
1366         switch (wifiConfig.getAuthType()) {
1367             case KeyMgmt.WPA_PSK:
1368                 return "wpa-psk";
1369             case KeyMgmt.WPA2_PSK:
1370                 return "wpa2-psk";
1371             default:
1372                 return "open";
1373         }
1374     }
1375
1376     /* @param mode can be "AP", "STA" or "P2P" */
1377     @Override
1378     public void wifiFirmwareReload(String wlanIface, String mode) {
1379         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1380         try {
1381             mConnector.execute("softap", "fwreload", wlanIface, mode);
1382         } catch (NativeDaemonConnectorException e) {
1383             throw e.rethrowAsParcelableException();
1384         }
1385     }
1386
1387     @Override
1388     public void stopAccessPoint(String wlanIface) {
1389         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1390         try {
1391             mConnector.execute("softap", "stopap");
1392             wifiFirmwareReload(wlanIface, "STA");
1393         } catch (NativeDaemonConnectorException e) {
1394             throw e.rethrowAsParcelableException();
1395         }
1396     }
1397
1398     @Override
1399     public void setAccessPoint(WifiConfiguration wifiConfig, String wlanIface) {
1400         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1401         try {
1402             if (wifiConfig == null) {
1403                 mConnector.execute("softap", "set", wlanIface);
1404             } else {
1405                 mConnector.execute("softap", "set", wlanIface, wifiConfig.SSID,
1406                                    "broadcast", "6", getSecurityType(wifiConfig),
1407                                    new SensitiveArg(wifiConfig.preSharedKey));
1408             }
1409         } catch (NativeDaemonConnectorException e) {
1410             throw e.rethrowAsParcelableException();
1411         }
1412     }
1413
1414     @Override
1415     public void addIdleTimer(String iface, int timeout, final int type) {
1416         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1417
1418         if (DBG) Slog.d(TAG, "Adding idletimer");
1419
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++;
1425                 return;
1426             }
1427
1428             try {
1429                 mConnector.execute("idletimer", "add", iface, Integer.toString(timeout),
1430                         Integer.toString(type));
1431             } catch (NativeDaemonConnectorException e) {
1432                 throw e.rethrowAsParcelableException();
1433             }
1434             mActiveIdleTimers.put(iface, new IdleTimerParams(timeout, type));
1435
1436             // Networks start up.
1437             if (ConnectivityManager.isNetworkTypeMobile(type)) {
1438                 mNetworkActive = false;
1439             }
1440             mDaemonHandler.post(new Runnable() {
1441                 @Override public void run() {
1442                     notifyInterfaceClassActivity(type,
1443                             DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH,
1444                             SystemClock.elapsedRealtimeNanos(), false);
1445                 }
1446             });
1447         }
1448     }
1449
1450     @Override
1451     public void removeIdleTimer(String iface) {
1452         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1453
1454         if (DBG) Slog.d(TAG, "Removing idletimer");
1455
1456         synchronized (mIdleTimerLock) {
1457             final IdleTimerParams params = mActiveIdleTimers.get(iface);
1458             if (params == null || --(params.networkCount) > 0) {
1459                 return;
1460             }
1461
1462             try {
1463                 mConnector.execute("idletimer", "remove", iface,
1464                         Integer.toString(params.timeout), Integer.toString(params.type));
1465             } catch (NativeDaemonConnectorException e) {
1466                 throw e.rethrowAsParcelableException();
1467             }
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);
1474                 }
1475             });
1476         }
1477     }
1478
1479     @Override
1480     public NetworkStats getNetworkStatsSummaryDev() {
1481         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1482         try {
1483             return mStatsFactory.readNetworkStatsSummaryDev();
1484         } catch (IOException e) {
1485             throw new IllegalStateException(e);
1486         }
1487     }
1488
1489     @Override
1490     public NetworkStats getNetworkStatsSummaryXt() {
1491         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1492         try {
1493             return mStatsFactory.readNetworkStatsSummaryXt();
1494         } catch (IOException e) {
1495             throw new IllegalStateException(e);
1496         }
1497     }
1498
1499     @Override
1500     public NetworkStats getNetworkStatsDetail() {
1501         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1502         try {
1503             return mStatsFactory.readNetworkStatsDetail(UID_ALL, null, TAG_ALL, null);
1504         } catch (IOException e) {
1505             throw new IllegalStateException(e);
1506         }
1507     }
1508
1509     @Override
1510     public void setInterfaceQuota(String iface, long quotaBytes) {
1511         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1512
1513         // silently discard when control disabled
1514         // TODO: eventually migrate to be always enabled
1515         if (!mBandwidthControlEnabled) return;
1516
1517         synchronized (mQuotaLock) {
1518             if (mActiveQuotas.containsKey(iface)) {
1519                 throw new IllegalStateException("iface " + iface + " already has quota");
1520             }
1521
1522             try {
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();
1528             }
1529         }
1530     }
1531
1532     @Override
1533     public void removeInterfaceQuota(String iface) {
1534         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1535
1536         // silently discard when control disabled
1537         // TODO: eventually migrate to be always enabled
1538         if (!mBandwidthControlEnabled) return;
1539
1540         synchronized (mQuotaLock) {
1541             if (!mActiveQuotas.containsKey(iface)) {
1542                 // TODO: eventually consider throwing
1543                 return;
1544             }
1545
1546             mActiveQuotas.remove(iface);
1547             mActiveAlerts.remove(iface);
1548
1549             try {
1550                 // TODO: support quota shared across interfaces
1551                 mConnector.execute("bandwidth", "removeiquota", iface);
1552             } catch (NativeDaemonConnectorException e) {
1553                 throw e.rethrowAsParcelableException();
1554             }
1555         }
1556     }
1557
1558     @Override
1559     public void setInterfaceAlert(String iface, long alertBytes) {
1560         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1561
1562         // silently discard when control disabled
1563         // TODO: eventually migrate to be always enabled
1564         if (!mBandwidthControlEnabled) return;
1565
1566         // quick sanity check
1567         if (!mActiveQuotas.containsKey(iface)) {
1568             throw new IllegalStateException("setting alert requires existing quota on iface");
1569         }
1570
1571         synchronized (mQuotaLock) {
1572             if (mActiveAlerts.containsKey(iface)) {
1573                 throw new IllegalStateException("iface " + iface + " already has alert");
1574             }
1575
1576             try {
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();
1582             }
1583         }
1584     }
1585
1586     @Override
1587     public void removeInterfaceAlert(String iface) {
1588         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1589
1590         // silently discard when control disabled
1591         // TODO: eventually migrate to be always enabled
1592         if (!mBandwidthControlEnabled) return;
1593
1594         synchronized (mQuotaLock) {
1595             if (!mActiveAlerts.containsKey(iface)) {
1596                 // TODO: eventually consider throwing
1597                 return;
1598             }
1599
1600             try {
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();
1606             }
1607         }
1608     }
1609
1610     @Override
1611     public void setGlobalAlert(long alertBytes) {
1612         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1613
1614         // silently discard when control disabled
1615         // TODO: eventually migrate to be always enabled
1616         if (!mBandwidthControlEnabled) return;
1617
1618         try {
1619             mConnector.execute("bandwidth", "setglobalalert", alertBytes);
1620         } catch (NativeDaemonConnectorException e) {
1621             throw e.rethrowAsParcelableException();
1622         }
1623     }
1624
1625     @Override
1626     public void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces) {
1627         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1628
1629         // silently discard when control disabled
1630         // TODO: eventually migrate to be always enabled
1631         if (!mBandwidthControlEnabled) return;
1632
1633         synchronized (mQuotaLock) {
1634             final boolean oldRejectOnQuota = mUidRejectOnQuota.get(uid, false);
1635             if (oldRejectOnQuota == rejectOnQuotaInterfaces) {
1636                 // TODO: eventually consider throwing
1637                 return;
1638             }
1639
1640             try {
1641                 mConnector.execute("bandwidth",
1642                         rejectOnQuotaInterfaces ? "addnaughtyapps" : "removenaughtyapps", uid);
1643                 if (rejectOnQuotaInterfaces) {
1644                     mUidRejectOnQuota.put(uid, true);
1645                 } else {
1646                     mUidRejectOnQuota.delete(uid);
1647                 }
1648             } catch (NativeDaemonConnectorException e) {
1649                 throw e.rethrowAsParcelableException();
1650             }
1651         }
1652     }
1653
1654     @Override
1655     public boolean isBandwidthControlEnabled() {
1656         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1657         return mBandwidthControlEnabled;
1658     }
1659
1660     @Override
1661     public NetworkStats getNetworkStatsUidDetail(int uid) {
1662         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1663         try {
1664             return mStatsFactory.readNetworkStatsDetail(uid, null, TAG_ALL, null);
1665         } catch (IOException e) {
1666             throw new IllegalStateException(e);
1667         }
1668     }
1669
1670     @Override
1671     public NetworkStats getNetworkStatsTethering() {
1672         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1673
1674         final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1);
1675         try {
1676             final NativeDaemonEvent[] events = mConnector.executeForList(
1677                     "bandwidth", "gettetherstats");
1678             for (NativeDaemonEvent event : events) {
1679                 if (event.getCode() != TetheringStatsListResult) continue;
1680
1681                 // 114 ifaceIn ifaceOut rx_bytes rx_packets tx_bytes tx_packets
1682                 final StringTokenizer tok = new StringTokenizer(event.getMessage());
1683                 try {
1684                     final String ifaceIn = tok.nextToken();
1685                     final String ifaceOut = tok.nextToken();
1686
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);
1701                 }
1702             }
1703         } catch (NativeDaemonConnectorException e) {
1704             throw e.rethrowAsParcelableException();
1705         }
1706         return stats;
1707     }
1708
1709     @Override
1710     public void setDnsServersForNetwork(int netId, String[] servers, String domains) {
1711         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1712
1713         final Command cmd = new Command("resolver", "setnetdns", netId,
1714                 (domains == null ? "" : domains));
1715
1716         for (String s : servers) {
1717             InetAddress a = NetworkUtils.numericToInetAddress(s);
1718             if (a.isAnyLocalAddress() == false) {
1719                 cmd.appendArg(a.getHostAddress());
1720             }
1721         }
1722
1723         try {
1724             mConnector.execute(cmd);
1725         } catch (NativeDaemonConnectorException e) {
1726             throw e.rethrowAsParcelableException();
1727         }
1728     }
1729
1730     @Override
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];
1734         argv[0] = "users";
1735         argv[1] = "add";
1736         argv[2] = netId;
1737         int argc = 3;
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) {
1742                 try {
1743                     mConnector.execute("network", Arrays.copyOf(argv, argc));
1744                 } catch (NativeDaemonConnectorException e) {
1745                     throw e.rethrowAsParcelableException();
1746                 }
1747                 argc = 3;
1748             }
1749         }
1750     }
1751
1752     @Override
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];
1756         argv[0] = "users";
1757         argv[1] = "remove";
1758         argv[2] = netId;
1759         int argc = 3;
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) {
1764                 try {
1765                     mConnector.execute("network", Arrays.copyOf(argv, argc));
1766                 } catch (NativeDaemonConnectorException e) {
1767                     throw e.rethrowAsParcelableException();
1768                 }
1769                 argc = 3;
1770             }
1771         }
1772     }
1773
1774     @Override
1775     public void flushNetworkDnsCache(int netId) {
1776         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1777         try {
1778             mConnector.execute("resolver", "flushnet", netId);
1779         } catch (NativeDaemonConnectorException e) {
1780             throw e.rethrowAsParcelableException();
1781         }
1782     }
1783
1784     @Override
1785     public void setFirewallEnabled(boolean enabled) {
1786         enforceSystemUid();
1787         try {
1788             mConnector.execute("firewall", enabled ? "enable" : "disable");
1789             mFirewallEnabled = enabled;
1790         } catch (NativeDaemonConnectorException e) {
1791             throw e.rethrowAsParcelableException();
1792         }
1793     }
1794
1795     @Override
1796     public boolean isFirewallEnabled() {
1797         enforceSystemUid();
1798         return mFirewallEnabled;
1799     }
1800
1801     @Override
1802     public void setFirewallInterfaceRule(String iface, boolean allow) {
1803         enforceSystemUid();
1804         Preconditions.checkState(mFirewallEnabled);
1805         final String rule = allow ? "allow" : "deny";
1806         try {
1807             mConnector.execute("firewall", "set_interface_rule", iface, rule);
1808         } catch (NativeDaemonConnectorException e) {
1809             throw e.rethrowAsParcelableException();
1810         }
1811     }
1812
1813     @Override
1814     public void setFirewallEgressSourceRule(String addr, boolean allow) {
1815         enforceSystemUid();
1816         Preconditions.checkState(mFirewallEnabled);
1817         final String rule = allow ? "allow" : "deny";
1818         try {
1819             mConnector.execute("firewall", "set_egress_source_rule", addr, rule);
1820         } catch (NativeDaemonConnectorException e) {
1821             throw e.rethrowAsParcelableException();
1822         }
1823     }
1824
1825     @Override
1826     public void setFirewallEgressDestRule(String addr, int port, boolean allow) {
1827         enforceSystemUid();
1828         Preconditions.checkState(mFirewallEnabled);
1829         final String rule = allow ? "allow" : "deny";
1830         try {
1831             mConnector.execute("firewall", "set_egress_dest_rule", addr, port, rule);
1832         } catch (NativeDaemonConnectorException e) {
1833             throw e.rethrowAsParcelableException();
1834         }
1835     }
1836
1837     @Override
1838     public void setFirewallUidRule(int uid, boolean allow) {
1839         enforceSystemUid();
1840         Preconditions.checkState(mFirewallEnabled);
1841         final String rule = allow ? "allow" : "deny";
1842         try {
1843             mConnector.execute("firewall", "set_uid_rule", uid, rule);
1844         } catch (NativeDaemonConnectorException e) {
1845             throw e.rethrowAsParcelableException();
1846         }
1847     }
1848
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");
1853         }
1854     }
1855
1856     @Override
1857     public void startClatd(String interfaceName) throws IllegalStateException {
1858         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1859
1860         try {
1861             mConnector.execute("clatd", "start", interfaceName);
1862         } catch (NativeDaemonConnectorException e) {
1863             throw e.rethrowAsParcelableException();
1864         }
1865     }
1866
1867     @Override
1868     public void stopClatd(String interfaceName) throws IllegalStateException {
1869         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1870
1871         try {
1872             mConnector.execute("clatd", "stop", interfaceName);
1873         } catch (NativeDaemonConnectorException e) {
1874             throw e.rethrowAsParcelableException();
1875         }
1876     }
1877
1878     @Override
1879     public boolean isClatdStarted(String interfaceName) {
1880         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1881
1882         final NativeDaemonEvent event;
1883         try {
1884             event = mConnector.execute("clatd", "status", interfaceName);
1885         } catch (NativeDaemonConnectorException e) {
1886             throw e.rethrowAsParcelableException();
1887         }
1888
1889         event.checkCode(ClatdStatusResult);
1890         return event.getMessage().endsWith("started");
1891     }
1892
1893     @Override
1894     public void registerNetworkActivityListener(INetworkActivityListener listener) {
1895         mNetworkActivityListeners.register(listener);
1896     }
1897
1898     @Override
1899     public void unregisterNetworkActivityListener(INetworkActivityListener listener) {
1900         mNetworkActivityListeners.unregister(listener);
1901     }
1902
1903     @Override
1904     public boolean isNetworkActive() {
1905         synchronized (mNetworkActivityListeners) {
1906             return mNetworkActive || mActiveIdleTimers.isEmpty();
1907         }
1908     }
1909
1910     private void reportNetworkActive() {
1911         final int length = mNetworkActivityListeners.beginBroadcast();
1912         try {
1913             for (int i = 0; i < length; i++) {
1914                 try {
1915                     mNetworkActivityListeners.getBroadcastItem(i).onNetworkActive();
1916                 } catch (RemoteException e) {
1917                 } catch (RuntimeException e) {
1918                 }
1919             }
1920         } finally {
1921             mNetworkActivityListeners.finishBroadcast();
1922         }
1923     }
1924
1925     /** {@inheritDoc} */
1926     @Override
1927     public void monitor() {
1928         if (mConnector != null) {
1929             mConnector.monitor();
1930         }
1931     }
1932
1933     @Override
1934     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1935         mContext.enforceCallingOrSelfPermission(DUMP, TAG);
1936
1937         pw.println("NetworkManagementService NativeDaemonConnector Log:");
1938         mConnector.dump(fd, pw, args);
1939         pw.println();
1940
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);
1945
1946         synchronized (mQuotaLock) {
1947             pw.print("Active quota ifaces: "); pw.println(mActiveQuotas.toString());
1948             pw.print("Active alert ifaces: "); pw.println(mActiveAlerts.toString());
1949         }
1950
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(",");
1957             }
1958             pw.println("]");
1959         }
1960
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);
1969             }
1970         }
1971
1972         pw.print("Firewall enabled: "); pw.println(mFirewallEnabled);
1973     }
1974
1975     @Override
1976     public void createPhysicalNetwork(int netId) {
1977         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1978
1979         try {
1980             mConnector.execute("network", "create", netId);
1981         } catch (NativeDaemonConnectorException e) {
1982             throw e.rethrowAsParcelableException();
1983         }
1984     }
1985
1986     @Override
1987     public void createVirtualNetwork(int netId, boolean hasDNS, boolean secure) {
1988         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1989
1990         try {
1991             mConnector.execute("network", "create", netId, "vpn", hasDNS ? "1" : "0",
1992                     secure ? "1" : "0");
1993         } catch (NativeDaemonConnectorException e) {
1994             throw e.rethrowAsParcelableException();
1995         }
1996     }
1997
1998     @Override
1999     public void removeNetwork(int netId) {
2000         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2001
2002         try {
2003             mConnector.execute("network", "destroy", netId);
2004         } catch (NativeDaemonConnectorException e) {
2005             throw e.rethrowAsParcelableException();
2006         }
2007     }
2008
2009     @Override
2010     public void addInterfaceToNetwork(String iface, int netId) {
2011         modifyInterfaceInNetwork("add", "" + netId, iface);
2012     }
2013
2014     @Override
2015     public void removeInterfaceFromNetwork(String iface, int netId) {
2016         modifyInterfaceInNetwork("remove", "" + netId, iface);
2017     }
2018
2019     private void modifyInterfaceInNetwork(String action, String netId, String iface) {
2020         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2021         try {
2022             mConnector.execute("network", "interface", action, netId, iface);
2023         } catch (NativeDaemonConnectorException e) {
2024             throw e.rethrowAsParcelableException();
2025         }
2026     }
2027
2028     @Override
2029     public void addLegacyRouteForNetId(int netId, RouteInfo routeInfo, int uid) {
2030         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2031
2032         final Command cmd = new Command("network", "route", "legacy", uid, "add", netId);
2033
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());
2040         }
2041
2042         try {
2043             mConnector.execute(cmd);
2044         } catch (NativeDaemonConnectorException e) {
2045             throw e.rethrowAsParcelableException();
2046         }
2047     }
2048
2049     @Override
2050     public void setDefaultNetId(int netId) {
2051         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2052
2053         try {
2054             mConnector.execute("network", "default", "set", netId);
2055         } catch (NativeDaemonConnectorException e) {
2056             throw e.rethrowAsParcelableException();
2057         }
2058     }
2059
2060     @Override
2061     public void clearDefaultNetId() {
2062         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2063
2064         try {
2065             mConnector.execute("network", "default", "clear");
2066         } catch (NativeDaemonConnectorException e) {
2067             throw e.rethrowAsParcelableException();
2068         }
2069     }
2070
2071     @Override
2072     public void setPermission(String permission, int[] uids) {
2073         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2074
2075         Object[] argv = new Object[4 + MAX_UID_RANGES_PER_COMMAND];
2076         argv[0] = "permission";
2077         argv[1] = "user";
2078         argv[2] = "set";
2079         argv[3] = permission;
2080         int argc = 4;
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) {
2085                 try {
2086                     mConnector.execute("network", Arrays.copyOf(argv, argc));
2087                 } catch (NativeDaemonConnectorException e) {
2088                     throw e.rethrowAsParcelableException();
2089                 }
2090                 argc = 4;
2091             }
2092         }
2093     }
2094
2095     @Override
2096     public void clearPermission(int[] uids) {
2097         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2098
2099         Object[] argv = new Object[3 + MAX_UID_RANGES_PER_COMMAND];
2100         argv[0] = "permission";
2101         argv[1] = "user";
2102         argv[2] = "clear";
2103         int argc = 3;
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) {
2108                 try {
2109                     mConnector.execute("network", Arrays.copyOf(argv, argc));
2110                 } catch (NativeDaemonConnectorException e) {
2111                     throw e.rethrowAsParcelableException();
2112                 }
2113                 argc = 3;
2114             }
2115         }
2116     }
2117
2118     @Override
2119     public void allowProtect(int uid) {
2120         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2121
2122         try {
2123             mConnector.execute("network", "protect", "allow", uid);
2124         } catch (NativeDaemonConnectorException e) {
2125             throw e.rethrowAsParcelableException();
2126         }
2127     }
2128
2129     @Override
2130     public void denyProtect(int uid) {
2131         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2132
2133         try {
2134             mConnector.execute("network", "protect", "deny", uid);
2135         } catch (NativeDaemonConnectorException e) {
2136             throw e.rethrowAsParcelableException();
2137         }
2138     }
2139
2140     @Override
2141     public void addInterfaceToLocalNetwork(String iface, List<RouteInfo> routes) {
2142         modifyInterfaceInNetwork("add", "local", iface);
2143
2144         for (RouteInfo route : routes) {
2145             if (!route.isDefaultRoute()) {
2146                 modifyRoute("add", "local", route);
2147             }
2148         }
2149     }
2150
2151     @Override
2152     public void removeInterfaceFromLocalNetwork(String iface) {
2153         modifyInterfaceInNetwork("remove", "local", iface);
2154     }
2155 }