NetworkManagementService.java revision 4b0f8e6fb707e19799011c1f4a5e4f54603e34b1
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
17package com.android.server;
18
19import static android.Manifest.permission.CHANGE_NETWORK_STATE;
20import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
21import static android.Manifest.permission.DUMP;
22import static android.Manifest.permission.SHUTDOWN;
23import static android.net.NetworkStats.SET_DEFAULT;
24import static android.net.NetworkStats.TAG_ALL;
25import static android.net.NetworkStats.TAG_NONE;
26import static android.net.NetworkStats.UID_ALL;
27import static android.net.TrafficStats.UID_TETHERING;
28import static android.net.RouteInfo.RTN_THROW;
29import static android.net.RouteInfo.RTN_UNICAST;
30import static android.net.RouteInfo.RTN_UNREACHABLE;
31import static android.system.OsConstants.AF_INET;
32import static android.system.OsConstants.AF_INET6;
33import static com.android.server.NetworkManagementService.NetdResponseCode.ClatdStatusResult;
34import static com.android.server.NetworkManagementService.NetdResponseCode.InterfaceGetCfgResult;
35import static com.android.server.NetworkManagementService.NetdResponseCode.InterfaceListResult;
36import static com.android.server.NetworkManagementService.NetdResponseCode.IpFwdStatusResult;
37import static com.android.server.NetworkManagementService.NetdResponseCode.TetherDnsFwdTgtListResult;
38import static com.android.server.NetworkManagementService.NetdResponseCode.TetherInterfaceListResult;
39import static com.android.server.NetworkManagementService.NetdResponseCode.TetherStatusResult;
40import static com.android.server.NetworkManagementService.NetdResponseCode.TetheringStatsListResult;
41import static com.android.server.NetworkManagementService.NetdResponseCode.TtyListResult;
42import static com.android.server.NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED;
43
44import android.content.Context;
45import android.net.ConnectivityManager;
46import android.net.INetworkManagementEventObserver;
47import android.net.InterfaceConfiguration;
48import android.net.IpPrefix;
49import android.net.LinkAddress;
50import android.net.Network;
51import android.net.NetworkStats;
52import android.net.NetworkUtils;
53import android.net.RouteInfo;
54import android.net.UidRange;
55import android.net.wifi.WifiConfiguration;
56import android.net.wifi.WifiConfiguration.KeyMgmt;
57import android.os.BatteryStats;
58import android.os.Binder;
59import android.os.Handler;
60import android.os.INetworkActivityListener;
61import android.os.INetworkManagementService;
62import android.os.PowerManager;
63import android.os.Process;
64import android.os.RemoteCallbackList;
65import android.os.RemoteException;
66import android.os.ServiceManager;
67import android.os.SystemClock;
68import android.os.SystemProperties;
69import android.telephony.DataConnectionRealTimeInfo;
70import android.telephony.PhoneStateListener;
71import android.telephony.SubscriptionManager;
72import android.telephony.TelephonyManager;
73import android.util.Log;
74import android.util.Slog;
75import android.util.SparseBooleanArray;
76
77import com.android.internal.app.IBatteryStats;
78import com.android.internal.net.NetworkStatsFactory;
79import com.android.internal.util.Preconditions;
80import com.android.server.NativeDaemonConnector.Command;
81import com.android.server.NativeDaemonConnector.SensitiveArg;
82import com.android.server.net.LockdownVpnTracker;
83import com.google.android.collect.Maps;
84
85import java.io.BufferedReader;
86import java.io.DataInputStream;
87import java.io.File;
88import java.io.FileDescriptor;
89import java.io.FileInputStream;
90import java.io.IOException;
91import java.io.InputStreamReader;
92import java.io.PrintWriter;
93import java.net.Inet4Address;
94import java.net.Inet6Address;
95import java.net.InetAddress;
96import java.net.InterfaceAddress;
97import java.net.NetworkInterface;
98import java.net.SocketException;
99import java.util.ArrayList;
100import java.util.Arrays;
101import java.util.HashMap;
102import java.util.List;
103import java.util.Map;
104import java.util.NoSuchElementException;
105import java.util.StringTokenizer;
106import java.util.concurrent.CountDownLatch;
107
108/**
109 * @hide
110 */
111public class NetworkManagementService extends INetworkManagementService.Stub
112        implements Watchdog.Monitor {
113    private static final String TAG = "NetworkManagementService";
114    private static final boolean DBG = false;
115    private static final String NETD_TAG = "NetdConnector";
116    private static final String NETD_SOCKET_NAME = "netd";
117
118    private static final int MAX_UID_RANGES_PER_COMMAND = 10;
119
120    /**
121     * Name representing {@link #setGlobalAlert(long)} limit when delivered to
122     * {@link INetworkManagementEventObserver#limitReached(String, String)}.
123     */
124    public static final String LIMIT_GLOBAL_ALERT = "globalAlert";
125
126    class NetdResponseCode {
127        /* Keep in sync with system/netd/server/ResponseCode.h */
128        public static final int InterfaceListResult       = 110;
129        public static final int TetherInterfaceListResult = 111;
130        public static final int TetherDnsFwdTgtListResult = 112;
131        public static final int TtyListResult             = 113;
132        public static final int TetheringStatsListResult  = 114;
133
134        public static final int TetherStatusResult        = 210;
135        public static final int IpFwdStatusResult         = 211;
136        public static final int InterfaceGetCfgResult     = 213;
137        public static final int SoftapStatusResult        = 214;
138        public static final int InterfaceRxCounterResult  = 216;
139        public static final int InterfaceTxCounterResult  = 217;
140        public static final int QuotaCounterResult        = 220;
141        public static final int TetheringStatsResult      = 221;
142        public static final int DnsProxyQueryResult       = 222;
143        public static final int ClatdStatusResult         = 223;
144
145        public static final int InterfaceChange           = 600;
146        public static final int BandwidthControl          = 601;
147        public static final int InterfaceClassActivity    = 613;
148        public static final int InterfaceAddressChange    = 614;
149        public static final int InterfaceDnsServerInfo    = 615;
150        public static final int RouteChange               = 616;
151    }
152
153    static final int DAEMON_MSG_MOBILE_CONN_REAL_TIME_INFO = 1;
154
155    /**
156     * Binder context for this service
157     */
158    private final Context mContext;
159
160    /**
161     * connector object for communicating with netd
162     */
163    private final NativeDaemonConnector mConnector;
164
165    private final Handler mFgHandler;
166    private final Handler mDaemonHandler;
167    private final PhoneStateListener mPhoneStateListener;
168
169    private IBatteryStats mBatteryStats;
170
171    private final Thread mThread;
172    private CountDownLatch mConnectedSignal = new CountDownLatch(1);
173
174    private final RemoteCallbackList<INetworkManagementEventObserver> mObservers =
175            new RemoteCallbackList<INetworkManagementEventObserver>();
176
177    private final NetworkStatsFactory mStatsFactory = new NetworkStatsFactory();
178
179    private Object mQuotaLock = new Object();
180    /** Set of interfaces with active quotas. */
181    private HashMap<String, Long> mActiveQuotas = Maps.newHashMap();
182    /** Set of interfaces with active alerts. */
183    private HashMap<String, Long> mActiveAlerts = Maps.newHashMap();
184    /** Set of UIDs with active reject rules. */
185    private SparseBooleanArray mUidRejectOnQuota = new SparseBooleanArray();
186
187    private Object mIdleTimerLock = new Object();
188    /** Set of interfaces with active idle timers. */
189    private static class IdleTimerParams {
190        public final int timeout;
191        public final int type;
192        public int networkCount;
193
194        IdleTimerParams(int timeout, int type) {
195            this.timeout = timeout;
196            this.type = type;
197            this.networkCount = 1;
198        }
199    }
200    private HashMap<String, IdleTimerParams> mActiveIdleTimers = Maps.newHashMap();
201
202    private volatile boolean mBandwidthControlEnabled;
203    private volatile boolean mFirewallEnabled;
204
205    private boolean mMobileActivityFromRadio = false;
206    private int mLastPowerStateFromRadio = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
207
208    private final RemoteCallbackList<INetworkActivityListener> mNetworkActivityListeners =
209            new RemoteCallbackList<INetworkActivityListener>();
210    private boolean mNetworkActive;
211
212    /**
213     * Constructs a new NetworkManagementService instance
214     *
215     * @param context  Binder context for this service
216     */
217    private NetworkManagementService(Context context, String socket) {
218        mContext = context;
219
220        // make sure this is on the same looper as our NativeDaemonConnector for sync purposes
221        mFgHandler = new Handler(FgThread.get().getLooper());
222
223        if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
224            mConnector = null;
225            mThread = null;
226            mDaemonHandler = null;
227            mPhoneStateListener = null;
228            return;
229        }
230
231        // Don't need this wake lock, since we now have a time stamp for when
232        // the network actually went inactive.  (It might be nice to still do this,
233        // but I don't want to do it through the power manager because that pollutes the
234        // battery stats history with pointless noise.)
235        //PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
236        PowerManager.WakeLock wl = null; //pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, NETD_TAG);
237
238        mConnector = new NativeDaemonConnector(
239                new NetdCallbackReceiver(), socket, 10, NETD_TAG, 160, wl,
240                FgThread.get().getLooper());
241        mThread = new Thread(mConnector, NETD_TAG);
242
243        mDaemonHandler = new Handler(FgThread.get().getLooper());
244
245        mPhoneStateListener = new PhoneStateListener(SubscriptionManager.DEFAULT_SUB_ID,
246                mDaemonHandler.getLooper()) {
247            @Override
248            public void onDataConnectionRealTimeInfoChanged(
249                    DataConnectionRealTimeInfo dcRtInfo) {
250                if (DBG) Slog.d(TAG, "onDataConnectionRealTimeInfoChanged: " + dcRtInfo);
251                notifyInterfaceClassActivity(ConnectivityManager.TYPE_MOBILE,
252                        dcRtInfo.getDcPowerState(), dcRtInfo.getTime(), true);
253            }
254        };
255        TelephonyManager tm = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
256        if (tm != null) {
257            tm.listen(mPhoneStateListener,
258                    PhoneStateListener.LISTEN_DATA_CONNECTION_REAL_TIME_INFO);
259        }
260
261        // Add ourself to the Watchdog monitors.
262        Watchdog.getInstance().addMonitor(this);
263    }
264
265    static NetworkManagementService create(Context context,
266            String socket) throws InterruptedException {
267        final NetworkManagementService service = new NetworkManagementService(context, socket);
268        final CountDownLatch connectedSignal = service.mConnectedSignal;
269        if (DBG) Slog.d(TAG, "Creating NetworkManagementService");
270        service.mThread.start();
271        if (DBG) Slog.d(TAG, "Awaiting socket connection");
272        connectedSignal.await();
273        if (DBG) Slog.d(TAG, "Connected");
274        return service;
275    }
276
277    public static NetworkManagementService create(Context context) throws InterruptedException {
278        return create(context, NETD_SOCKET_NAME);
279    }
280
281    public void systemReady() {
282        prepareNativeDaemon();
283        if (DBG) Slog.d(TAG, "Prepared");
284    }
285
286    private IBatteryStats getBatteryStats() {
287        synchronized (this) {
288            if (mBatteryStats != null) {
289                return mBatteryStats;
290            }
291            mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService(
292                    BatteryStats.SERVICE_NAME));
293            return mBatteryStats;
294        }
295    }
296
297    @Override
298    public void registerObserver(INetworkManagementEventObserver observer) {
299        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
300        mObservers.register(observer);
301    }
302
303    @Override
304    public void unregisterObserver(INetworkManagementEventObserver observer) {
305        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
306        mObservers.unregister(observer);
307    }
308
309    /**
310     * Notify our observers of an interface status change
311     */
312    private void notifyInterfaceStatusChanged(String iface, boolean up) {
313        final int length = mObservers.beginBroadcast();
314        try {
315            for (int i = 0; i < length; i++) {
316                try {
317                    mObservers.getBroadcastItem(i).interfaceStatusChanged(iface, up);
318                } catch (RemoteException e) {
319                } catch (RuntimeException e) {
320                }
321            }
322        } finally {
323            mObservers.finishBroadcast();
324        }
325    }
326
327    /**
328     * Notify our observers of an interface link state change
329     * (typically, an Ethernet cable has been plugged-in or unplugged).
330     */
331    private void notifyInterfaceLinkStateChanged(String iface, boolean up) {
332        final int length = mObservers.beginBroadcast();
333        try {
334            for (int i = 0; i < length; i++) {
335                try {
336                    mObservers.getBroadcastItem(i).interfaceLinkStateChanged(iface, up);
337                } catch (RemoteException e) {
338                } catch (RuntimeException e) {
339                }
340            }
341        } finally {
342            mObservers.finishBroadcast();
343        }
344    }
345
346    /**
347     * Notify our observers of an interface addition.
348     */
349    private void notifyInterfaceAdded(String iface) {
350        final int length = mObservers.beginBroadcast();
351        try {
352            for (int i = 0; i < length; i++) {
353                try {
354                    mObservers.getBroadcastItem(i).interfaceAdded(iface);
355                } catch (RemoteException e) {
356                } catch (RuntimeException e) {
357                }
358            }
359        } finally {
360            mObservers.finishBroadcast();
361        }
362    }
363
364    /**
365     * Notify our observers of an interface removal.
366     */
367    private void notifyInterfaceRemoved(String iface) {
368        // netd already clears out quota and alerts for removed ifaces; update
369        // our sanity-checking state.
370        mActiveAlerts.remove(iface);
371        mActiveQuotas.remove(iface);
372
373        final int length = mObservers.beginBroadcast();
374        try {
375            for (int i = 0; i < length; i++) {
376                try {
377                    mObservers.getBroadcastItem(i).interfaceRemoved(iface);
378                } catch (RemoteException e) {
379                } catch (RuntimeException e) {
380                }
381            }
382        } finally {
383            mObservers.finishBroadcast();
384        }
385    }
386
387    /**
388     * Notify our observers of a limit reached.
389     */
390    private void notifyLimitReached(String limitName, String iface) {
391        final int length = mObservers.beginBroadcast();
392        try {
393            for (int i = 0; i < length; i++) {
394                try {
395                    mObservers.getBroadcastItem(i).limitReached(limitName, iface);
396                } catch (RemoteException e) {
397                } catch (RuntimeException e) {
398                }
399            }
400        } finally {
401            mObservers.finishBroadcast();
402        }
403    }
404
405    /**
406     * Notify our observers of a change in the data activity state of the interface
407     */
408    private void notifyInterfaceClassActivity(int type, int powerState, long tsNanos,
409            boolean fromRadio) {
410        final boolean isMobile = ConnectivityManager.isNetworkTypeMobile(type);
411        if (isMobile) {
412            if (!fromRadio) {
413                if (mMobileActivityFromRadio) {
414                    // If this call is not coming from a report from the radio itself, but we
415                    // have previously received reports from the radio, then we will take the
416                    // power state to just be whatever the radio last reported.
417                    powerState = mLastPowerStateFromRadio;
418                }
419            } else {
420                mMobileActivityFromRadio = true;
421            }
422            if (mLastPowerStateFromRadio != powerState) {
423                mLastPowerStateFromRadio = powerState;
424                try {
425                    getBatteryStats().noteMobileRadioPowerState(powerState, tsNanos);
426                } catch (RemoteException e) {
427                }
428            }
429        }
430
431        boolean isActive = powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_MEDIUM
432                || powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH;
433
434        if (!isMobile || fromRadio || !mMobileActivityFromRadio) {
435            // Report the change in data activity.  We don't do this if this is a change
436            // on the mobile network, that is not coming from the radio itself, and we
437            // have previously seen change reports from the radio.  In that case only
438            // the radio is the authority for the current state.
439            final int length = mObservers.beginBroadcast();
440            try {
441                for (int i = 0; i < length; i++) {
442                    try {
443                        mObservers.getBroadcastItem(i).interfaceClassDataActivityChanged(
444                                Integer.toString(type), isActive, tsNanos);
445                    } catch (RemoteException e) {
446                    } catch (RuntimeException e) {
447                    }
448                }
449            } finally {
450                mObservers.finishBroadcast();
451            }
452        }
453
454        boolean report = false;
455        synchronized (mIdleTimerLock) {
456            if (mActiveIdleTimers.isEmpty()) {
457                // If there are no idle timers, we are not monitoring activity, so we
458                // are always considered active.
459                isActive = true;
460            }
461            if (mNetworkActive != isActive) {
462                mNetworkActive = isActive;
463                report = isActive;
464            }
465        }
466        if (report) {
467            reportNetworkActive();
468        }
469    }
470
471    /**
472     * Prepare native daemon once connected, enabling modules and pushing any
473     * existing in-memory rules.
474     */
475    private void prepareNativeDaemon() {
476        mBandwidthControlEnabled = false;
477
478        // only enable bandwidth control when support exists
479        final boolean hasKernelSupport = new File("/proc/net/xt_qtaguid/ctrl").exists();
480        if (hasKernelSupport) {
481            Slog.d(TAG, "enabling bandwidth control");
482            try {
483                mConnector.execute("bandwidth", "enable");
484                mBandwidthControlEnabled = true;
485            } catch (NativeDaemonConnectorException e) {
486                Log.wtf(TAG, "problem enabling bandwidth controls", e);
487            }
488        } else {
489            Slog.d(TAG, "not enabling bandwidth control");
490        }
491
492        SystemProperties.set(PROP_QTAGUID_ENABLED, mBandwidthControlEnabled ? "1" : "0");
493
494        if (mBandwidthControlEnabled) {
495            try {
496                getBatteryStats().noteNetworkStatsEnabled();
497            } catch (RemoteException e) {
498            }
499        }
500
501        // push any existing quota or UID rules
502        synchronized (mQuotaLock) {
503            int size = mActiveQuotas.size();
504            if (size > 0) {
505                Slog.d(TAG, "pushing " + size + " active quota rules");
506                final HashMap<String, Long> activeQuotas = mActiveQuotas;
507                mActiveQuotas = Maps.newHashMap();
508                for (Map.Entry<String, Long> entry : activeQuotas.entrySet()) {
509                    setInterfaceQuota(entry.getKey(), entry.getValue());
510                }
511            }
512
513            size = mActiveAlerts.size();
514            if (size > 0) {
515                Slog.d(TAG, "pushing " + size + " active alert rules");
516                final HashMap<String, Long> activeAlerts = mActiveAlerts;
517                mActiveAlerts = Maps.newHashMap();
518                for (Map.Entry<String, Long> entry : activeAlerts.entrySet()) {
519                    setInterfaceAlert(entry.getKey(), entry.getValue());
520                }
521            }
522
523            size = mUidRejectOnQuota.size();
524            if (size > 0) {
525                Slog.d(TAG, "pushing " + size + " active uid rules");
526                final SparseBooleanArray uidRejectOnQuota = mUidRejectOnQuota;
527                mUidRejectOnQuota = new SparseBooleanArray();
528                for (int i = 0; i < uidRejectOnQuota.size(); i++) {
529                    setUidNetworkRules(uidRejectOnQuota.keyAt(i), uidRejectOnQuota.valueAt(i));
530                }
531            }
532        }
533
534        // TODO: Push any existing firewall state
535        setFirewallEnabled(mFirewallEnabled || LockdownVpnTracker.isEnabled());
536    }
537
538    /**
539     * Notify our observers of a new or updated interface address.
540     */
541    private void notifyAddressUpdated(String iface, LinkAddress address) {
542        final int length = mObservers.beginBroadcast();
543        try {
544            for (int i = 0; i < length; i++) {
545                try {
546                    mObservers.getBroadcastItem(i).addressUpdated(iface, address);
547                } catch (RemoteException e) {
548                } catch (RuntimeException e) {
549                }
550            }
551        } finally {
552            mObservers.finishBroadcast();
553        }
554    }
555
556    /**
557     * Notify our observers of a deleted interface address.
558     */
559    private void notifyAddressRemoved(String iface, LinkAddress address) {
560        final int length = mObservers.beginBroadcast();
561        try {
562            for (int i = 0; i < length; i++) {
563                try {
564                    mObservers.getBroadcastItem(i).addressRemoved(iface, address);
565                } catch (RemoteException e) {
566                } catch (RuntimeException e) {
567                }
568            }
569        } finally {
570            mObservers.finishBroadcast();
571        }
572    }
573
574    /**
575     * Notify our observers of DNS server information received.
576     */
577    private void notifyInterfaceDnsServerInfo(String iface, long lifetime, String[] addresses) {
578        final int length = mObservers.beginBroadcast();
579        try {
580            for (int i = 0; i < length; i++) {
581                try {
582                    mObservers.getBroadcastItem(i).interfaceDnsServerInfo(iface, lifetime,
583                        addresses);
584                } catch (RemoteException e) {
585                } catch (RuntimeException e) {
586                }
587            }
588        } finally {
589            mObservers.finishBroadcast();
590        }
591    }
592
593    /**
594     * Notify our observers of a route change.
595     */
596    private void notifyRouteChange(String action, RouteInfo route) {
597        final int length = mObservers.beginBroadcast();
598        try {
599            for (int i = 0; i < length; i++) {
600                try {
601                    if (action.equals("updated")) {
602                        mObservers.getBroadcastItem(i).routeUpdated(route);
603                    } else {
604                        mObservers.getBroadcastItem(i).routeRemoved(route);
605                    }
606                } catch (RemoteException e) {
607                } catch (RuntimeException e) {
608                }
609            }
610        } finally {
611            mObservers.finishBroadcast();
612        }
613    }
614
615    //
616    // Netd Callback handling
617    //
618
619    private class NetdCallbackReceiver implements INativeDaemonConnectorCallbacks {
620        @Override
621        public void onDaemonConnected() {
622            // event is dispatched from internal NDC thread, so we prepare the
623            // daemon back on main thread.
624            if (mConnectedSignal != null) {
625                mConnectedSignal.countDown();
626                mConnectedSignal = null;
627            } else {
628                mFgHandler.post(new Runnable() {
629                    @Override
630                    public void run() {
631                        prepareNativeDaemon();
632                    }
633                });
634            }
635        }
636
637        @Override
638        public boolean onCheckHoldWakeLock(int code) {
639            return code == NetdResponseCode.InterfaceClassActivity;
640        }
641
642        @Override
643        public boolean onEvent(int code, String raw, String[] cooked) {
644            String errorMessage = String.format("Invalid event from daemon (%s)", raw);
645            switch (code) {
646            case NetdResponseCode.InterfaceChange:
647                    /*
648                     * a network interface change occured
649                     * Format: "NNN Iface added <name>"
650                     *         "NNN Iface removed <name>"
651                     *         "NNN Iface changed <name> <up/down>"
652                     *         "NNN Iface linkstatus <name> <up/down>"
653                     */
654                    if (cooked.length < 4 || !cooked[1].equals("Iface")) {
655                        throw new IllegalStateException(errorMessage);
656                    }
657                    if (cooked[2].equals("added")) {
658                        notifyInterfaceAdded(cooked[3]);
659                        return true;
660                    } else if (cooked[2].equals("removed")) {
661                        notifyInterfaceRemoved(cooked[3]);
662                        return true;
663                    } else if (cooked[2].equals("changed") && cooked.length == 5) {
664                        notifyInterfaceStatusChanged(cooked[3], cooked[4].equals("up"));
665                        return true;
666                    } else if (cooked[2].equals("linkstate") && cooked.length == 5) {
667                        notifyInterfaceLinkStateChanged(cooked[3], cooked[4].equals("up"));
668                        return true;
669                    }
670                    throw new IllegalStateException(errorMessage);
671                    // break;
672            case NetdResponseCode.BandwidthControl:
673                    /*
674                     * Bandwidth control needs some attention
675                     * Format: "NNN limit alert <alertName> <ifaceName>"
676                     */
677                    if (cooked.length < 5 || !cooked[1].equals("limit")) {
678                        throw new IllegalStateException(errorMessage);
679                    }
680                    if (cooked[2].equals("alert")) {
681                        notifyLimitReached(cooked[3], cooked[4]);
682                        return true;
683                    }
684                    throw new IllegalStateException(errorMessage);
685                    // break;
686            case NetdResponseCode.InterfaceClassActivity:
687                    /*
688                     * An network interface class state changed (active/idle)
689                     * Format: "NNN IfaceClass <active/idle> <label>"
690                     */
691                    if (cooked.length < 4 || !cooked[1].equals("IfaceClass")) {
692                        throw new IllegalStateException(errorMessage);
693                    }
694                    long timestampNanos = 0;
695                    if (cooked.length == 5) {
696                        try {
697                            timestampNanos = Long.parseLong(cooked[4]);
698                        } catch(NumberFormatException ne) {}
699                    } else {
700                        timestampNanos = SystemClock.elapsedRealtimeNanos();
701                    }
702                    boolean isActive = cooked[2].equals("active");
703                    notifyInterfaceClassActivity(Integer.parseInt(cooked[3]),
704                            isActive ? DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH
705                            : DataConnectionRealTimeInfo.DC_POWER_STATE_LOW, timestampNanos, false);
706                    return true;
707                    // break;
708            case NetdResponseCode.InterfaceAddressChange:
709                    /*
710                     * A network address change occurred
711                     * Format: "NNN Address updated <addr> <iface> <flags> <scope>"
712                     *         "NNN Address removed <addr> <iface> <flags> <scope>"
713                     */
714                    if (cooked.length < 7 || !cooked[1].equals("Address")) {
715                        throw new IllegalStateException(errorMessage);
716                    }
717
718                    String iface = cooked[4];
719                    LinkAddress address;
720                    try {
721                        int flags = Integer.parseInt(cooked[5]);
722                        int scope = Integer.parseInt(cooked[6]);
723                        address = new LinkAddress(cooked[3], flags, scope);
724                    } catch(NumberFormatException e) {     // Non-numeric lifetime or scope.
725                        throw new IllegalStateException(errorMessage, e);
726                    } catch(IllegalArgumentException e) {  // Malformed/invalid IP address.
727                        throw new IllegalStateException(errorMessage, e);
728                    }
729
730                    if (cooked[2].equals("updated")) {
731                        notifyAddressUpdated(iface, address);
732                    } else {
733                        notifyAddressRemoved(iface, address);
734                    }
735                    return true;
736                    // break;
737            case NetdResponseCode.InterfaceDnsServerInfo:
738                    /*
739                     * Information about available DNS servers has been received.
740                     * Format: "NNN DnsInfo servers <interface> <lifetime> <servers>"
741                     */
742                    long lifetime;  // Actually a 32-bit unsigned integer.
743
744                    if (cooked.length == 6 &&
745                        cooked[1].equals("DnsInfo") &&
746                        cooked[2].equals("servers")) {
747                        try {
748                            lifetime = Long.parseLong(cooked[4]);
749                        } catch (NumberFormatException e) {
750                            throw new IllegalStateException(errorMessage);
751                        }
752                        String[] servers = cooked[5].split(",");
753                        notifyInterfaceDnsServerInfo(cooked[3], lifetime, servers);
754                    }
755                    return true;
756                    // break;
757            case NetdResponseCode.RouteChange:
758                    /*
759                     * A route has been updated or removed.
760                     * Format: "NNN Route <updated|removed> <dst> [via <gateway] [dev <iface>]"
761                     */
762                    if (!cooked[1].equals("Route") || cooked.length < 6) {
763                        throw new IllegalStateException(errorMessage);
764                    }
765
766                    String via = null;
767                    String dev = null;
768                    boolean valid = true;
769                    for (int i = 4; (i + 1) < cooked.length && valid; i += 2) {
770                        if (cooked[i].equals("dev")) {
771                            if (dev == null) {
772                                dev = cooked[i+1];
773                            } else {
774                                valid = false;  // Duplicate interface.
775                            }
776                        } else if (cooked[i].equals("via")) {
777                            if (via == null) {
778                                via = cooked[i+1];
779                            } else {
780                                valid = false;  // Duplicate gateway.
781                            }
782                        } else {
783                            valid = false;      // Unknown syntax.
784                        }
785                    }
786                    if (valid) {
787                        try {
788                            // InetAddress.parseNumericAddress(null) inexplicably returns ::1.
789                            InetAddress gateway = null;
790                            if (via != null) gateway = InetAddress.parseNumericAddress(via);
791                            RouteInfo route = new RouteInfo(new IpPrefix(cooked[3]), gateway, dev);
792                            notifyRouteChange(cooked[2], route);
793                            return true;
794                        } catch (IllegalArgumentException e) {}
795                    }
796                    throw new IllegalStateException(errorMessage);
797                    // break;
798            default: break;
799            }
800            return false;
801        }
802    }
803
804
805    //
806    // INetworkManagementService members
807    //
808
809    @Override
810    public String[] listInterfaces() {
811        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
812        try {
813            return NativeDaemonEvent.filterMessageList(
814                    mConnector.executeForList("interface", "list"), InterfaceListResult);
815        } catch (NativeDaemonConnectorException e) {
816            throw e.rethrowAsParcelableException();
817        }
818    }
819
820    @Override
821    public InterfaceConfiguration getInterfaceConfig(String iface) {
822        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
823
824        final NativeDaemonEvent event;
825        try {
826            event = mConnector.execute("interface", "getcfg", iface);
827        } catch (NativeDaemonConnectorException e) {
828            throw e.rethrowAsParcelableException();
829        }
830
831        event.checkCode(InterfaceGetCfgResult);
832
833        // Rsp: 213 xx:xx:xx:xx:xx:xx yyy.yyy.yyy.yyy zzz flag1 flag2 flag3
834        final StringTokenizer st = new StringTokenizer(event.getMessage());
835
836        InterfaceConfiguration cfg;
837        try {
838            cfg = new InterfaceConfiguration();
839            cfg.setHardwareAddress(st.nextToken(" "));
840            InetAddress addr = null;
841            int prefixLength = 0;
842            try {
843                addr = NetworkUtils.numericToInetAddress(st.nextToken());
844            } catch (IllegalArgumentException iae) {
845                Slog.e(TAG, "Failed to parse ipaddr", iae);
846            }
847
848            try {
849                prefixLength = Integer.parseInt(st.nextToken());
850            } catch (NumberFormatException nfe) {
851                Slog.e(TAG, "Failed to parse prefixLength", nfe);
852            }
853
854            cfg.setLinkAddress(new LinkAddress(addr, prefixLength));
855            while (st.hasMoreTokens()) {
856                cfg.setFlag(st.nextToken());
857            }
858        } catch (NoSuchElementException nsee) {
859            throw new IllegalStateException("Invalid response from daemon: " + event);
860        }
861        return cfg;
862    }
863
864    @Override
865    public void setInterfaceConfig(String iface, InterfaceConfiguration cfg) {
866        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
867        LinkAddress linkAddr = cfg.getLinkAddress();
868        if (linkAddr == null || linkAddr.getAddress() == null) {
869            throw new IllegalStateException("Null LinkAddress given");
870        }
871
872        final Command cmd = new Command("interface", "setcfg", iface,
873                linkAddr.getAddress().getHostAddress(),
874                linkAddr.getPrefixLength());
875        for (String flag : cfg.getFlags()) {
876            cmd.appendArg(flag);
877        }
878
879        try {
880            mConnector.execute(cmd);
881        } catch (NativeDaemonConnectorException e) {
882            throw e.rethrowAsParcelableException();
883        }
884    }
885
886    @Override
887    public void setInterfaceDown(String iface) {
888        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
889        final InterfaceConfiguration ifcg = getInterfaceConfig(iface);
890        ifcg.setInterfaceDown();
891        setInterfaceConfig(iface, ifcg);
892    }
893
894    @Override
895    public void setInterfaceUp(String iface) {
896        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
897        final InterfaceConfiguration ifcg = getInterfaceConfig(iface);
898        ifcg.setInterfaceUp();
899        setInterfaceConfig(iface, ifcg);
900    }
901
902    @Override
903    public void setInterfaceIpv6PrivacyExtensions(String iface, boolean enable) {
904        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
905        try {
906            mConnector.execute(
907                    "interface", "ipv6privacyextensions", iface, enable ? "enable" : "disable");
908        } catch (NativeDaemonConnectorException e) {
909            throw e.rethrowAsParcelableException();
910        }
911    }
912
913    /* TODO: This is right now a IPv4 only function. Works for wifi which loses its
914       IPv6 addresses on interface down, but we need to do full clean up here */
915    @Override
916    public void clearInterfaceAddresses(String iface) {
917        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
918        try {
919            mConnector.execute("interface", "clearaddrs", iface);
920        } catch (NativeDaemonConnectorException e) {
921            throw e.rethrowAsParcelableException();
922        }
923    }
924
925    @Override
926    public void enableIpv6(String iface) {
927        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
928        try {
929            mConnector.execute("interface", "ipv6", iface, "enable");
930        } catch (NativeDaemonConnectorException e) {
931            throw e.rethrowAsParcelableException();
932        }
933    }
934
935    @Override
936    public void disableIpv6(String iface) {
937        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
938        try {
939            mConnector.execute("interface", "ipv6", iface, "disable");
940        } catch (NativeDaemonConnectorException e) {
941            throw e.rethrowAsParcelableException();
942        }
943    }
944
945    @Override
946    public void addRoute(int netId, RouteInfo route) {
947        modifyRoute("add", "" + netId, route);
948    }
949
950    @Override
951    public void removeRoute(int netId, RouteInfo route) {
952        modifyRoute("remove", "" + netId, route);
953    }
954
955    private void modifyRoute(String action, String netId, RouteInfo route) {
956        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
957
958        final Command cmd = new Command("network", "route", action, netId);
959
960        // create triplet: interface dest-ip-addr/prefixlength gateway-ip-addr
961        cmd.appendArg(route.getInterface());
962        cmd.appendArg(route.getDestination().toString());
963
964        switch (route.getType()) {
965            case RouteInfo.RTN_UNICAST:
966                if (route.hasGateway()) {
967                    cmd.appendArg(route.getGateway().getHostAddress());
968                }
969                break;
970            case RouteInfo.RTN_UNREACHABLE:
971                cmd.appendArg("unreachable");
972                break;
973            case RouteInfo.RTN_THROW:
974                cmd.appendArg("throw");
975                break;
976        }
977
978        try {
979            mConnector.execute(cmd);
980        } catch (NativeDaemonConnectorException e) {
981            throw e.rethrowAsParcelableException();
982        }
983    }
984
985    private ArrayList<String> readRouteList(String filename) {
986        FileInputStream fstream = null;
987        ArrayList<String> list = new ArrayList<String>();
988
989        try {
990            fstream = new FileInputStream(filename);
991            DataInputStream in = new DataInputStream(fstream);
992            BufferedReader br = new BufferedReader(new InputStreamReader(in));
993            String s;
994
995            // throw away the title line
996
997            while (((s = br.readLine()) != null) && (s.length() != 0)) {
998                list.add(s);
999            }
1000        } catch (IOException ex) {
1001            // return current list, possibly empty
1002        } finally {
1003            if (fstream != null) {
1004                try {
1005                    fstream.close();
1006                } catch (IOException ex) {}
1007            }
1008        }
1009
1010        return list;
1011    }
1012
1013    @Override
1014    public RouteInfo[] getRoutes(String interfaceName) {
1015        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1016        ArrayList<RouteInfo> routes = new ArrayList<RouteInfo>();
1017
1018        // v4 routes listed as:
1019        // iface dest-addr gateway-addr flags refcnt use metric netmask mtu window IRTT
1020        for (String s : readRouteList("/proc/net/route")) {
1021            String[] fields = s.split("\t");
1022
1023            if (fields.length > 7) {
1024                String iface = fields[0];
1025
1026                if (interfaceName.equals(iface)) {
1027                    String dest = fields[1];
1028                    String gate = fields[2];
1029                    String flags = fields[3]; // future use?
1030                    String mask = fields[7];
1031                    try {
1032                        // address stored as a hex string, ex: 0014A8C0
1033                        InetAddress destAddr =
1034                                NetworkUtils.intToInetAddress((int)Long.parseLong(dest, 16));
1035                        int prefixLength =
1036                                NetworkUtils.netmaskIntToPrefixLength(
1037                                (int)Long.parseLong(mask, 16));
1038                        LinkAddress linkAddress = new LinkAddress(destAddr, prefixLength);
1039
1040                        // address stored as a hex string, ex 0014A8C0
1041                        InetAddress gatewayAddr =
1042                                NetworkUtils.intToInetAddress((int)Long.parseLong(gate, 16));
1043
1044                        RouteInfo route = new RouteInfo(linkAddress, gatewayAddr);
1045                        routes.add(route);
1046                    } catch (Exception e) {
1047                        Log.e(TAG, "Error parsing route " + s + " : " + e);
1048                        continue;
1049                    }
1050                }
1051            }
1052        }
1053
1054        // v6 routes listed as:
1055        // dest-addr prefixlength ?? ?? gateway-addr ?? ?? ?? ?? iface
1056        for (String s : readRouteList("/proc/net/ipv6_route")) {
1057            String[]fields = s.split("\\s+");
1058            if (fields.length > 9) {
1059                String iface = fields[9].trim();
1060                if (interfaceName.equals(iface)) {
1061                    String dest = fields[0];
1062                    String prefix = fields[1];
1063                    String gate = fields[4];
1064
1065                    try {
1066                        // prefix length stored as a hex string, ex 40
1067                        int prefixLength = Integer.parseInt(prefix, 16);
1068
1069                        // address stored as a 32 char hex string
1070                        // ex fe800000000000000000000000000000
1071                        InetAddress destAddr = NetworkUtils.hexToInet6Address(dest);
1072                        LinkAddress linkAddress = new LinkAddress(destAddr, prefixLength);
1073
1074                        InetAddress gateAddr = NetworkUtils.hexToInet6Address(gate);
1075
1076                        RouteInfo route = new RouteInfo(linkAddress, gateAddr);
1077                        routes.add(route);
1078                    } catch (Exception e) {
1079                        Log.e(TAG, "Error parsing route " + s + " : " + e);
1080                        continue;
1081                    }
1082                }
1083            }
1084        }
1085        return routes.toArray(new RouteInfo[routes.size()]);
1086    }
1087
1088    @Override
1089    public void setMtu(String iface, int mtu) {
1090        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1091
1092        final NativeDaemonEvent event;
1093        try {
1094            event = mConnector.execute("interface", "setmtu", iface, mtu);
1095        } catch (NativeDaemonConnectorException e) {
1096            throw e.rethrowAsParcelableException();
1097        }
1098    }
1099
1100    @Override
1101    public void shutdown() {
1102        // TODO: remove from aidl if nobody calls externally
1103        mContext.enforceCallingOrSelfPermission(SHUTDOWN, TAG);
1104
1105        Slog.d(TAG, "Shutting down");
1106    }
1107
1108    @Override
1109    public boolean getIpForwardingEnabled() throws IllegalStateException{
1110        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1111
1112        final NativeDaemonEvent event;
1113        try {
1114            event = mConnector.execute("ipfwd", "status");
1115        } catch (NativeDaemonConnectorException e) {
1116            throw e.rethrowAsParcelableException();
1117        }
1118
1119        // 211 Forwarding enabled
1120        event.checkCode(IpFwdStatusResult);
1121        return event.getMessage().endsWith("enabled");
1122    }
1123
1124    @Override
1125    public void setIpForwardingEnabled(boolean enable) {
1126        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1127        try {
1128            mConnector.execute("ipfwd", enable ? "enable" : "disable");
1129        } catch (NativeDaemonConnectorException e) {
1130            throw e.rethrowAsParcelableException();
1131        }
1132    }
1133
1134    @Override
1135    public void startTethering(String[] dhcpRange) {
1136        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1137        // cmd is "tether start first_start first_stop second_start second_stop ..."
1138        // an odd number of addrs will fail
1139
1140        final Command cmd = new Command("tether", "start");
1141        for (String d : dhcpRange) {
1142            cmd.appendArg(d);
1143        }
1144
1145        try {
1146            mConnector.execute(cmd);
1147        } catch (NativeDaemonConnectorException e) {
1148            throw e.rethrowAsParcelableException();
1149        }
1150    }
1151
1152    @Override
1153    public void stopTethering() {
1154        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1155        try {
1156            mConnector.execute("tether", "stop");
1157        } catch (NativeDaemonConnectorException e) {
1158            throw e.rethrowAsParcelableException();
1159        }
1160    }
1161
1162    @Override
1163    public boolean isTetheringStarted() {
1164        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1165
1166        final NativeDaemonEvent event;
1167        try {
1168            event = mConnector.execute("tether", "status");
1169        } catch (NativeDaemonConnectorException e) {
1170            throw e.rethrowAsParcelableException();
1171        }
1172
1173        // 210 Tethering services started
1174        event.checkCode(TetherStatusResult);
1175        return event.getMessage().endsWith("started");
1176    }
1177
1178    @Override
1179    public void tetherInterface(String iface) {
1180        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1181        try {
1182            mConnector.execute("tether", "interface", "add", iface);
1183        } catch (NativeDaemonConnectorException e) {
1184            throw e.rethrowAsParcelableException();
1185        }
1186        List<RouteInfo> routes = new ArrayList<RouteInfo>();
1187        // The RouteInfo constructor truncates the LinkAddress to a network prefix, thus making it
1188        // suitable to use as a route destination.
1189        routes.add(new RouteInfo(getInterfaceConfig(iface).getLinkAddress(), null, iface));
1190        addInterfaceToLocalNetwork(iface, routes);
1191    }
1192
1193    @Override
1194    public void untetherInterface(String iface) {
1195        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1196        try {
1197            mConnector.execute("tether", "interface", "remove", iface);
1198        } catch (NativeDaemonConnectorException e) {
1199            throw e.rethrowAsParcelableException();
1200        }
1201        removeInterfaceFromLocalNetwork(iface);
1202    }
1203
1204    @Override
1205    public String[] listTetheredInterfaces() {
1206        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1207        try {
1208            return NativeDaemonEvent.filterMessageList(
1209                    mConnector.executeForList("tether", "interface", "list"),
1210                    TetherInterfaceListResult);
1211        } catch (NativeDaemonConnectorException e) {
1212            throw e.rethrowAsParcelableException();
1213        }
1214    }
1215
1216    @Override
1217    public void setDnsForwarders(Network network, String[] dns) {
1218        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1219
1220        int netId = (network != null) ? network.netId : ConnectivityManager.NETID_UNSET;
1221        final Command cmd = new Command("tether", "dns", "set", netId);
1222
1223        for (String s : dns) {
1224            cmd.appendArg(NetworkUtils.numericToInetAddress(s).getHostAddress());
1225        }
1226
1227        try {
1228            mConnector.execute(cmd);
1229        } catch (NativeDaemonConnectorException e) {
1230            throw e.rethrowAsParcelableException();
1231        }
1232    }
1233
1234    @Override
1235    public String[] getDnsForwarders() {
1236        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1237        try {
1238            return NativeDaemonEvent.filterMessageList(
1239                    mConnector.executeForList("tether", "dns", "list"), TetherDnsFwdTgtListResult);
1240        } catch (NativeDaemonConnectorException e) {
1241            throw e.rethrowAsParcelableException();
1242        }
1243    }
1244
1245    private List<InterfaceAddress> excludeLinkLocal(List<InterfaceAddress> addresses) {
1246        ArrayList<InterfaceAddress> filtered = new ArrayList<InterfaceAddress>(addresses.size());
1247        for (InterfaceAddress ia : addresses) {
1248            if (!ia.getAddress().isLinkLocalAddress())
1249                filtered.add(ia);
1250        }
1251        return filtered;
1252    }
1253
1254    private void modifyNat(String action, String internalInterface, String externalInterface)
1255            throws SocketException {
1256        final Command cmd = new Command("nat", action, internalInterface, externalInterface);
1257
1258        final NetworkInterface internalNetworkInterface = NetworkInterface.getByName(
1259                internalInterface);
1260        if (internalNetworkInterface == null) {
1261            cmd.appendArg("0");
1262        } else {
1263            // Don't touch link-local routes, as link-local addresses aren't routable,
1264            // kernel creates link-local routes on all interfaces automatically
1265            List<InterfaceAddress> interfaceAddresses = excludeLinkLocal(
1266                    internalNetworkInterface.getInterfaceAddresses());
1267            cmd.appendArg(interfaceAddresses.size());
1268            for (InterfaceAddress ia : interfaceAddresses) {
1269                InetAddress addr = NetworkUtils.getNetworkPart(
1270                        ia.getAddress(), ia.getNetworkPrefixLength());
1271                cmd.appendArg(addr.getHostAddress() + "/" + ia.getNetworkPrefixLength());
1272            }
1273        }
1274
1275        try {
1276            mConnector.execute(cmd);
1277        } catch (NativeDaemonConnectorException e) {
1278            throw e.rethrowAsParcelableException();
1279        }
1280    }
1281
1282    @Override
1283    public void enableNat(String internalInterface, String externalInterface) {
1284        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1285        try {
1286            modifyNat("enable", internalInterface, externalInterface);
1287        } catch (SocketException e) {
1288            throw new IllegalStateException(e);
1289        }
1290    }
1291
1292    @Override
1293    public void disableNat(String internalInterface, String externalInterface) {
1294        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1295        try {
1296            modifyNat("disable", internalInterface, externalInterface);
1297        } catch (SocketException e) {
1298            throw new IllegalStateException(e);
1299        }
1300    }
1301
1302    @Override
1303    public String[] listTtys() {
1304        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1305        try {
1306            return NativeDaemonEvent.filterMessageList(
1307                    mConnector.executeForList("list_ttys"), TtyListResult);
1308        } catch (NativeDaemonConnectorException e) {
1309            throw e.rethrowAsParcelableException();
1310        }
1311    }
1312
1313    @Override
1314    public void attachPppd(
1315            String tty, String localAddr, String remoteAddr, String dns1Addr, String dns2Addr) {
1316        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1317        try {
1318            mConnector.execute("pppd", "attach", tty,
1319                    NetworkUtils.numericToInetAddress(localAddr).getHostAddress(),
1320                    NetworkUtils.numericToInetAddress(remoteAddr).getHostAddress(),
1321                    NetworkUtils.numericToInetAddress(dns1Addr).getHostAddress(),
1322                    NetworkUtils.numericToInetAddress(dns2Addr).getHostAddress());
1323        } catch (NativeDaemonConnectorException e) {
1324            throw e.rethrowAsParcelableException();
1325        }
1326    }
1327
1328    @Override
1329    public void detachPppd(String tty) {
1330        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1331        try {
1332            mConnector.execute("pppd", "detach", tty);
1333        } catch (NativeDaemonConnectorException e) {
1334            throw e.rethrowAsParcelableException();
1335        }
1336    }
1337
1338    @Override
1339    public void startAccessPoint(
1340            WifiConfiguration wifiConfig, String wlanIface) {
1341        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1342        try {
1343            wifiFirmwareReload(wlanIface, "AP");
1344            if (wifiConfig == null) {
1345                mConnector.execute("softap", "set", wlanIface);
1346            } else {
1347                mConnector.execute("softap", "set", wlanIface, wifiConfig.SSID,
1348                                   "broadcast", "6", getSecurityType(wifiConfig),
1349                                   new SensitiveArg(wifiConfig.preSharedKey));
1350            }
1351            mConnector.execute("softap", "startap");
1352        } catch (NativeDaemonConnectorException e) {
1353            throw e.rethrowAsParcelableException();
1354        }
1355    }
1356
1357    private static String getSecurityType(WifiConfiguration wifiConfig) {
1358        switch (wifiConfig.getAuthType()) {
1359            case KeyMgmt.WPA_PSK:
1360                return "wpa-psk";
1361            case KeyMgmt.WPA2_PSK:
1362                return "wpa2-psk";
1363            default:
1364                return "open";
1365        }
1366    }
1367
1368    /* @param mode can be "AP", "STA" or "P2P" */
1369    @Override
1370    public void wifiFirmwareReload(String wlanIface, String mode) {
1371        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1372        try {
1373            mConnector.execute("softap", "fwreload", wlanIface, mode);
1374        } catch (NativeDaemonConnectorException e) {
1375            throw e.rethrowAsParcelableException();
1376        }
1377    }
1378
1379    @Override
1380    public void stopAccessPoint(String wlanIface) {
1381        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1382        try {
1383            mConnector.execute("softap", "stopap");
1384            wifiFirmwareReload(wlanIface, "STA");
1385        } catch (NativeDaemonConnectorException e) {
1386            throw e.rethrowAsParcelableException();
1387        }
1388    }
1389
1390    @Override
1391    public void setAccessPoint(WifiConfiguration wifiConfig, String wlanIface) {
1392        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1393        try {
1394            if (wifiConfig == null) {
1395                mConnector.execute("softap", "set", wlanIface);
1396            } else {
1397                mConnector.execute("softap", "set", wlanIface, wifiConfig.SSID,
1398                                   "broadcast", "6", getSecurityType(wifiConfig),
1399                                   new SensitiveArg(wifiConfig.preSharedKey));
1400            }
1401        } catch (NativeDaemonConnectorException e) {
1402            throw e.rethrowAsParcelableException();
1403        }
1404    }
1405
1406    @Override
1407    public void addIdleTimer(String iface, int timeout, final int type) {
1408        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1409
1410        if (DBG) Slog.d(TAG, "Adding idletimer");
1411
1412        synchronized (mIdleTimerLock) {
1413            IdleTimerParams params = mActiveIdleTimers.get(iface);
1414            if (params != null) {
1415                // the interface already has idletimer, update network count
1416                params.networkCount++;
1417                return;
1418            }
1419
1420            try {
1421                mConnector.execute("idletimer", "add", iface, Integer.toString(timeout),
1422                        Integer.toString(type));
1423            } catch (NativeDaemonConnectorException e) {
1424                throw e.rethrowAsParcelableException();
1425            }
1426            mActiveIdleTimers.put(iface, new IdleTimerParams(timeout, type));
1427
1428            // Networks start up.
1429            if (ConnectivityManager.isNetworkTypeMobile(type)) {
1430                mNetworkActive = false;
1431            }
1432            mDaemonHandler.post(new Runnable() {
1433                @Override public void run() {
1434                    notifyInterfaceClassActivity(type,
1435                            DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH,
1436                            SystemClock.elapsedRealtimeNanos(), false);
1437                }
1438            });
1439        }
1440    }
1441
1442    @Override
1443    public void removeIdleTimer(String iface) {
1444        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1445
1446        if (DBG) Slog.d(TAG, "Removing idletimer");
1447
1448        synchronized (mIdleTimerLock) {
1449            final IdleTimerParams params = mActiveIdleTimers.get(iface);
1450            if (params == null || --(params.networkCount) > 0) {
1451                return;
1452            }
1453
1454            try {
1455                mConnector.execute("idletimer", "remove", iface,
1456                        Integer.toString(params.timeout), Integer.toString(params.type));
1457            } catch (NativeDaemonConnectorException e) {
1458                throw e.rethrowAsParcelableException();
1459            }
1460            mActiveIdleTimers.remove(iface);
1461            mDaemonHandler.post(new Runnable() {
1462                @Override public void run() {
1463                    notifyInterfaceClassActivity(params.type,
1464                            DataConnectionRealTimeInfo.DC_POWER_STATE_LOW,
1465                            SystemClock.elapsedRealtimeNanos(), false);
1466                }
1467            });
1468        }
1469    }
1470
1471    @Override
1472    public NetworkStats getNetworkStatsSummaryDev() {
1473        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1474        try {
1475            return mStatsFactory.readNetworkStatsSummaryDev();
1476        } catch (IOException e) {
1477            throw new IllegalStateException(e);
1478        }
1479    }
1480
1481    @Override
1482    public NetworkStats getNetworkStatsSummaryXt() {
1483        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1484        try {
1485            return mStatsFactory.readNetworkStatsSummaryXt();
1486        } catch (IOException e) {
1487            throw new IllegalStateException(e);
1488        }
1489    }
1490
1491    @Override
1492    public NetworkStats getNetworkStatsDetail() {
1493        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1494        try {
1495            return mStatsFactory.readNetworkStatsDetail(UID_ALL, null, TAG_ALL, null);
1496        } catch (IOException e) {
1497            throw new IllegalStateException(e);
1498        }
1499    }
1500
1501    @Override
1502    public void setInterfaceQuota(String iface, long quotaBytes) {
1503        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1504
1505        // silently discard when control disabled
1506        // TODO: eventually migrate to be always enabled
1507        if (!mBandwidthControlEnabled) return;
1508
1509        synchronized (mQuotaLock) {
1510            if (mActiveQuotas.containsKey(iface)) {
1511                throw new IllegalStateException("iface " + iface + " already has quota");
1512            }
1513
1514            try {
1515                // TODO: support quota shared across interfaces
1516                mConnector.execute("bandwidth", "setiquota", iface, quotaBytes);
1517                mActiveQuotas.put(iface, quotaBytes);
1518            } catch (NativeDaemonConnectorException e) {
1519                throw e.rethrowAsParcelableException();
1520            }
1521        }
1522    }
1523
1524    @Override
1525    public void removeInterfaceQuota(String iface) {
1526        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1527
1528        // silently discard when control disabled
1529        // TODO: eventually migrate to be always enabled
1530        if (!mBandwidthControlEnabled) return;
1531
1532        synchronized (mQuotaLock) {
1533            if (!mActiveQuotas.containsKey(iface)) {
1534                // TODO: eventually consider throwing
1535                return;
1536            }
1537
1538            mActiveQuotas.remove(iface);
1539            mActiveAlerts.remove(iface);
1540
1541            try {
1542                // TODO: support quota shared across interfaces
1543                mConnector.execute("bandwidth", "removeiquota", iface);
1544            } catch (NativeDaemonConnectorException e) {
1545                throw e.rethrowAsParcelableException();
1546            }
1547        }
1548    }
1549
1550    @Override
1551    public void setInterfaceAlert(String iface, long alertBytes) {
1552        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1553
1554        // silently discard when control disabled
1555        // TODO: eventually migrate to be always enabled
1556        if (!mBandwidthControlEnabled) return;
1557
1558        // quick sanity check
1559        if (!mActiveQuotas.containsKey(iface)) {
1560            throw new IllegalStateException("setting alert requires existing quota on iface");
1561        }
1562
1563        synchronized (mQuotaLock) {
1564            if (mActiveAlerts.containsKey(iface)) {
1565                throw new IllegalStateException("iface " + iface + " already has alert");
1566            }
1567
1568            try {
1569                // TODO: support alert shared across interfaces
1570                mConnector.execute("bandwidth", "setinterfacealert", iface, alertBytes);
1571                mActiveAlerts.put(iface, alertBytes);
1572            } catch (NativeDaemonConnectorException e) {
1573                throw e.rethrowAsParcelableException();
1574            }
1575        }
1576    }
1577
1578    @Override
1579    public void removeInterfaceAlert(String iface) {
1580        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1581
1582        // silently discard when control disabled
1583        // TODO: eventually migrate to be always enabled
1584        if (!mBandwidthControlEnabled) return;
1585
1586        synchronized (mQuotaLock) {
1587            if (!mActiveAlerts.containsKey(iface)) {
1588                // TODO: eventually consider throwing
1589                return;
1590            }
1591
1592            try {
1593                // TODO: support alert shared across interfaces
1594                mConnector.execute("bandwidth", "removeinterfacealert", iface);
1595                mActiveAlerts.remove(iface);
1596            } catch (NativeDaemonConnectorException e) {
1597                throw e.rethrowAsParcelableException();
1598            }
1599        }
1600    }
1601
1602    @Override
1603    public void setGlobalAlert(long alertBytes) {
1604        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1605
1606        // silently discard when control disabled
1607        // TODO: eventually migrate to be always enabled
1608        if (!mBandwidthControlEnabled) return;
1609
1610        try {
1611            mConnector.execute("bandwidth", "setglobalalert", alertBytes);
1612        } catch (NativeDaemonConnectorException e) {
1613            throw e.rethrowAsParcelableException();
1614        }
1615    }
1616
1617    @Override
1618    public void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces) {
1619        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1620
1621        // silently discard when control disabled
1622        // TODO: eventually migrate to be always enabled
1623        if (!mBandwidthControlEnabled) return;
1624
1625        synchronized (mQuotaLock) {
1626            final boolean oldRejectOnQuota = mUidRejectOnQuota.get(uid, false);
1627            if (oldRejectOnQuota == rejectOnQuotaInterfaces) {
1628                // TODO: eventually consider throwing
1629                return;
1630            }
1631
1632            try {
1633                mConnector.execute("bandwidth",
1634                        rejectOnQuotaInterfaces ? "addnaughtyapps" : "removenaughtyapps", uid);
1635                if (rejectOnQuotaInterfaces) {
1636                    mUidRejectOnQuota.put(uid, true);
1637                } else {
1638                    mUidRejectOnQuota.delete(uid);
1639                }
1640            } catch (NativeDaemonConnectorException e) {
1641                throw e.rethrowAsParcelableException();
1642            }
1643        }
1644    }
1645
1646    @Override
1647    public boolean isBandwidthControlEnabled() {
1648        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1649        return mBandwidthControlEnabled;
1650    }
1651
1652    @Override
1653    public NetworkStats getNetworkStatsUidDetail(int uid) {
1654        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1655        try {
1656            return mStatsFactory.readNetworkStatsDetail(uid, null, TAG_ALL, null);
1657        } catch (IOException e) {
1658            throw new IllegalStateException(e);
1659        }
1660    }
1661
1662    @Override
1663    public NetworkStats getNetworkStatsTethering() {
1664        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1665
1666        final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1);
1667        try {
1668            final NativeDaemonEvent[] events = mConnector.executeForList(
1669                    "bandwidth", "gettetherstats");
1670            for (NativeDaemonEvent event : events) {
1671                if (event.getCode() != TetheringStatsListResult) continue;
1672
1673                // 114 ifaceIn ifaceOut rx_bytes rx_packets tx_bytes tx_packets
1674                final StringTokenizer tok = new StringTokenizer(event.getMessage());
1675                try {
1676                    final String ifaceIn = tok.nextToken();
1677                    final String ifaceOut = tok.nextToken();
1678
1679                    final NetworkStats.Entry entry = new NetworkStats.Entry();
1680                    entry.iface = ifaceOut;
1681                    entry.uid = UID_TETHERING;
1682                    entry.set = SET_DEFAULT;
1683                    entry.tag = TAG_NONE;
1684                    entry.rxBytes = Long.parseLong(tok.nextToken());
1685                    entry.rxPackets = Long.parseLong(tok.nextToken());
1686                    entry.txBytes = Long.parseLong(tok.nextToken());
1687                    entry.txPackets = Long.parseLong(tok.nextToken());
1688                    stats.combineValues(entry);
1689                } catch (NoSuchElementException e) {
1690                    throw new IllegalStateException("problem parsing tethering stats: " + event);
1691                } catch (NumberFormatException e) {
1692                    throw new IllegalStateException("problem parsing tethering stats: " + event);
1693                }
1694            }
1695        } catch (NativeDaemonConnectorException e) {
1696            throw e.rethrowAsParcelableException();
1697        }
1698        return stats;
1699    }
1700
1701    @Override
1702    public void setDnsServersForNetwork(int netId, String[] servers, String domains) {
1703        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1704
1705        final Command cmd = new Command("resolver", "setnetdns", netId,
1706                (domains == null ? "" : domains));
1707
1708        for (String s : servers) {
1709            InetAddress a = NetworkUtils.numericToInetAddress(s);
1710            if (a.isAnyLocalAddress() == false) {
1711                cmd.appendArg(a.getHostAddress());
1712            }
1713        }
1714
1715        try {
1716            mConnector.execute(cmd);
1717        } catch (NativeDaemonConnectorException e) {
1718            throw e.rethrowAsParcelableException();
1719        }
1720    }
1721
1722    @Override
1723    public void addVpnUidRanges(int netId, UidRange[] ranges) {
1724        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1725        Object[] argv = new Object[3 + MAX_UID_RANGES_PER_COMMAND];
1726        argv[0] = "users";
1727        argv[1] = "add";
1728        argv[2] = netId;
1729        int argc = 3;
1730        // Avoid overly long commands by limiting number of UID ranges per command.
1731        for (int i = 0; i < ranges.length; i++) {
1732            argv[argc++] = ranges[i].toString();
1733            if (i == (ranges.length - 1) || argc == argv.length) {
1734                try {
1735                    mConnector.execute("network", Arrays.copyOf(argv, argc));
1736                } catch (NativeDaemonConnectorException e) {
1737                    throw e.rethrowAsParcelableException();
1738                }
1739                argc = 3;
1740            }
1741        }
1742    }
1743
1744    @Override
1745    public void removeVpnUidRanges(int netId, UidRange[] ranges) {
1746        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1747        Object[] argv = new Object[3 + MAX_UID_RANGES_PER_COMMAND];
1748        argv[0] = "users";
1749        argv[1] = "remove";
1750        argv[2] = netId;
1751        int argc = 3;
1752        // Avoid overly long commands by limiting number of UID ranges per command.
1753        for (int i = 0; i < ranges.length; i++) {
1754            argv[argc++] = ranges[i].toString();
1755            if (i == (ranges.length - 1) || argc == argv.length) {
1756                try {
1757                    mConnector.execute("network", Arrays.copyOf(argv, argc));
1758                } catch (NativeDaemonConnectorException e) {
1759                    throw e.rethrowAsParcelableException();
1760                }
1761                argc = 3;
1762            }
1763        }
1764    }
1765
1766    @Override
1767    public void flushNetworkDnsCache(int netId) {
1768        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1769        try {
1770            mConnector.execute("resolver", "flushnet", netId);
1771        } catch (NativeDaemonConnectorException e) {
1772            throw e.rethrowAsParcelableException();
1773        }
1774    }
1775
1776    @Override
1777    public void setFirewallEnabled(boolean enabled) {
1778        enforceSystemUid();
1779        try {
1780            mConnector.execute("firewall", enabled ? "enable" : "disable");
1781            mFirewallEnabled = enabled;
1782        } catch (NativeDaemonConnectorException e) {
1783            throw e.rethrowAsParcelableException();
1784        }
1785    }
1786
1787    @Override
1788    public boolean isFirewallEnabled() {
1789        enforceSystemUid();
1790        return mFirewallEnabled;
1791    }
1792
1793    @Override
1794    public void setFirewallInterfaceRule(String iface, boolean allow) {
1795        enforceSystemUid();
1796        Preconditions.checkState(mFirewallEnabled);
1797        final String rule = allow ? "allow" : "deny";
1798        try {
1799            mConnector.execute("firewall", "set_interface_rule", iface, rule);
1800        } catch (NativeDaemonConnectorException e) {
1801            throw e.rethrowAsParcelableException();
1802        }
1803    }
1804
1805    @Override
1806    public void setFirewallEgressSourceRule(String addr, boolean allow) {
1807        enforceSystemUid();
1808        Preconditions.checkState(mFirewallEnabled);
1809        final String rule = allow ? "allow" : "deny";
1810        try {
1811            mConnector.execute("firewall", "set_egress_source_rule", addr, rule);
1812        } catch (NativeDaemonConnectorException e) {
1813            throw e.rethrowAsParcelableException();
1814        }
1815    }
1816
1817    @Override
1818    public void setFirewallEgressDestRule(String addr, int port, boolean allow) {
1819        enforceSystemUid();
1820        Preconditions.checkState(mFirewallEnabled);
1821        final String rule = allow ? "allow" : "deny";
1822        try {
1823            mConnector.execute("firewall", "set_egress_dest_rule", addr, port, rule);
1824        } catch (NativeDaemonConnectorException e) {
1825            throw e.rethrowAsParcelableException();
1826        }
1827    }
1828
1829    @Override
1830    public void setFirewallUidRule(int uid, boolean allow) {
1831        enforceSystemUid();
1832        Preconditions.checkState(mFirewallEnabled);
1833        final String rule = allow ? "allow" : "deny";
1834        try {
1835            mConnector.execute("firewall", "set_uid_rule", uid, rule);
1836        } catch (NativeDaemonConnectorException e) {
1837            throw e.rethrowAsParcelableException();
1838        }
1839    }
1840
1841    private static void enforceSystemUid() {
1842        final int uid = Binder.getCallingUid();
1843        if (uid != Process.SYSTEM_UID) {
1844            throw new SecurityException("Only available to AID_SYSTEM");
1845        }
1846    }
1847
1848    @Override
1849    public void startClatd(String interfaceName) throws IllegalStateException {
1850        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1851
1852        try {
1853            mConnector.execute("clatd", "start", interfaceName);
1854        } catch (NativeDaemonConnectorException e) {
1855            throw e.rethrowAsParcelableException();
1856        }
1857    }
1858
1859    @Override
1860    public void stopClatd() throws IllegalStateException {
1861        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1862
1863        try {
1864            mConnector.execute("clatd", "stop");
1865        } catch (NativeDaemonConnectorException e) {
1866            throw e.rethrowAsParcelableException();
1867        }
1868    }
1869
1870    @Override
1871    public boolean isClatdStarted() {
1872        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1873
1874        final NativeDaemonEvent event;
1875        try {
1876            event = mConnector.execute("clatd", "status");
1877        } catch (NativeDaemonConnectorException e) {
1878            throw e.rethrowAsParcelableException();
1879        }
1880
1881        event.checkCode(ClatdStatusResult);
1882        return event.getMessage().endsWith("started");
1883    }
1884
1885    @Override
1886    public void registerNetworkActivityListener(INetworkActivityListener listener) {
1887        mNetworkActivityListeners.register(listener);
1888    }
1889
1890    @Override
1891    public void unregisterNetworkActivityListener(INetworkActivityListener listener) {
1892        mNetworkActivityListeners.unregister(listener);
1893    }
1894
1895    @Override
1896    public boolean isNetworkActive() {
1897        synchronized (mNetworkActivityListeners) {
1898            return mNetworkActive || mActiveIdleTimers.isEmpty();
1899        }
1900    }
1901
1902    private void reportNetworkActive() {
1903        final int length = mNetworkActivityListeners.beginBroadcast();
1904        try {
1905            for (int i = 0; i < length; i++) {
1906                try {
1907                    mNetworkActivityListeners.getBroadcastItem(i).onNetworkActive();
1908                } catch (RemoteException e) {
1909                } catch (RuntimeException e) {
1910                }
1911            }
1912        } finally {
1913            mNetworkActivityListeners.finishBroadcast();
1914        }
1915    }
1916
1917    /** {@inheritDoc} */
1918    @Override
1919    public void monitor() {
1920        if (mConnector != null) {
1921            mConnector.monitor();
1922        }
1923    }
1924
1925    @Override
1926    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1927        mContext.enforceCallingOrSelfPermission(DUMP, TAG);
1928
1929        pw.println("NetworkManagementService NativeDaemonConnector Log:");
1930        mConnector.dump(fd, pw, args);
1931        pw.println();
1932
1933        pw.print("Bandwidth control enabled: "); pw.println(mBandwidthControlEnabled);
1934        pw.print("mMobileActivityFromRadio="); pw.print(mMobileActivityFromRadio);
1935                pw.print(" mLastPowerStateFromRadio="); pw.println(mLastPowerStateFromRadio);
1936        pw.print("mNetworkActive="); pw.println(mNetworkActive);
1937
1938        synchronized (mQuotaLock) {
1939            pw.print("Active quota ifaces: "); pw.println(mActiveQuotas.toString());
1940            pw.print("Active alert ifaces: "); pw.println(mActiveAlerts.toString());
1941        }
1942
1943        synchronized (mUidRejectOnQuota) {
1944            pw.print("UID reject on quota ifaces: [");
1945            final int size = mUidRejectOnQuota.size();
1946            for (int i = 0; i < size; i++) {
1947                pw.print(mUidRejectOnQuota.keyAt(i));
1948                if (i < size - 1) pw.print(",");
1949            }
1950            pw.println("]");
1951        }
1952
1953        synchronized (mIdleTimerLock) {
1954            pw.println("Idle timers:");
1955            for (HashMap.Entry<String, IdleTimerParams> ent : mActiveIdleTimers.entrySet()) {
1956                pw.print("  "); pw.print(ent.getKey()); pw.println(":");
1957                IdleTimerParams params = ent.getValue();
1958                pw.print("    timeout="); pw.print(params.timeout);
1959                pw.print(" type="); pw.print(params.type);
1960                pw.print(" networkCount="); pw.println(params.networkCount);
1961            }
1962        }
1963
1964        pw.print("Firewall enabled: "); pw.println(mFirewallEnabled);
1965    }
1966
1967    @Override
1968    public void createPhysicalNetwork(int netId) {
1969        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1970
1971        try {
1972            mConnector.execute("network", "create", netId);
1973        } catch (NativeDaemonConnectorException e) {
1974            throw e.rethrowAsParcelableException();
1975        }
1976    }
1977
1978    @Override
1979    public void createVirtualNetwork(int netId, boolean hasDNS, boolean secure) {
1980        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1981
1982        try {
1983            mConnector.execute("network", "create", netId, "vpn", hasDNS ? "1" : "0",
1984                    secure ? "1" : "0");
1985        } catch (NativeDaemonConnectorException e) {
1986            throw e.rethrowAsParcelableException();
1987        }
1988    }
1989
1990    @Override
1991    public void removeNetwork(int netId) {
1992        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1993
1994        try {
1995            mConnector.execute("network", "destroy", netId);
1996        } catch (NativeDaemonConnectorException e) {
1997            throw e.rethrowAsParcelableException();
1998        }
1999    }
2000
2001    @Override
2002    public void addInterfaceToNetwork(String iface, int netId) {
2003        modifyInterfaceInNetwork("add", "" + netId, iface);
2004    }
2005
2006    @Override
2007    public void removeInterfaceFromNetwork(String iface, int netId) {
2008        modifyInterfaceInNetwork("remove", "" + netId, iface);
2009    }
2010
2011    private void modifyInterfaceInNetwork(String action, String netId, String iface) {
2012        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2013        try {
2014            mConnector.execute("network", "interface", action, netId, iface);
2015        } catch (NativeDaemonConnectorException e) {
2016            throw e.rethrowAsParcelableException();
2017        }
2018    }
2019
2020    @Override
2021    public void addLegacyRouteForNetId(int netId, RouteInfo routeInfo, int uid) {
2022        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2023
2024        final Command cmd = new Command("network", "route", "legacy", uid, "add", netId);
2025
2026        // create triplet: interface dest-ip-addr/prefixlength gateway-ip-addr
2027        final LinkAddress la = routeInfo.getDestinationLinkAddress();
2028        cmd.appendArg(routeInfo.getInterface());
2029        cmd.appendArg(la.getAddress().getHostAddress() + "/" + la.getPrefixLength());
2030        if (routeInfo.hasGateway()) {
2031            cmd.appendArg(routeInfo.getGateway().getHostAddress());
2032        }
2033
2034        try {
2035            mConnector.execute(cmd);
2036        } catch (NativeDaemonConnectorException e) {
2037            throw e.rethrowAsParcelableException();
2038        }
2039    }
2040
2041    @Override
2042    public void setDefaultNetId(int netId) {
2043        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2044
2045        try {
2046            mConnector.execute("network", "default", "set", netId);
2047        } catch (NativeDaemonConnectorException e) {
2048            throw e.rethrowAsParcelableException();
2049        }
2050    }
2051
2052    @Override
2053    public void clearDefaultNetId() {
2054        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2055
2056        try {
2057            mConnector.execute("network", "default", "clear");
2058        } catch (NativeDaemonConnectorException e) {
2059            throw e.rethrowAsParcelableException();
2060        }
2061    }
2062
2063    @Override
2064    public void setPermission(boolean internal, boolean changeNetState, int[] uids) {
2065        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2066
2067        final Command cmd = new Command("network", "permission", "user", "set");
2068        if (internal) cmd.appendArg(CONNECTIVITY_INTERNAL);
2069        if (changeNetState) cmd.appendArg(CHANGE_NETWORK_STATE);
2070        for (int i=0; i<uids.length; i++) {
2071            cmd.appendArg(uids[i]);
2072        }
2073
2074        try {
2075            mConnector.execute(cmd);
2076        } catch (NativeDaemonConnectorException e) {
2077            throw e.rethrowAsParcelableException();
2078        }
2079    }
2080
2081    @Override
2082    public void clearPermission(int[] uids) {
2083        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2084
2085        final Command cmd = new Command("network", "permission", "user", "clear");
2086        for (int i=0; i<uids.length; i++) {
2087            cmd.appendArg(uids[i]);
2088        }
2089
2090        try {
2091            mConnector.execute(cmd);
2092        } catch (NativeDaemonConnectorException e) {
2093            throw e.rethrowAsParcelableException();
2094        }
2095    }
2096
2097    @Override
2098    public void allowProtect(int uid) {
2099        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2100
2101        try {
2102            mConnector.execute("network", "protect", "allow", uid);
2103        } catch (NativeDaemonConnectorException e) {
2104            throw e.rethrowAsParcelableException();
2105        }
2106    }
2107
2108    @Override
2109    public void denyProtect(int uid) {
2110        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2111
2112        try {
2113            mConnector.execute("network", "protect", "deny", uid);
2114        } catch (NativeDaemonConnectorException e) {
2115            throw e.rethrowAsParcelableException();
2116        }
2117    }
2118
2119    @Override
2120    public void addInterfaceToLocalNetwork(String iface, List<RouteInfo> routes) {
2121        modifyInterfaceInNetwork("add", "local", iface);
2122
2123        for (RouteInfo route : routes) {
2124            if (!route.isDefaultRoute()) {
2125                modifyRoute("add", "local", route);
2126            }
2127        }
2128    }
2129
2130    @Override
2131    public void removeInterfaceFromLocalNetwork(String iface) {
2132        modifyInterfaceInNetwork("remove", "local", iface);
2133    }
2134
2135    @Override
2136    public void blockAddressFamily(int family, int netId, String iface) {
2137        modifyAddressFamily("add", family, netId, iface);
2138    }
2139
2140    @Override
2141    public void unblockAddressFamily(int family, int netId, String iface) {
2142        modifyAddressFamily("remove", family, netId, iface);
2143    }
2144
2145    // TODO: get rid of this and add RTN_UNREACHABLE routes instead.
2146    private void modifyAddressFamily(String action, int family, int netId, String iface) {
2147        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2148
2149        final Command cmd = new Command("network", "route", action, netId, iface);
2150
2151        if (family == AF_INET) {
2152            cmd.appendArg(Inet4Address.ANY.getHostAddress() + "/0");
2153        } else if (family == AF_INET6) {
2154            cmd.appendArg(Inet6Address.ANY.getHostAddress() + "/0");
2155        } else {
2156            throw new IllegalStateException(family + " is neither " + AF_INET + " nor " + AF_INET6);
2157        }
2158
2159        cmd.appendArg("unreachable");
2160
2161        try {
2162            mConnector.execute(cmd);
2163        } catch (NativeDaemonConnectorException e) {
2164            throw e.rethrowAsParcelableException();
2165        }
2166    }
2167}
2168