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