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