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