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