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