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