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