NetworkManagementService.java revision 0535a9f7aa5d0f875b06845e9af5f6dbfc5c8a19
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, long tsNanos) {
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, tsNanos);
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                    long timestampNanos = 0;
575                    if (cooked.length == 5) {
576                        try {
577                            timestampNanos = Long.parseLong(cooked[4]);
578                        } catch(NumberFormatException ne) {}
579                    }
580                    boolean isActive = cooked[2].equals("active");
581                    notifyInterfaceClassActivity(Integer.parseInt(cooked[3]),
582                            isActive, timestampNanos);
583                    return true;
584                    // break;
585            case NetdResponseCode.InterfaceAddressChange:
586                    /*
587                     * A network address change occurred
588                     * Format: "NNN Address updated <addr> <iface> <flags> <scope>"
589                     *         "NNN Address removed <addr> <iface> <flags> <scope>"
590                     */
591                    if (cooked.length < 7 || !cooked[1].equals("Address")) {
592                        throw new IllegalStateException(errorMessage);
593                    }
594
595                    String iface = cooked[4];
596                    LinkAddress address;
597                    try {
598                        int flags = Integer.parseInt(cooked[5]);
599                        int scope = Integer.parseInt(cooked[6]);
600                        address = new LinkAddress(cooked[3], flags, scope);
601                    } catch(NumberFormatException e) {     // Non-numeric lifetime or scope.
602                        throw new IllegalStateException(errorMessage, e);
603                    } catch(IllegalArgumentException e) {  // Malformed/invalid IP address.
604                        throw new IllegalStateException(errorMessage, e);
605                    }
606
607                    if (cooked[2].equals("updated")) {
608                        notifyAddressUpdated(iface, address);
609                    } else {
610                        notifyAddressRemoved(iface, address);
611                    }
612                    return true;
613                    // break;
614            case NetdResponseCode.InterfaceDnsServerInfo:
615                    /*
616                     * Information about available DNS servers has been received.
617                     * Format: "NNN DnsInfo servers <interface> <lifetime> <servers>"
618                     */
619                    long lifetime;  // Actually a 32-bit unsigned integer.
620
621                    if (cooked.length == 6 &&
622                        cooked[1].equals("DnsInfo") &&
623                        cooked[2].equals("servers")) {
624                        try {
625                            lifetime = Long.parseLong(cooked[4]);
626                        } catch (NumberFormatException e) {
627                            throw new IllegalStateException(errorMessage);
628                        }
629                        String[] servers = cooked[5].split(",");
630                        notifyInterfaceDnsServerInfo(cooked[3], lifetime, servers);
631                    }
632                    return true;
633                    // break;
634            default: break;
635            }
636            return false;
637        }
638    }
639
640
641    //
642    // INetworkManagementService members
643    //
644
645    @Override
646    public String[] listInterfaces() {
647        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
648        try {
649            return NativeDaemonEvent.filterMessageList(
650                    mConnector.executeForList("interface", "list"), InterfaceListResult);
651        } catch (NativeDaemonConnectorException e) {
652            throw e.rethrowAsParcelableException();
653        }
654    }
655
656    @Override
657    public InterfaceConfiguration getInterfaceConfig(String iface) {
658        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
659
660        final NativeDaemonEvent event;
661        try {
662            event = mConnector.execute("interface", "getcfg", iface);
663        } catch (NativeDaemonConnectorException e) {
664            throw e.rethrowAsParcelableException();
665        }
666
667        event.checkCode(InterfaceGetCfgResult);
668
669        // Rsp: 213 xx:xx:xx:xx:xx:xx yyy.yyy.yyy.yyy zzz flag1 flag2 flag3
670        final StringTokenizer st = new StringTokenizer(event.getMessage());
671
672        InterfaceConfiguration cfg;
673        try {
674            cfg = new InterfaceConfiguration();
675            cfg.setHardwareAddress(st.nextToken(" "));
676            InetAddress addr = null;
677            int prefixLength = 0;
678            try {
679                addr = NetworkUtils.numericToInetAddress(st.nextToken());
680            } catch (IllegalArgumentException iae) {
681                Slog.e(TAG, "Failed to parse ipaddr", iae);
682            }
683
684            try {
685                prefixLength = Integer.parseInt(st.nextToken());
686            } catch (NumberFormatException nfe) {
687                Slog.e(TAG, "Failed to parse prefixLength", nfe);
688            }
689
690            cfg.setLinkAddress(new LinkAddress(addr, prefixLength));
691            while (st.hasMoreTokens()) {
692                cfg.setFlag(st.nextToken());
693            }
694        } catch (NoSuchElementException nsee) {
695            throw new IllegalStateException("Invalid response from daemon: " + event);
696        }
697        return cfg;
698    }
699
700    @Override
701    public void setInterfaceConfig(String iface, InterfaceConfiguration cfg) {
702        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
703        LinkAddress linkAddr = cfg.getLinkAddress();
704        if (linkAddr == null || linkAddr.getAddress() == null) {
705            throw new IllegalStateException("Null LinkAddress given");
706        }
707
708        final Command cmd = new Command("interface", "setcfg", iface,
709                linkAddr.getAddress().getHostAddress(),
710                linkAddr.getNetworkPrefixLength());
711        for (String flag : cfg.getFlags()) {
712            cmd.appendArg(flag);
713        }
714
715        try {
716            mConnector.execute(cmd);
717        } catch (NativeDaemonConnectorException e) {
718            throw e.rethrowAsParcelableException();
719        }
720    }
721
722    @Override
723    public void setInterfaceDown(String iface) {
724        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
725        final InterfaceConfiguration ifcg = getInterfaceConfig(iface);
726        ifcg.setInterfaceDown();
727        setInterfaceConfig(iface, ifcg);
728    }
729
730    @Override
731    public void setInterfaceUp(String iface) {
732        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
733        final InterfaceConfiguration ifcg = getInterfaceConfig(iface);
734        ifcg.setInterfaceUp();
735        setInterfaceConfig(iface, ifcg);
736    }
737
738    @Override
739    public void setInterfaceIpv6PrivacyExtensions(String iface, boolean enable) {
740        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
741        try {
742            mConnector.execute(
743                    "interface", "ipv6privacyextensions", iface, enable ? "enable" : "disable");
744        } catch (NativeDaemonConnectorException e) {
745            throw e.rethrowAsParcelableException();
746        }
747    }
748
749    /* TODO: This is right now a IPv4 only function. Works for wifi which loses its
750       IPv6 addresses on interface down, but we need to do full clean up here */
751    @Override
752    public void clearInterfaceAddresses(String iface) {
753        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
754        try {
755            mConnector.execute("interface", "clearaddrs", iface);
756        } catch (NativeDaemonConnectorException e) {
757            throw e.rethrowAsParcelableException();
758        }
759    }
760
761    @Override
762    public void enableIpv6(String iface) {
763        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
764        try {
765            mConnector.execute("interface", "ipv6", iface, "enable");
766        } catch (NativeDaemonConnectorException e) {
767            throw e.rethrowAsParcelableException();
768        }
769    }
770
771    @Override
772    public void disableIpv6(String iface) {
773        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
774        try {
775            mConnector.execute("interface", "ipv6", iface, "disable");
776        } catch (NativeDaemonConnectorException e) {
777            throw e.rethrowAsParcelableException();
778        }
779    }
780
781    @Override
782    public void addRoute(String interfaceName, RouteInfo route) {
783        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
784        modifyRoute(interfaceName, ADD, route, DEFAULT);
785    }
786
787    @Override
788    public void removeRoute(String interfaceName, RouteInfo route) {
789        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
790        modifyRoute(interfaceName, REMOVE, route, DEFAULT);
791    }
792
793    @Override
794    public void addSecondaryRoute(String interfaceName, RouteInfo route) {
795        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
796        modifyRoute(interfaceName, ADD, route, SECONDARY);
797    }
798
799    @Override
800    public void removeSecondaryRoute(String interfaceName, RouteInfo route) {
801        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
802        modifyRoute(interfaceName, REMOVE, route, SECONDARY);
803    }
804
805    private void modifyRoute(String interfaceName, String action, RouteInfo route, String type) {
806        final Command cmd = new Command("interface", "route", action, interfaceName, type);
807
808        // create triplet: dest-ip-addr prefixlength gateway-ip-addr
809        final LinkAddress la = route.getDestination();
810        cmd.appendArg(la.getAddress().getHostAddress());
811        cmd.appendArg(la.getNetworkPrefixLength());
812
813        if (route.getGateway() == null) {
814            if (la.getAddress() instanceof Inet4Address) {
815                cmd.appendArg("0.0.0.0");
816            } else {
817                cmd.appendArg("::0");
818            }
819        } else {
820            cmd.appendArg(route.getGateway().getHostAddress());
821        }
822
823        try {
824            mConnector.execute(cmd);
825        } catch (NativeDaemonConnectorException e) {
826            throw e.rethrowAsParcelableException();
827        }
828    }
829
830    private ArrayList<String> readRouteList(String filename) {
831        FileInputStream fstream = null;
832        ArrayList<String> list = new ArrayList<String>();
833
834        try {
835            fstream = new FileInputStream(filename);
836            DataInputStream in = new DataInputStream(fstream);
837            BufferedReader br = new BufferedReader(new InputStreamReader(in));
838            String s;
839
840            // throw away the title line
841
842            while (((s = br.readLine()) != null) && (s.length() != 0)) {
843                list.add(s);
844            }
845        } catch (IOException ex) {
846            // return current list, possibly empty
847        } finally {
848            if (fstream != null) {
849                try {
850                    fstream.close();
851                } catch (IOException ex) {}
852            }
853        }
854
855        return list;
856    }
857
858    @Override
859    public RouteInfo[] getRoutes(String interfaceName) {
860        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
861        ArrayList<RouteInfo> routes = new ArrayList<RouteInfo>();
862
863        // v4 routes listed as:
864        // iface dest-addr gateway-addr flags refcnt use metric netmask mtu window IRTT
865        for (String s : readRouteList("/proc/net/route")) {
866            String[] fields = s.split("\t");
867
868            if (fields.length > 7) {
869                String iface = fields[0];
870
871                if (interfaceName.equals(iface)) {
872                    String dest = fields[1];
873                    String gate = fields[2];
874                    String flags = fields[3]; // future use?
875                    String mask = fields[7];
876                    try {
877                        // address stored as a hex string, ex: 0014A8C0
878                        InetAddress destAddr =
879                                NetworkUtils.intToInetAddress((int)Long.parseLong(dest, 16));
880                        int prefixLength =
881                                NetworkUtils.netmaskIntToPrefixLength(
882                                (int)Long.parseLong(mask, 16));
883                        LinkAddress linkAddress = new LinkAddress(destAddr, prefixLength);
884
885                        // address stored as a hex string, ex 0014A8C0
886                        InetAddress gatewayAddr =
887                                NetworkUtils.intToInetAddress((int)Long.parseLong(gate, 16));
888
889                        RouteInfo route = new RouteInfo(linkAddress, gatewayAddr);
890                        routes.add(route);
891                    } catch (Exception e) {
892                        Log.e(TAG, "Error parsing route " + s + " : " + e);
893                        continue;
894                    }
895                }
896            }
897        }
898
899        // v6 routes listed as:
900        // dest-addr prefixlength ?? ?? gateway-addr ?? ?? ?? ?? iface
901        for (String s : readRouteList("/proc/net/ipv6_route")) {
902            String[]fields = s.split("\\s+");
903            if (fields.length > 9) {
904                String iface = fields[9].trim();
905                if (interfaceName.equals(iface)) {
906                    String dest = fields[0];
907                    String prefix = fields[1];
908                    String gate = fields[4];
909
910                    try {
911                        // prefix length stored as a hex string, ex 40
912                        int prefixLength = Integer.parseInt(prefix, 16);
913
914                        // address stored as a 32 char hex string
915                        // ex fe800000000000000000000000000000
916                        InetAddress destAddr = NetworkUtils.hexToInet6Address(dest);
917                        LinkAddress linkAddress = new LinkAddress(destAddr, prefixLength);
918
919                        InetAddress gateAddr = NetworkUtils.hexToInet6Address(gate);
920
921                        RouteInfo route = new RouteInfo(linkAddress, gateAddr);
922                        routes.add(route);
923                    } catch (Exception e) {
924                        Log.e(TAG, "Error parsing route " + s + " : " + e);
925                        continue;
926                    }
927                }
928            }
929        }
930        return routes.toArray(new RouteInfo[routes.size()]);
931    }
932
933    @Override
934    public void setMtu(String iface, int mtu) {
935        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
936
937        final NativeDaemonEvent event;
938        try {
939            event = mConnector.execute("interface", "setmtu", iface, mtu);
940        } catch (NativeDaemonConnectorException e) {
941            throw e.rethrowAsParcelableException();
942        }
943    }
944
945    @Override
946    public void shutdown() {
947        // TODO: remove from aidl if nobody calls externally
948        mContext.enforceCallingOrSelfPermission(SHUTDOWN, TAG);
949
950        Slog.d(TAG, "Shutting down");
951    }
952
953    @Override
954    public boolean getIpForwardingEnabled() throws IllegalStateException{
955        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
956
957        final NativeDaemonEvent event;
958        try {
959            event = mConnector.execute("ipfwd", "status");
960        } catch (NativeDaemonConnectorException e) {
961            throw e.rethrowAsParcelableException();
962        }
963
964        // 211 Forwarding enabled
965        event.checkCode(IpFwdStatusResult);
966        return event.getMessage().endsWith("enabled");
967    }
968
969    @Override
970    public void setIpForwardingEnabled(boolean enable) {
971        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
972        try {
973            mConnector.execute("ipfwd", enable ? "enable" : "disable");
974        } catch (NativeDaemonConnectorException e) {
975            throw e.rethrowAsParcelableException();
976        }
977    }
978
979    @Override
980    public void startTethering(String[] dhcpRange) {
981        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
982        // cmd is "tether start first_start first_stop second_start second_stop ..."
983        // an odd number of addrs will fail
984
985        final Command cmd = new Command("tether", "start");
986        for (String d : dhcpRange) {
987            cmd.appendArg(d);
988        }
989
990        try {
991            mConnector.execute(cmd);
992        } catch (NativeDaemonConnectorException e) {
993            throw e.rethrowAsParcelableException();
994        }
995    }
996
997    @Override
998    public void stopTethering() {
999        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1000        try {
1001            mConnector.execute("tether", "stop");
1002        } catch (NativeDaemonConnectorException e) {
1003            throw e.rethrowAsParcelableException();
1004        }
1005    }
1006
1007    @Override
1008    public boolean isTetheringStarted() {
1009        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1010
1011        final NativeDaemonEvent event;
1012        try {
1013            event = mConnector.execute("tether", "status");
1014        } catch (NativeDaemonConnectorException e) {
1015            throw e.rethrowAsParcelableException();
1016        }
1017
1018        // 210 Tethering services started
1019        event.checkCode(TetherStatusResult);
1020        return event.getMessage().endsWith("started");
1021    }
1022
1023    @Override
1024    public void tetherInterface(String iface) {
1025        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1026        try {
1027            mConnector.execute("tether", "interface", "add", iface);
1028        } catch (NativeDaemonConnectorException e) {
1029            throw e.rethrowAsParcelableException();
1030        }
1031    }
1032
1033    @Override
1034    public void untetherInterface(String iface) {
1035        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1036        try {
1037            mConnector.execute("tether", "interface", "remove", iface);
1038        } catch (NativeDaemonConnectorException e) {
1039            throw e.rethrowAsParcelableException();
1040        }
1041    }
1042
1043    @Override
1044    public String[] listTetheredInterfaces() {
1045        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1046        try {
1047            return NativeDaemonEvent.filterMessageList(
1048                    mConnector.executeForList("tether", "interface", "list"),
1049                    TetherInterfaceListResult);
1050        } catch (NativeDaemonConnectorException e) {
1051            throw e.rethrowAsParcelableException();
1052        }
1053    }
1054
1055    @Override
1056    public void setDnsForwarders(String[] dns) {
1057        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1058
1059        final Command cmd = new Command("tether", "dns", "set");
1060        for (String s : dns) {
1061            cmd.appendArg(NetworkUtils.numericToInetAddress(s).getHostAddress());
1062        }
1063
1064        try {
1065            mConnector.execute(cmd);
1066        } catch (NativeDaemonConnectorException e) {
1067            throw e.rethrowAsParcelableException();
1068        }
1069    }
1070
1071    @Override
1072    public String[] getDnsForwarders() {
1073        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1074        try {
1075            return NativeDaemonEvent.filterMessageList(
1076                    mConnector.executeForList("tether", "dns", "list"), TetherDnsFwdTgtListResult);
1077        } catch (NativeDaemonConnectorException e) {
1078            throw e.rethrowAsParcelableException();
1079        }
1080    }
1081
1082    private List<InterfaceAddress> excludeLinkLocal(List<InterfaceAddress> addresses) {
1083        ArrayList<InterfaceAddress> filtered = new ArrayList<InterfaceAddress>(addresses.size());
1084        for (InterfaceAddress ia : addresses) {
1085            if (!ia.getAddress().isLinkLocalAddress())
1086                filtered.add(ia);
1087        }
1088        return filtered;
1089    }
1090
1091    private void modifyNat(String action, String internalInterface, String externalInterface)
1092            throws SocketException {
1093        final Command cmd = new Command("nat", action, internalInterface, externalInterface);
1094
1095        final NetworkInterface internalNetworkInterface = NetworkInterface.getByName(
1096                internalInterface);
1097        if (internalNetworkInterface == null) {
1098            cmd.appendArg("0");
1099        } else {
1100            // Don't touch link-local routes, as link-local addresses aren't routable,
1101            // kernel creates link-local routes on all interfaces automatically
1102            List<InterfaceAddress> interfaceAddresses = excludeLinkLocal(
1103                    internalNetworkInterface.getInterfaceAddresses());
1104            cmd.appendArg(interfaceAddresses.size());
1105            for (InterfaceAddress ia : interfaceAddresses) {
1106                InetAddress addr = NetworkUtils.getNetworkPart(
1107                        ia.getAddress(), ia.getNetworkPrefixLength());
1108                cmd.appendArg(addr.getHostAddress() + "/" + ia.getNetworkPrefixLength());
1109            }
1110        }
1111
1112        try {
1113            mConnector.execute(cmd);
1114        } catch (NativeDaemonConnectorException e) {
1115            throw e.rethrowAsParcelableException();
1116        }
1117    }
1118
1119    @Override
1120    public void enableNat(String internalInterface, String externalInterface) {
1121        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1122        try {
1123            modifyNat("enable", internalInterface, externalInterface);
1124        } catch (SocketException e) {
1125            throw new IllegalStateException(e);
1126        }
1127    }
1128
1129    @Override
1130    public void disableNat(String internalInterface, String externalInterface) {
1131        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1132        try {
1133            modifyNat("disable", internalInterface, externalInterface);
1134        } catch (SocketException e) {
1135            throw new IllegalStateException(e);
1136        }
1137    }
1138
1139    @Override
1140    public String[] listTtys() {
1141        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1142        try {
1143            return NativeDaemonEvent.filterMessageList(
1144                    mConnector.executeForList("list_ttys"), TtyListResult);
1145        } catch (NativeDaemonConnectorException e) {
1146            throw e.rethrowAsParcelableException();
1147        }
1148    }
1149
1150    @Override
1151    public void attachPppd(
1152            String tty, String localAddr, String remoteAddr, String dns1Addr, String dns2Addr) {
1153        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1154        try {
1155            mConnector.execute("pppd", "attach", tty,
1156                    NetworkUtils.numericToInetAddress(localAddr).getHostAddress(),
1157                    NetworkUtils.numericToInetAddress(remoteAddr).getHostAddress(),
1158                    NetworkUtils.numericToInetAddress(dns1Addr).getHostAddress(),
1159                    NetworkUtils.numericToInetAddress(dns2Addr).getHostAddress());
1160        } catch (NativeDaemonConnectorException e) {
1161            throw e.rethrowAsParcelableException();
1162        }
1163    }
1164
1165    @Override
1166    public void detachPppd(String tty) {
1167        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1168        try {
1169            mConnector.execute("pppd", "detach", tty);
1170        } catch (NativeDaemonConnectorException e) {
1171            throw e.rethrowAsParcelableException();
1172        }
1173    }
1174
1175    @Override
1176    public void startAccessPoint(
1177            WifiConfiguration wifiConfig, String wlanIface) {
1178        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1179        try {
1180            wifiFirmwareReload(wlanIface, "AP");
1181            if (wifiConfig == null) {
1182                mConnector.execute("softap", "set", wlanIface);
1183            } else {
1184                mConnector.execute("softap", "set", wlanIface, wifiConfig.SSID,
1185                                   "broadcast", "6", getSecurityType(wifiConfig),
1186                                   new SensitiveArg(wifiConfig.preSharedKey));
1187            }
1188            mConnector.execute("softap", "startap");
1189        } catch (NativeDaemonConnectorException e) {
1190            throw e.rethrowAsParcelableException();
1191        }
1192    }
1193
1194    private static String getSecurityType(WifiConfiguration wifiConfig) {
1195        switch (wifiConfig.getAuthType()) {
1196            case KeyMgmt.WPA_PSK:
1197                return "wpa-psk";
1198            case KeyMgmt.WPA2_PSK:
1199                return "wpa2-psk";
1200            default:
1201                return "open";
1202        }
1203    }
1204
1205    /* @param mode can be "AP", "STA" or "P2P" */
1206    @Override
1207    public void wifiFirmwareReload(String wlanIface, String mode) {
1208        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1209        try {
1210            mConnector.execute("softap", "fwreload", wlanIface, mode);
1211        } catch (NativeDaemonConnectorException e) {
1212            throw e.rethrowAsParcelableException();
1213        }
1214    }
1215
1216    @Override
1217    public void stopAccessPoint(String wlanIface) {
1218        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1219        try {
1220            mConnector.execute("softap", "stopap");
1221            wifiFirmwareReload(wlanIface, "STA");
1222        } catch (NativeDaemonConnectorException e) {
1223            throw e.rethrowAsParcelableException();
1224        }
1225    }
1226
1227    @Override
1228    public void setAccessPoint(WifiConfiguration wifiConfig, String wlanIface) {
1229        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1230        try {
1231            if (wifiConfig == null) {
1232                mConnector.execute("softap", "set", wlanIface);
1233            } else {
1234                mConnector.execute("softap", "set", wlanIface, wifiConfig.SSID,
1235                                   "broadcast", "6", getSecurityType(wifiConfig),
1236                                   new SensitiveArg(wifiConfig.preSharedKey));
1237            }
1238        } catch (NativeDaemonConnectorException e) {
1239            throw e.rethrowAsParcelableException();
1240        }
1241    }
1242
1243    @Override
1244    public void addIdleTimer(String iface, int timeout, final int type) {
1245        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1246
1247        if (DBG) Slog.d(TAG, "Adding idletimer");
1248
1249        synchronized (mIdleTimerLock) {
1250            IdleTimerParams params = mActiveIdleTimers.get(iface);
1251            if (params != null) {
1252                // the interface already has idletimer, update network count
1253                params.networkCount++;
1254                return;
1255            }
1256
1257            try {
1258                mConnector.execute("idletimer", "add", iface, Integer.toString(timeout),
1259                        Integer.toString(type));
1260            } catch (NativeDaemonConnectorException e) {
1261                throw e.rethrowAsParcelableException();
1262            }
1263            mActiveIdleTimers.put(iface, new IdleTimerParams(timeout, type));
1264
1265            // Networks start up.
1266            if (ConnectivityManager.isNetworkTypeMobile(type)) {
1267                mNetworkActive = false;
1268            }
1269            mMainHandler.post(new Runnable() {
1270                @Override public void run() {
1271                    notifyInterfaceClassActivity(type, true, SystemClock.elapsedRealtimeNanos());
1272                }
1273            });
1274        }
1275    }
1276
1277    @Override
1278    public void removeIdleTimer(String iface) {
1279        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1280
1281        if (DBG) Slog.d(TAG, "Removing idletimer");
1282
1283        synchronized (mIdleTimerLock) {
1284            final IdleTimerParams params = mActiveIdleTimers.get(iface);
1285            if (params == null || --(params.networkCount) > 0) {
1286                return;
1287            }
1288
1289            try {
1290                mConnector.execute("idletimer", "remove", iface,
1291                        Integer.toString(params.timeout), Integer.toString(params.type));
1292            } catch (NativeDaemonConnectorException e) {
1293                throw e.rethrowAsParcelableException();
1294            }
1295            mActiveIdleTimers.remove(iface);
1296            mMainHandler.post(new Runnable() {
1297                @Override public void run() {
1298                    notifyInterfaceClassActivity(params.type, false,
1299                            SystemClock.elapsedRealtimeNanos());
1300                }
1301            });
1302        }
1303    }
1304
1305    @Override
1306    public NetworkStats getNetworkStatsSummaryDev() {
1307        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1308        try {
1309            return mStatsFactory.readNetworkStatsSummaryDev();
1310        } catch (IOException e) {
1311            throw new IllegalStateException(e);
1312        }
1313    }
1314
1315    @Override
1316    public NetworkStats getNetworkStatsSummaryXt() {
1317        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1318        try {
1319            return mStatsFactory.readNetworkStatsSummaryXt();
1320        } catch (IOException e) {
1321            throw new IllegalStateException(e);
1322        }
1323    }
1324
1325    @Override
1326    public NetworkStats getNetworkStatsDetail() {
1327        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1328        try {
1329            return mStatsFactory.readNetworkStatsDetail(UID_ALL, null, TAG_ALL, null);
1330        } catch (IOException e) {
1331            throw new IllegalStateException(e);
1332        }
1333    }
1334
1335    @Override
1336    public void setInterfaceQuota(String iface, long quotaBytes) {
1337        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1338
1339        // silently discard when control disabled
1340        // TODO: eventually migrate to be always enabled
1341        if (!mBandwidthControlEnabled) return;
1342
1343        synchronized (mQuotaLock) {
1344            if (mActiveQuotas.containsKey(iface)) {
1345                throw new IllegalStateException("iface " + iface + " already has quota");
1346            }
1347
1348            try {
1349                // TODO: support quota shared across interfaces
1350                mConnector.execute("bandwidth", "setiquota", iface, quotaBytes);
1351                mActiveQuotas.put(iface, quotaBytes);
1352            } catch (NativeDaemonConnectorException e) {
1353                throw e.rethrowAsParcelableException();
1354            }
1355        }
1356    }
1357
1358    @Override
1359    public void removeInterfaceQuota(String iface) {
1360        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1361
1362        // silently discard when control disabled
1363        // TODO: eventually migrate to be always enabled
1364        if (!mBandwidthControlEnabled) return;
1365
1366        synchronized (mQuotaLock) {
1367            if (!mActiveQuotas.containsKey(iface)) {
1368                // TODO: eventually consider throwing
1369                return;
1370            }
1371
1372            mActiveQuotas.remove(iface);
1373            mActiveAlerts.remove(iface);
1374
1375            try {
1376                // TODO: support quota shared across interfaces
1377                mConnector.execute("bandwidth", "removeiquota", iface);
1378            } catch (NativeDaemonConnectorException e) {
1379                throw e.rethrowAsParcelableException();
1380            }
1381        }
1382    }
1383
1384    @Override
1385    public void setInterfaceAlert(String iface, long alertBytes) {
1386        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1387
1388        // silently discard when control disabled
1389        // TODO: eventually migrate to be always enabled
1390        if (!mBandwidthControlEnabled) return;
1391
1392        // quick sanity check
1393        if (!mActiveQuotas.containsKey(iface)) {
1394            throw new IllegalStateException("setting alert requires existing quota on iface");
1395        }
1396
1397        synchronized (mQuotaLock) {
1398            if (mActiveAlerts.containsKey(iface)) {
1399                throw new IllegalStateException("iface " + iface + " already has alert");
1400            }
1401
1402            try {
1403                // TODO: support alert shared across interfaces
1404                mConnector.execute("bandwidth", "setinterfacealert", iface, alertBytes);
1405                mActiveAlerts.put(iface, alertBytes);
1406            } catch (NativeDaemonConnectorException e) {
1407                throw e.rethrowAsParcelableException();
1408            }
1409        }
1410    }
1411
1412    @Override
1413    public void removeInterfaceAlert(String iface) {
1414        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1415
1416        // silently discard when control disabled
1417        // TODO: eventually migrate to be always enabled
1418        if (!mBandwidthControlEnabled) return;
1419
1420        synchronized (mQuotaLock) {
1421            if (!mActiveAlerts.containsKey(iface)) {
1422                // TODO: eventually consider throwing
1423                return;
1424            }
1425
1426            try {
1427                // TODO: support alert shared across interfaces
1428                mConnector.execute("bandwidth", "removeinterfacealert", iface);
1429                mActiveAlerts.remove(iface);
1430            } catch (NativeDaemonConnectorException e) {
1431                throw e.rethrowAsParcelableException();
1432            }
1433        }
1434    }
1435
1436    @Override
1437    public void setGlobalAlert(long alertBytes) {
1438        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1439
1440        // silently discard when control disabled
1441        // TODO: eventually migrate to be always enabled
1442        if (!mBandwidthControlEnabled) return;
1443
1444        try {
1445            mConnector.execute("bandwidth", "setglobalalert", alertBytes);
1446        } catch (NativeDaemonConnectorException e) {
1447            throw e.rethrowAsParcelableException();
1448        }
1449    }
1450
1451    @Override
1452    public void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces) {
1453        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1454
1455        // silently discard when control disabled
1456        // TODO: eventually migrate to be always enabled
1457        if (!mBandwidthControlEnabled) return;
1458
1459        synchronized (mQuotaLock) {
1460            final boolean oldRejectOnQuota = mUidRejectOnQuota.get(uid, false);
1461            if (oldRejectOnQuota == rejectOnQuotaInterfaces) {
1462                // TODO: eventually consider throwing
1463                return;
1464            }
1465
1466            try {
1467                mConnector.execute("bandwidth",
1468                        rejectOnQuotaInterfaces ? "addnaughtyapps" : "removenaughtyapps", uid);
1469                if (rejectOnQuotaInterfaces) {
1470                    mUidRejectOnQuota.put(uid, true);
1471                } else {
1472                    mUidRejectOnQuota.delete(uid);
1473                }
1474            } catch (NativeDaemonConnectorException e) {
1475                throw e.rethrowAsParcelableException();
1476            }
1477        }
1478    }
1479
1480    @Override
1481    public boolean isBandwidthControlEnabled() {
1482        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1483        return mBandwidthControlEnabled;
1484    }
1485
1486    @Override
1487    public NetworkStats getNetworkStatsUidDetail(int uid) {
1488        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1489        try {
1490            return mStatsFactory.readNetworkStatsDetail(uid, null, TAG_ALL, null);
1491        } catch (IOException e) {
1492            throw new IllegalStateException(e);
1493        }
1494    }
1495
1496    @Override
1497    public NetworkStats getNetworkStatsTethering() {
1498        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1499
1500        final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1);
1501        try {
1502            final NativeDaemonEvent[] events = mConnector.executeForList(
1503                    "bandwidth", "gettetherstats");
1504            for (NativeDaemonEvent event : events) {
1505                if (event.getCode() != TetheringStatsListResult) continue;
1506
1507                // 114 ifaceIn ifaceOut rx_bytes rx_packets tx_bytes tx_packets
1508                final StringTokenizer tok = new StringTokenizer(event.getMessage());
1509                try {
1510                    final String ifaceIn = tok.nextToken();
1511                    final String ifaceOut = tok.nextToken();
1512
1513                    final NetworkStats.Entry entry = new NetworkStats.Entry();
1514                    entry.iface = ifaceOut;
1515                    entry.uid = UID_TETHERING;
1516                    entry.set = SET_DEFAULT;
1517                    entry.tag = TAG_NONE;
1518                    entry.rxBytes = Long.parseLong(tok.nextToken());
1519                    entry.rxPackets = Long.parseLong(tok.nextToken());
1520                    entry.txBytes = Long.parseLong(tok.nextToken());
1521                    entry.txPackets = Long.parseLong(tok.nextToken());
1522                    stats.combineValues(entry);
1523                } catch (NoSuchElementException e) {
1524                    throw new IllegalStateException("problem parsing tethering stats: " + event);
1525                } catch (NumberFormatException e) {
1526                    throw new IllegalStateException("problem parsing tethering stats: " + event);
1527                }
1528            }
1529        } catch (NativeDaemonConnectorException e) {
1530            throw e.rethrowAsParcelableException();
1531        }
1532        return stats;
1533    }
1534
1535    @Override
1536    public void setDefaultInterfaceForDns(String iface) {
1537        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1538        try {
1539            mConnector.execute("resolver", "setdefaultif", iface);
1540        } catch (NativeDaemonConnectorException e) {
1541            throw e.rethrowAsParcelableException();
1542        }
1543    }
1544
1545    @Override
1546    public void setDnsServersForInterface(String iface, String[] servers, String domains) {
1547        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1548
1549        final Command cmd = new Command("resolver", "setifdns", iface,
1550                (domains == null ? "" : domains));
1551
1552        for (String s : servers) {
1553            InetAddress a = NetworkUtils.numericToInetAddress(s);
1554            if (a.isAnyLocalAddress() == false) {
1555                cmd.appendArg(a.getHostAddress());
1556            }
1557        }
1558
1559        try {
1560            mConnector.execute(cmd);
1561        } catch (NativeDaemonConnectorException e) {
1562            throw e.rethrowAsParcelableException();
1563        }
1564    }
1565
1566    @Override
1567    public void setUidRangeRoute(String iface, int uid_start, int uid_end) {
1568        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1569        try {
1570            mConnector.execute("interface", "fwmark",
1571                    "uid", "add", iface, uid_start, uid_end);
1572        } catch (NativeDaemonConnectorException e) {
1573            throw e.rethrowAsParcelableException();
1574        }
1575    }
1576
1577    @Override
1578    public void clearUidRangeRoute(String iface, int uid_start, int uid_end) {
1579        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1580        try {
1581            mConnector.execute("interface", "fwmark",
1582                    "uid", "remove", iface, uid_start, uid_end);
1583        } catch (NativeDaemonConnectorException e) {
1584            throw e.rethrowAsParcelableException();
1585        }
1586    }
1587
1588    @Override
1589    public void setMarkedForwarding(String iface) {
1590        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1591        try {
1592            mConnector.execute("interface", "fwmark", "rule", "add", iface);
1593        } catch (NativeDaemonConnectorException e) {
1594            throw e.rethrowAsParcelableException();
1595        }
1596    }
1597
1598    @Override
1599    public void clearMarkedForwarding(String iface) {
1600        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1601        try {
1602            mConnector.execute("interface", "fwmark", "rule", "remove", iface);
1603        } catch (NativeDaemonConnectorException e) {
1604            throw e.rethrowAsParcelableException();
1605        }
1606    }
1607
1608    @Override
1609    public int getMarkForUid(int uid) {
1610        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1611        final NativeDaemonEvent event;
1612        try {
1613            event = mConnector.execute("interface", "fwmark", "get", "mark", uid);
1614        } catch (NativeDaemonConnectorException e) {
1615            throw e.rethrowAsParcelableException();
1616        }
1617        event.checkCode(GetMarkResult);
1618        return Integer.parseInt(event.getMessage());
1619    }
1620
1621    @Override
1622    public int getMarkForProtect() {
1623        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1624        final NativeDaemonEvent event;
1625        try {
1626            event = mConnector.execute("interface", "fwmark", "get", "protect");
1627        } catch (NativeDaemonConnectorException e) {
1628            throw e.rethrowAsParcelableException();
1629        }
1630        event.checkCode(GetMarkResult);
1631        return Integer.parseInt(event.getMessage());
1632    }
1633
1634    @Override
1635    public void setMarkedForwardingRoute(String iface, RouteInfo route) {
1636        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1637        try {
1638            LinkAddress dest = route.getDestination();
1639            mConnector.execute("interface", "fwmark", "route", "add", iface,
1640                    dest.getAddress().getHostAddress(), dest.getNetworkPrefixLength());
1641        } catch (NativeDaemonConnectorException e) {
1642            throw e.rethrowAsParcelableException();
1643        }
1644    }
1645
1646    @Override
1647    public void clearMarkedForwardingRoute(String iface, RouteInfo route) {
1648        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1649        try {
1650            LinkAddress dest = route.getDestination();
1651            mConnector.execute("interface", "fwmark", "route", "remove", iface,
1652                    dest.getAddress().getHostAddress(), dest.getNetworkPrefixLength());
1653        } catch (NativeDaemonConnectorException e) {
1654            throw e.rethrowAsParcelableException();
1655        }
1656    }
1657
1658    @Override
1659    public void setHostExemption(LinkAddress host) {
1660        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1661        try {
1662            mConnector.execute("interface", "fwmark", "exempt", "add", host);
1663        } catch (NativeDaemonConnectorException e) {
1664            throw e.rethrowAsParcelableException();
1665        }
1666    }
1667
1668    @Override
1669    public void clearHostExemption(LinkAddress host) {
1670        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1671        try {
1672            mConnector.execute("interface", "fwmark", "exempt", "remove", host);
1673        } catch (NativeDaemonConnectorException e) {
1674            throw e.rethrowAsParcelableException();
1675        }
1676    }
1677
1678    @Override
1679    public void setDnsInterfaceForUidRange(String iface, int uid_start, int uid_end) {
1680        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1681        try {
1682            mConnector.execute("resolver", "setifaceforuidrange", iface, uid_start, uid_end);
1683        } catch (NativeDaemonConnectorException e) {
1684            throw e.rethrowAsParcelableException();
1685        }
1686    }
1687
1688    @Override
1689    public void clearDnsInterfaceForUidRange(int uid_start, int uid_end) {
1690        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1691        try {
1692            mConnector.execute("resolver", "clearifaceforuidrange", uid_start, uid_end);
1693        } catch (NativeDaemonConnectorException e) {
1694            throw e.rethrowAsParcelableException();
1695        }
1696    }
1697
1698    @Override
1699    public void clearDnsInterfaceMaps() {
1700        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1701        try {
1702            mConnector.execute("resolver", "clearifacemapping");
1703        } catch (NativeDaemonConnectorException e) {
1704            throw e.rethrowAsParcelableException();
1705        }
1706    }
1707
1708
1709    @Override
1710    public void flushDefaultDnsCache() {
1711        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1712        try {
1713            mConnector.execute("resolver", "flushdefaultif");
1714        } catch (NativeDaemonConnectorException e) {
1715            throw e.rethrowAsParcelableException();
1716        }
1717    }
1718
1719    @Override
1720    public void flushInterfaceDnsCache(String iface) {
1721        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1722        try {
1723            mConnector.execute("resolver", "flushif", iface);
1724        } catch (NativeDaemonConnectorException e) {
1725            throw e.rethrowAsParcelableException();
1726        }
1727    }
1728
1729    @Override
1730    public void setFirewallEnabled(boolean enabled) {
1731        enforceSystemUid();
1732        try {
1733            mConnector.execute("firewall", enabled ? "enable" : "disable");
1734            mFirewallEnabled = enabled;
1735        } catch (NativeDaemonConnectorException e) {
1736            throw e.rethrowAsParcelableException();
1737        }
1738    }
1739
1740    @Override
1741    public boolean isFirewallEnabled() {
1742        enforceSystemUid();
1743        return mFirewallEnabled;
1744    }
1745
1746    @Override
1747    public void setFirewallInterfaceRule(String iface, boolean allow) {
1748        enforceSystemUid();
1749        Preconditions.checkState(mFirewallEnabled);
1750        final String rule = allow ? ALLOW : DENY;
1751        try {
1752            mConnector.execute("firewall", "set_interface_rule", iface, rule);
1753        } catch (NativeDaemonConnectorException e) {
1754            throw e.rethrowAsParcelableException();
1755        }
1756    }
1757
1758    @Override
1759    public void setFirewallEgressSourceRule(String addr, boolean allow) {
1760        enforceSystemUid();
1761        Preconditions.checkState(mFirewallEnabled);
1762        final String rule = allow ? ALLOW : DENY;
1763        try {
1764            mConnector.execute("firewall", "set_egress_source_rule", addr, rule);
1765        } catch (NativeDaemonConnectorException e) {
1766            throw e.rethrowAsParcelableException();
1767        }
1768    }
1769
1770    @Override
1771    public void setFirewallEgressDestRule(String addr, int port, boolean allow) {
1772        enforceSystemUid();
1773        Preconditions.checkState(mFirewallEnabled);
1774        final String rule = allow ? ALLOW : DENY;
1775        try {
1776            mConnector.execute("firewall", "set_egress_dest_rule", addr, port, rule);
1777        } catch (NativeDaemonConnectorException e) {
1778            throw e.rethrowAsParcelableException();
1779        }
1780    }
1781
1782    @Override
1783    public void setFirewallUidRule(int uid, boolean allow) {
1784        enforceSystemUid();
1785        Preconditions.checkState(mFirewallEnabled);
1786        final String rule = allow ? ALLOW : DENY;
1787        try {
1788            mConnector.execute("firewall", "set_uid_rule", uid, rule);
1789        } catch (NativeDaemonConnectorException e) {
1790            throw e.rethrowAsParcelableException();
1791        }
1792    }
1793
1794    private static void enforceSystemUid() {
1795        final int uid = Binder.getCallingUid();
1796        if (uid != Process.SYSTEM_UID) {
1797            throw new SecurityException("Only available to AID_SYSTEM");
1798        }
1799    }
1800
1801    @Override
1802    public void setDnsInterfaceForPid(String iface, int pid) throws IllegalStateException {
1803        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1804        try {
1805            mConnector.execute("resolver", "setifaceforpid", iface, pid);
1806        } catch (NativeDaemonConnectorException e) {
1807            throw new IllegalStateException(
1808                    "Error communicating with native deamon to set interface for pid" + iface, e);
1809        }
1810    }
1811
1812    @Override
1813    public void clearDnsInterfaceForPid(int pid) throws IllegalStateException {
1814        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1815        try {
1816            mConnector.execute("resolver", "clearifaceforpid", pid);
1817        } catch (NativeDaemonConnectorException e) {
1818            throw new IllegalStateException(
1819                    "Error communicating with native deamon to clear interface for pid " + pid, e);
1820        }
1821    }
1822
1823    @Override
1824    public void startClatd(String interfaceName) throws IllegalStateException {
1825        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1826
1827        try {
1828            mConnector.execute("clatd", "start", interfaceName);
1829        } catch (NativeDaemonConnectorException e) {
1830            throw e.rethrowAsParcelableException();
1831        }
1832    }
1833
1834    @Override
1835    public void stopClatd() throws IllegalStateException {
1836        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1837
1838        try {
1839            mConnector.execute("clatd", "stop");
1840        } catch (NativeDaemonConnectorException e) {
1841            throw e.rethrowAsParcelableException();
1842        }
1843    }
1844
1845    @Override
1846    public boolean isClatdStarted() {
1847        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1848
1849        final NativeDaemonEvent event;
1850        try {
1851            event = mConnector.execute("clatd", "status");
1852        } catch (NativeDaemonConnectorException e) {
1853            throw e.rethrowAsParcelableException();
1854        }
1855
1856        event.checkCode(ClatdStatusResult);
1857        return event.getMessage().endsWith("started");
1858    }
1859
1860    @Override
1861    public void registerNetworkActivityListener(INetworkActivityListener listener) {
1862        mNetworkActivityListeners.register(listener);
1863    }
1864
1865    @Override
1866    public void unregisterNetworkActivityListener(INetworkActivityListener listener) {
1867        mNetworkActivityListeners.unregister(listener);
1868    }
1869
1870    @Override
1871    public boolean isNetworkActive() {
1872        synchronized (mNetworkActivityListeners) {
1873            return mNetworkActive || mActiveIdleTimers.isEmpty();
1874        }
1875    }
1876
1877    private void reportNetworkActive() {
1878        final int length = mNetworkActivityListeners.beginBroadcast();
1879        for (int i = 0; i < length; i++) {
1880            try {
1881                mNetworkActivityListeners.getBroadcastItem(i).onNetworkActive();
1882            } catch (RemoteException e) {
1883            } catch (RuntimeException e) {
1884            }
1885        }
1886        mNetworkActivityListeners.finishBroadcast();
1887    }
1888
1889    /** {@inheritDoc} */
1890    @Override
1891    public void monitor() {
1892        if (mConnector != null) {
1893            mConnector.monitor();
1894        }
1895    }
1896
1897    @Override
1898    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1899        mContext.enforceCallingOrSelfPermission(DUMP, TAG);
1900
1901        pw.println("NetworkManagementService NativeDaemonConnector Log:");
1902        mConnector.dump(fd, pw, args);
1903        pw.println();
1904
1905        pw.print("Bandwidth control enabled: "); pw.println(mBandwidthControlEnabled);
1906
1907        synchronized (mQuotaLock) {
1908            pw.print("Active quota ifaces: "); pw.println(mActiveQuotas.toString());
1909            pw.print("Active alert ifaces: "); pw.println(mActiveAlerts.toString());
1910        }
1911
1912        synchronized (mUidRejectOnQuota) {
1913            pw.print("UID reject on quota ifaces: [");
1914            final int size = mUidRejectOnQuota.size();
1915            for (int i = 0; i < size; i++) {
1916                pw.print(mUidRejectOnQuota.keyAt(i));
1917                if (i < size - 1) pw.print(",");
1918            }
1919            pw.println("]");
1920        }
1921
1922        synchronized (mIdleTimerLock) {
1923            pw.println("Idle timers:");
1924            for (HashMap.Entry<String, IdleTimerParams> ent : mActiveIdleTimers.entrySet()) {
1925                pw.print("  "); pw.print(ent.getKey()); pw.println(":");
1926                IdleTimerParams params = ent.getValue();
1927                pw.print("    timeout="); pw.print(params.timeout);
1928                pw.print(" type="); pw.print(params.type);
1929                pw.print(" networkCount="); pw.println(params.networkCount);
1930            }
1931        }
1932
1933        pw.print("Firewall enabled: "); pw.println(mFirewallEnabled);
1934    }
1935}
1936