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