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