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