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