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, uid);
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    @Override
975    public INetd getNetdService() throws RemoteException {
976        final CountDownLatch connectedSignal = mConnectedSignal;
977        if (connectedSignal != null) {
978            try {
979                connectedSignal.await();
980            } catch (InterruptedException ignored) {}
981        }
982
983        return mNetdService;
984    }
985
986    @Override
987    public String[] listInterfaces() {
988        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
989        try {
990            return NativeDaemonEvent.filterMessageList(
991                    mConnector.executeForList("interface", "list"), InterfaceListResult);
992        } catch (NativeDaemonConnectorException e) {
993            throw e.rethrowAsParcelableException();
994        }
995    }
996
997    @Override
998    public InterfaceConfiguration getInterfaceConfig(String iface) {
999        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1000
1001        final NativeDaemonEvent event;
1002        try {
1003            event = mConnector.execute("interface", "getcfg", iface);
1004        } catch (NativeDaemonConnectorException e) {
1005            throw e.rethrowAsParcelableException();
1006        }
1007
1008        event.checkCode(InterfaceGetCfgResult);
1009
1010        // Rsp: 213 xx:xx:xx:xx:xx:xx yyy.yyy.yyy.yyy zzz flag1 flag2 flag3
1011        final StringTokenizer st = new StringTokenizer(event.getMessage());
1012
1013        InterfaceConfiguration cfg;
1014        try {
1015            cfg = new InterfaceConfiguration();
1016            cfg.setHardwareAddress(st.nextToken(" "));
1017            InetAddress addr = null;
1018            int prefixLength = 0;
1019            try {
1020                addr = NetworkUtils.numericToInetAddress(st.nextToken());
1021            } catch (IllegalArgumentException iae) {
1022                Slog.e(TAG, "Failed to parse ipaddr", iae);
1023            }
1024
1025            try {
1026                prefixLength = Integer.parseInt(st.nextToken());
1027            } catch (NumberFormatException nfe) {
1028                Slog.e(TAG, "Failed to parse prefixLength", nfe);
1029            }
1030
1031            cfg.setLinkAddress(new LinkAddress(addr, prefixLength));
1032            while (st.hasMoreTokens()) {
1033                cfg.setFlag(st.nextToken());
1034            }
1035        } catch (NoSuchElementException nsee) {
1036            throw new IllegalStateException("Invalid response from daemon: " + event);
1037        }
1038        return cfg;
1039    }
1040
1041    @Override
1042    public void setInterfaceConfig(String iface, InterfaceConfiguration cfg) {
1043        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1044        LinkAddress linkAddr = cfg.getLinkAddress();
1045        if (linkAddr == null || linkAddr.getAddress() == null) {
1046            throw new IllegalStateException("Null LinkAddress given");
1047        }
1048
1049        final Command cmd = new Command("interface", "setcfg", iface,
1050                linkAddr.getAddress().getHostAddress(),
1051                linkAddr.getPrefixLength());
1052        for (String flag : cfg.getFlags()) {
1053            cmd.appendArg(flag);
1054        }
1055
1056        try {
1057            mConnector.execute(cmd);
1058        } catch (NativeDaemonConnectorException e) {
1059            throw e.rethrowAsParcelableException();
1060        }
1061    }
1062
1063    @Override
1064    public void setInterfaceDown(String iface) {
1065        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1066        final InterfaceConfiguration ifcg = getInterfaceConfig(iface);
1067        ifcg.setInterfaceDown();
1068        setInterfaceConfig(iface, ifcg);
1069    }
1070
1071    @Override
1072    public void setInterfaceUp(String iface) {
1073        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1074        final InterfaceConfiguration ifcg = getInterfaceConfig(iface);
1075        ifcg.setInterfaceUp();
1076        setInterfaceConfig(iface, ifcg);
1077    }
1078
1079    @Override
1080    public void setInterfaceIpv6PrivacyExtensions(String iface, boolean enable) {
1081        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1082        try {
1083            mConnector.execute(
1084                    "interface", "ipv6privacyextensions", iface, enable ? "enable" : "disable");
1085        } catch (NativeDaemonConnectorException e) {
1086            throw e.rethrowAsParcelableException();
1087        }
1088    }
1089
1090    /* TODO: This is right now a IPv4 only function. Works for wifi which loses its
1091       IPv6 addresses on interface down, but we need to do full clean up here */
1092    @Override
1093    public void clearInterfaceAddresses(String iface) {
1094        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1095        try {
1096            mConnector.execute("interface", "clearaddrs", iface);
1097        } catch (NativeDaemonConnectorException e) {
1098            throw e.rethrowAsParcelableException();
1099        }
1100    }
1101
1102    @Override
1103    public void enableIpv6(String iface) {
1104        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1105        try {
1106            mConnector.execute("interface", "ipv6", iface, "enable");
1107        } catch (NativeDaemonConnectorException e) {
1108            throw e.rethrowAsParcelableException();
1109        }
1110    }
1111
1112    @Override
1113    public void disableIpv6(String iface) {
1114        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1115        try {
1116            mConnector.execute("interface", "ipv6", iface, "disable");
1117        } catch (NativeDaemonConnectorException e) {
1118            throw e.rethrowAsParcelableException();
1119        }
1120    }
1121
1122    @Override
1123    public void setInterfaceIpv6NdOffload(String iface, boolean enable) {
1124        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1125        try {
1126            mConnector.execute(
1127                    "interface", "ipv6ndoffload", iface, (enable ? "enable" : "disable"));
1128        } catch (NativeDaemonConnectorException e) {
1129            throw e.rethrowAsParcelableException();
1130        }
1131    }
1132
1133    @Override
1134    public void addRoute(int netId, RouteInfo route) {
1135        modifyRoute("add", "" + netId, route);
1136    }
1137
1138    @Override
1139    public void removeRoute(int netId, RouteInfo route) {
1140        modifyRoute("remove", "" + netId, route);
1141    }
1142
1143    private void modifyRoute(String action, String netId, RouteInfo route) {
1144        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1145
1146        final Command cmd = new Command("network", "route", action, netId);
1147
1148        // create triplet: interface dest-ip-addr/prefixlength gateway-ip-addr
1149        cmd.appendArg(route.getInterface());
1150        cmd.appendArg(route.getDestination().toString());
1151
1152        switch (route.getType()) {
1153            case RouteInfo.RTN_UNICAST:
1154                if (route.hasGateway()) {
1155                    cmd.appendArg(route.getGateway().getHostAddress());
1156                }
1157                break;
1158            case RouteInfo.RTN_UNREACHABLE:
1159                cmd.appendArg("unreachable");
1160                break;
1161            case RouteInfo.RTN_THROW:
1162                cmd.appendArg("throw");
1163                break;
1164        }
1165
1166        try {
1167            mConnector.execute(cmd);
1168        } catch (NativeDaemonConnectorException e) {
1169            throw e.rethrowAsParcelableException();
1170        }
1171    }
1172
1173    private ArrayList<String> readRouteList(String filename) {
1174        FileInputStream fstream = null;
1175        ArrayList<String> list = new ArrayList<String>();
1176
1177        try {
1178            fstream = new FileInputStream(filename);
1179            DataInputStream in = new DataInputStream(fstream);
1180            BufferedReader br = new BufferedReader(new InputStreamReader(in));
1181            String s;
1182
1183            // throw away the title line
1184
1185            while (((s = br.readLine()) != null) && (s.length() != 0)) {
1186                list.add(s);
1187            }
1188        } catch (IOException ex) {
1189            // return current list, possibly empty
1190        } finally {
1191            if (fstream != null) {
1192                try {
1193                    fstream.close();
1194                } catch (IOException ex) {}
1195            }
1196        }
1197
1198        return list;
1199    }
1200
1201    @Override
1202    public void setMtu(String iface, int mtu) {
1203        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1204
1205        final NativeDaemonEvent event;
1206        try {
1207            event = mConnector.execute("interface", "setmtu", iface, mtu);
1208        } catch (NativeDaemonConnectorException e) {
1209            throw e.rethrowAsParcelableException();
1210        }
1211    }
1212
1213    @Override
1214    public void shutdown() {
1215        // TODO: remove from aidl if nobody calls externally
1216        mContext.enforceCallingOrSelfPermission(SHUTDOWN, TAG);
1217
1218        Slog.i(TAG, "Shutting down");
1219    }
1220
1221    @Override
1222    public boolean getIpForwardingEnabled() throws IllegalStateException{
1223        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1224
1225        final NativeDaemonEvent event;
1226        try {
1227            event = mConnector.execute("ipfwd", "status");
1228        } catch (NativeDaemonConnectorException e) {
1229            throw e.rethrowAsParcelableException();
1230        }
1231
1232        // 211 Forwarding enabled
1233        event.checkCode(IpFwdStatusResult);
1234        return event.getMessage().endsWith("enabled");
1235    }
1236
1237    @Override
1238    public void setIpForwardingEnabled(boolean enable) {
1239        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1240        try {
1241            mConnector.execute("ipfwd", enable ? "enable" : "disable", "tethering");
1242        } catch (NativeDaemonConnectorException e) {
1243            throw e.rethrowAsParcelableException();
1244        }
1245    }
1246
1247    @Override
1248    public void startTethering(String[] dhcpRange) {
1249        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1250        // cmd is "tether start first_start first_stop second_start second_stop ..."
1251        // an odd number of addrs will fail
1252
1253        final Command cmd = new Command("tether", "start");
1254        for (String d : dhcpRange) {
1255            cmd.appendArg(d);
1256        }
1257
1258        try {
1259            mConnector.execute(cmd);
1260        } catch (NativeDaemonConnectorException e) {
1261            throw e.rethrowAsParcelableException();
1262        }
1263    }
1264
1265    @Override
1266    public void stopTethering() {
1267        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1268        try {
1269            mConnector.execute("tether", "stop");
1270        } catch (NativeDaemonConnectorException e) {
1271            throw e.rethrowAsParcelableException();
1272        }
1273    }
1274
1275    @Override
1276    public boolean isTetheringStarted() {
1277        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1278
1279        final NativeDaemonEvent event;
1280        try {
1281            event = mConnector.execute("tether", "status");
1282        } catch (NativeDaemonConnectorException e) {
1283            throw e.rethrowAsParcelableException();
1284        }
1285
1286        // 210 Tethering services started
1287        event.checkCode(TetherStatusResult);
1288        return event.getMessage().endsWith("started");
1289    }
1290
1291    @Override
1292    public void tetherInterface(String iface) {
1293        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1294        try {
1295            mConnector.execute("tether", "interface", "add", iface);
1296        } catch (NativeDaemonConnectorException e) {
1297            throw e.rethrowAsParcelableException();
1298        }
1299        List<RouteInfo> routes = new ArrayList<RouteInfo>();
1300        // The RouteInfo constructor truncates the LinkAddress to a network prefix, thus making it
1301        // suitable to use as a route destination.
1302        routes.add(new RouteInfo(getInterfaceConfig(iface).getLinkAddress(), null, iface));
1303        addInterfaceToLocalNetwork(iface, routes);
1304    }
1305
1306    @Override
1307    public void untetherInterface(String iface) {
1308        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1309        try {
1310            mConnector.execute("tether", "interface", "remove", iface);
1311        } catch (NativeDaemonConnectorException e) {
1312            throw e.rethrowAsParcelableException();
1313        } finally {
1314            removeInterfaceFromLocalNetwork(iface);
1315        }
1316    }
1317
1318    @Override
1319    public String[] listTetheredInterfaces() {
1320        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1321        try {
1322            return NativeDaemonEvent.filterMessageList(
1323                    mConnector.executeForList("tether", "interface", "list"),
1324                    TetherInterfaceListResult);
1325        } catch (NativeDaemonConnectorException e) {
1326            throw e.rethrowAsParcelableException();
1327        }
1328    }
1329
1330    @Override
1331    public void setDnsForwarders(Network network, String[] dns) {
1332        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1333
1334        int netId = (network != null) ? network.netId : ConnectivityManager.NETID_UNSET;
1335        final Command cmd = new Command("tether", "dns", "set", netId);
1336
1337        for (String s : dns) {
1338            cmd.appendArg(NetworkUtils.numericToInetAddress(s).getHostAddress());
1339        }
1340
1341        try {
1342            mConnector.execute(cmd);
1343        } catch (NativeDaemonConnectorException e) {
1344            throw e.rethrowAsParcelableException();
1345        }
1346    }
1347
1348    @Override
1349    public String[] getDnsForwarders() {
1350        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1351        try {
1352            return NativeDaemonEvent.filterMessageList(
1353                    mConnector.executeForList("tether", "dns", "list"), TetherDnsFwdTgtListResult);
1354        } catch (NativeDaemonConnectorException e) {
1355            throw e.rethrowAsParcelableException();
1356        }
1357    }
1358
1359    private List<InterfaceAddress> excludeLinkLocal(List<InterfaceAddress> addresses) {
1360        ArrayList<InterfaceAddress> filtered = new ArrayList<InterfaceAddress>(addresses.size());
1361        for (InterfaceAddress ia : addresses) {
1362            if (!ia.getAddress().isLinkLocalAddress())
1363                filtered.add(ia);
1364        }
1365        return filtered;
1366    }
1367
1368    private void modifyInterfaceForward(boolean add, String fromIface, String toIface) {
1369        final Command cmd = new Command("ipfwd", add ? "add" : "remove", fromIface, toIface);
1370        try {
1371            mConnector.execute(cmd);
1372        } catch (NativeDaemonConnectorException e) {
1373            throw e.rethrowAsParcelableException();
1374        }
1375    }
1376
1377    @Override
1378    public void startInterfaceForwarding(String fromIface, String toIface) {
1379        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1380        modifyInterfaceForward(true, fromIface, toIface);
1381    }
1382
1383    @Override
1384    public void stopInterfaceForwarding(String fromIface, String toIface) {
1385        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1386        modifyInterfaceForward(false, fromIface, toIface);
1387    }
1388
1389    private void modifyNat(String action, String internalInterface, String externalInterface)
1390            throws SocketException {
1391        final Command cmd = new Command("nat", action, internalInterface, externalInterface);
1392
1393        final NetworkInterface internalNetworkInterface = NetworkInterface.getByName(
1394                internalInterface);
1395        if (internalNetworkInterface == null) {
1396            cmd.appendArg("0");
1397        } else {
1398            // Don't touch link-local routes, as link-local addresses aren't routable,
1399            // kernel creates link-local routes on all interfaces automatically
1400            List<InterfaceAddress> interfaceAddresses = excludeLinkLocal(
1401                    internalNetworkInterface.getInterfaceAddresses());
1402            cmd.appendArg(interfaceAddresses.size());
1403            for (InterfaceAddress ia : interfaceAddresses) {
1404                InetAddress addr = NetworkUtils.getNetworkPart(
1405                        ia.getAddress(), ia.getNetworkPrefixLength());
1406                cmd.appendArg(addr.getHostAddress() + "/" + ia.getNetworkPrefixLength());
1407            }
1408        }
1409
1410        try {
1411            mConnector.execute(cmd);
1412        } catch (NativeDaemonConnectorException e) {
1413            throw e.rethrowAsParcelableException();
1414        }
1415    }
1416
1417    @Override
1418    public void enableNat(String internalInterface, String externalInterface) {
1419        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1420        try {
1421            modifyNat("enable", internalInterface, externalInterface);
1422        } catch (SocketException e) {
1423            throw new IllegalStateException(e);
1424        }
1425    }
1426
1427    @Override
1428    public void disableNat(String internalInterface, String externalInterface) {
1429        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1430        try {
1431            modifyNat("disable", internalInterface, externalInterface);
1432        } catch (SocketException e) {
1433            throw new IllegalStateException(e);
1434        }
1435    }
1436
1437    @Override
1438    public String[] listTtys() {
1439        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1440        try {
1441            return NativeDaemonEvent.filterMessageList(
1442                    mConnector.executeForList("list_ttys"), TtyListResult);
1443        } catch (NativeDaemonConnectorException e) {
1444            throw e.rethrowAsParcelableException();
1445        }
1446    }
1447
1448    @Override
1449    public void attachPppd(
1450            String tty, String localAddr, String remoteAddr, String dns1Addr, String dns2Addr) {
1451        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1452        try {
1453            mConnector.execute("pppd", "attach", tty,
1454                    NetworkUtils.numericToInetAddress(localAddr).getHostAddress(),
1455                    NetworkUtils.numericToInetAddress(remoteAddr).getHostAddress(),
1456                    NetworkUtils.numericToInetAddress(dns1Addr).getHostAddress(),
1457                    NetworkUtils.numericToInetAddress(dns2Addr).getHostAddress());
1458        } catch (NativeDaemonConnectorException e) {
1459            throw e.rethrowAsParcelableException();
1460        }
1461    }
1462
1463    @Override
1464    public void detachPppd(String tty) {
1465        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1466        try {
1467            mConnector.execute("pppd", "detach", tty);
1468        } catch (NativeDaemonConnectorException e) {
1469            throw e.rethrowAsParcelableException();
1470        }
1471    }
1472
1473    /**
1474     * Private method used to call execute for a command given the provided arguments.
1475     *
1476     * This function checks the returned NativeDaemonEvent for the provided expected response code
1477     * and message.  If either of these is not correct, an error is logged.
1478     *
1479     * @param String command The command to execute.
1480     * @param Object[] args If needed, arguments for the command to execute.
1481     * @param int expectedResponseCode The code expected to be returned in the corresponding event.
1482     * @param String expectedResponseMessage The message expected in the returned event.
1483     * @param String logMsg The message to log as an error (TAG will be applied).
1484     */
1485    private void executeOrLogWithMessage(String command, Object[] args,
1486            int expectedResponseCode, String expectedResponseMessage, String logMsg)
1487            throws NativeDaemonConnectorException {
1488        NativeDaemonEvent event = mConnector.execute(command, args);
1489        if (event.getCode() != expectedResponseCode
1490                || !event.getMessage().equals(expectedResponseMessage)) {
1491            Log.e(TAG, logMsg + ": event = " + event);
1492        }
1493    }
1494
1495    @Override
1496    public void startAccessPoint(WifiConfiguration wifiConfig, String wlanIface) {
1497        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1498        Object[] args;
1499        String logMsg = "startAccessPoint Error setting up softap";
1500        try {
1501            if (wifiConfig == null) {
1502                args = new Object[] {"set", wlanIface};
1503            } else {
1504                args = new Object[] {"set", wlanIface, wifiConfig.SSID,
1505                        "broadcast", Integer.toString(wifiConfig.apChannel),
1506                        getSecurityType(wifiConfig), new SensitiveArg(wifiConfig.preSharedKey)};
1507            }
1508            executeOrLogWithMessage(SOFT_AP_COMMAND, args, NetdResponseCode.SoftapStatusResult,
1509                    SOFT_AP_COMMAND_SUCCESS, logMsg);
1510
1511            logMsg = "startAccessPoint Error starting softap";
1512            args = new Object[] {"startap"};
1513            executeOrLogWithMessage(SOFT_AP_COMMAND, args, NetdResponseCode.SoftapStatusResult,
1514                    SOFT_AP_COMMAND_SUCCESS, logMsg);
1515        } catch (NativeDaemonConnectorException e) {
1516            throw e.rethrowAsParcelableException();
1517        }
1518    }
1519
1520    private static String getSecurityType(WifiConfiguration wifiConfig) {
1521        switch (wifiConfig.getAuthType()) {
1522            case KeyMgmt.WPA_PSK:
1523                return "wpa-psk";
1524            case KeyMgmt.WPA2_PSK:
1525                return "wpa2-psk";
1526            default:
1527                return "open";
1528        }
1529    }
1530
1531    /* @param mode can be "AP", "STA" or "P2P" */
1532    @Override
1533    public void wifiFirmwareReload(String wlanIface, String mode) {
1534        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1535        Object[] args = {"fwreload", wlanIface, mode};
1536        String logMsg = "wifiFirmwareReload Error reloading "
1537                + wlanIface + " fw in " + mode + " mode";
1538        try {
1539            executeOrLogWithMessage(SOFT_AP_COMMAND, args, NetdResponseCode.SoftapStatusResult,
1540                    SOFT_AP_COMMAND_SUCCESS, logMsg);
1541        } catch (NativeDaemonConnectorException e) {
1542            throw e.rethrowAsParcelableException();
1543        }
1544
1545        // Ensure that before we return from this command, any asynchronous
1546        // notifications generated before the command completed have been
1547        // processed by all NetworkManagementEventObservers.
1548        mConnector.waitForCallbacks();
1549    }
1550
1551    @Override
1552    public void stopAccessPoint(String wlanIface) {
1553        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1554        Object[] args = {"stopap"};
1555        String logMsg = "stopAccessPoint Error stopping softap";
1556
1557        try {
1558            executeOrLogWithMessage(SOFT_AP_COMMAND, args, NetdResponseCode.SoftapStatusResult,
1559                    SOFT_AP_COMMAND_SUCCESS, logMsg);
1560            wifiFirmwareReload(wlanIface, "STA");
1561        } catch (NativeDaemonConnectorException e) {
1562            throw e.rethrowAsParcelableException();
1563        }
1564    }
1565
1566    @Override
1567    public void setAccessPoint(WifiConfiguration wifiConfig, String wlanIface) {
1568        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1569        Object[] args;
1570        String logMsg = "startAccessPoint Error setting up softap";
1571        try {
1572            if (wifiConfig == null) {
1573                args = new Object[] {"set", wlanIface};
1574            } else {
1575                // TODO: understand why this is set to "6" instead of
1576                // Integer.toString(wifiConfig.apChannel) as in startAccessPoint
1577                // TODO: should startAccessPoint call this instead of repeating code?
1578                args = new Object[] {"set", wlanIface, wifiConfig.SSID,
1579                        "broadcast", "6",
1580                        getSecurityType(wifiConfig), new SensitiveArg(wifiConfig.preSharedKey)};
1581            }
1582            executeOrLogWithMessage(SOFT_AP_COMMAND, args, NetdResponseCode.SoftapStatusResult,
1583                    SOFT_AP_COMMAND_SUCCESS, logMsg);
1584        } catch (NativeDaemonConnectorException e) {
1585            throw e.rethrowAsParcelableException();
1586        }
1587    }
1588
1589    @Override
1590    public void addIdleTimer(String iface, int timeout, final int type) {
1591        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1592
1593        if (DBG) Slog.d(TAG, "Adding idletimer");
1594
1595        synchronized (mIdleTimerLock) {
1596            IdleTimerParams params = mActiveIdleTimers.get(iface);
1597            if (params != null) {
1598                // the interface already has idletimer, update network count
1599                params.networkCount++;
1600                return;
1601            }
1602
1603            try {
1604                mConnector.execute("idletimer", "add", iface, Integer.toString(timeout),
1605                        Integer.toString(type));
1606            } catch (NativeDaemonConnectorException e) {
1607                throw e.rethrowAsParcelableException();
1608            }
1609            mActiveIdleTimers.put(iface, new IdleTimerParams(timeout, type));
1610
1611            // Networks start up.
1612            if (ConnectivityManager.isNetworkTypeMobile(type)) {
1613                mNetworkActive = false;
1614            }
1615            mDaemonHandler.post(new Runnable() {
1616                @Override public void run() {
1617                    notifyInterfaceClassActivity(type,
1618                            DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH,
1619                            SystemClock.elapsedRealtimeNanos(), -1, false);
1620                }
1621            });
1622        }
1623    }
1624
1625    @Override
1626    public void removeIdleTimer(String iface) {
1627        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1628
1629        if (DBG) Slog.d(TAG, "Removing idletimer");
1630
1631        synchronized (mIdleTimerLock) {
1632            final IdleTimerParams params = mActiveIdleTimers.get(iface);
1633            if (params == null || --(params.networkCount) > 0) {
1634                return;
1635            }
1636
1637            try {
1638                mConnector.execute("idletimer", "remove", iface,
1639                        Integer.toString(params.timeout), Integer.toString(params.type));
1640            } catch (NativeDaemonConnectorException e) {
1641                throw e.rethrowAsParcelableException();
1642            }
1643            mActiveIdleTimers.remove(iface);
1644            mDaemonHandler.post(new Runnable() {
1645                @Override public void run() {
1646                    notifyInterfaceClassActivity(params.type,
1647                            DataConnectionRealTimeInfo.DC_POWER_STATE_LOW,
1648                            SystemClock.elapsedRealtimeNanos(), -1, false);
1649                }
1650            });
1651        }
1652    }
1653
1654    @Override
1655    public NetworkStats getNetworkStatsSummaryDev() {
1656        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1657        try {
1658            return mStatsFactory.readNetworkStatsSummaryDev();
1659        } catch (IOException e) {
1660            throw new IllegalStateException(e);
1661        }
1662    }
1663
1664    @Override
1665    public NetworkStats getNetworkStatsSummaryXt() {
1666        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1667        try {
1668            return mStatsFactory.readNetworkStatsSummaryXt();
1669        } catch (IOException e) {
1670            throw new IllegalStateException(e);
1671        }
1672    }
1673
1674    @Override
1675    public NetworkStats getNetworkStatsDetail() {
1676        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1677        try {
1678            return mStatsFactory.readNetworkStatsDetail(UID_ALL, null, TAG_ALL, null);
1679        } catch (IOException e) {
1680            throw new IllegalStateException(e);
1681        }
1682    }
1683
1684    @Override
1685    public void setInterfaceQuota(String iface, long quotaBytes) {
1686        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1687
1688        // silently discard when control disabled
1689        // TODO: eventually migrate to be always enabled
1690        if (!mBandwidthControlEnabled) return;
1691
1692        synchronized (mQuotaLock) {
1693            if (mActiveQuotas.containsKey(iface)) {
1694                throw new IllegalStateException("iface " + iface + " already has quota");
1695            }
1696
1697            try {
1698                // TODO: support quota shared across interfaces
1699                mConnector.execute("bandwidth", "setiquota", iface, quotaBytes);
1700                mActiveQuotas.put(iface, quotaBytes);
1701            } catch (NativeDaemonConnectorException e) {
1702                throw e.rethrowAsParcelableException();
1703            }
1704        }
1705    }
1706
1707    @Override
1708    public void removeInterfaceQuota(String iface) {
1709        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1710
1711        // silently discard when control disabled
1712        // TODO: eventually migrate to be always enabled
1713        if (!mBandwidthControlEnabled) return;
1714
1715        synchronized (mQuotaLock) {
1716            if (!mActiveQuotas.containsKey(iface)) {
1717                // TODO: eventually consider throwing
1718                return;
1719            }
1720
1721            mActiveQuotas.remove(iface);
1722            mActiveAlerts.remove(iface);
1723
1724            try {
1725                // TODO: support quota shared across interfaces
1726                mConnector.execute("bandwidth", "removeiquota", iface);
1727            } catch (NativeDaemonConnectorException e) {
1728                throw e.rethrowAsParcelableException();
1729            }
1730        }
1731    }
1732
1733    @Override
1734    public void setInterfaceAlert(String iface, long alertBytes) {
1735        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1736
1737        // silently discard when control disabled
1738        // TODO: eventually migrate to be always enabled
1739        if (!mBandwidthControlEnabled) return;
1740
1741        // quick sanity check
1742        if (!mActiveQuotas.containsKey(iface)) {
1743            throw new IllegalStateException("setting alert requires existing quota on iface");
1744        }
1745
1746        synchronized (mQuotaLock) {
1747            if (mActiveAlerts.containsKey(iface)) {
1748                throw new IllegalStateException("iface " + iface + " already has alert");
1749            }
1750
1751            try {
1752                // TODO: support alert shared across interfaces
1753                mConnector.execute("bandwidth", "setinterfacealert", iface, alertBytes);
1754                mActiveAlerts.put(iface, alertBytes);
1755            } catch (NativeDaemonConnectorException e) {
1756                throw e.rethrowAsParcelableException();
1757            }
1758        }
1759    }
1760
1761    @Override
1762    public void removeInterfaceAlert(String iface) {
1763        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1764
1765        // silently discard when control disabled
1766        // TODO: eventually migrate to be always enabled
1767        if (!mBandwidthControlEnabled) return;
1768
1769        synchronized (mQuotaLock) {
1770            if (!mActiveAlerts.containsKey(iface)) {
1771                // TODO: eventually consider throwing
1772                return;
1773            }
1774
1775            try {
1776                // TODO: support alert shared across interfaces
1777                mConnector.execute("bandwidth", "removeinterfacealert", iface);
1778                mActiveAlerts.remove(iface);
1779            } catch (NativeDaemonConnectorException e) {
1780                throw e.rethrowAsParcelableException();
1781            }
1782        }
1783    }
1784
1785    @Override
1786    public void setGlobalAlert(long alertBytes) {
1787        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1788
1789        // silently discard when control disabled
1790        // TODO: eventually migrate to be always enabled
1791        if (!mBandwidthControlEnabled) return;
1792
1793        try {
1794            mConnector.execute("bandwidth", "setglobalalert", alertBytes);
1795        } catch (NativeDaemonConnectorException e) {
1796            throw e.rethrowAsParcelableException();
1797        }
1798    }
1799
1800    private void setUidOnMeteredNetworkList(SparseBooleanArray quotaList, int uid,
1801            boolean blacklist, boolean enable) {
1802        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1803
1804        // silently discard when control disabled
1805        // TODO: eventually migrate to be always enabled
1806        if (!mBandwidthControlEnabled) return;
1807
1808        final String chain = blacklist ? "naughtyapps" : "niceapps";
1809        final String suffix = enable ? "add" : "remove";
1810
1811        synchronized (mQuotaLock) {
1812            final boolean oldEnable = quotaList.get(uid, false);
1813            if (oldEnable == enable) {
1814                // TODO: eventually consider throwing
1815                return;
1816            }
1817
1818            try {
1819                mConnector.execute("bandwidth", suffix + chain, uid);
1820                if (enable) {
1821                    quotaList.put(uid, true);
1822                } else {
1823                    quotaList.delete(uid);
1824                }
1825            } catch (NativeDaemonConnectorException e) {
1826                throw e.rethrowAsParcelableException();
1827            }
1828        }
1829    }
1830
1831    @Override
1832    public void setUidMeteredNetworkBlacklist(int uid, boolean enable) {
1833        setUidOnMeteredNetworkList(mUidRejectOnMetered, uid, true, enable);
1834    }
1835
1836    @Override
1837    public void setUidMeteredNetworkWhitelist(int uid, boolean enable) {
1838        setUidOnMeteredNetworkList(mUidAllowOnMetered, uid, false, enable);
1839    }
1840
1841    @Override
1842    public boolean setDataSaverModeEnabled(boolean enable) {
1843        if (DBG) Log.d(TAG, "setDataSaverMode: " + enable);
1844        synchronized (mQuotaLock) {
1845            if (mDataSaverMode == enable) {
1846                Log.w(TAG, "setDataSaverMode(): already " + mDataSaverMode);
1847                return true;
1848            }
1849            try {
1850                final boolean changed = mNetdService.bandwidthEnableDataSaver(enable);
1851                if (changed) {
1852                    mDataSaverMode = enable;
1853                } else {
1854                    Log.w(TAG, "setDataSaverMode(" + enable + "): netd command silently failed");
1855                }
1856                return changed;
1857            } catch (RemoteException e) {
1858                Log.w(TAG, "setDataSaverMode(" + enable + "): netd command failed", e);
1859                return false;
1860            }
1861        }
1862    }
1863
1864    @Override
1865    public void setAllowOnlyVpnForUids(boolean add, UidRange[] uidRanges)
1866            throws ServiceSpecificException {
1867        try {
1868            mNetdService.networkRejectNonSecureVpn(add, uidRanges);
1869        } catch (ServiceSpecificException e) {
1870            Log.w(TAG, "setAllowOnlyVpnForUids(" + add + ", " + Arrays.toString(uidRanges) + ")"
1871                    + ": netd command failed", e);
1872            throw e;
1873        } catch (RemoteException e) {
1874            Log.w(TAG, "setAllowOnlyVpnForUids(" + add + ", " + Arrays.toString(uidRanges) + ")"
1875                    + ": netd command failed", e);
1876            throw e.rethrowAsRuntimeException();
1877        }
1878    }
1879
1880    @Override
1881    public void setUidCleartextNetworkPolicy(int uid, int policy) {
1882        if (Binder.getCallingUid() != uid) {
1883            mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1884        }
1885
1886        synchronized (mQuotaLock) {
1887            final int oldPolicy = mUidCleartextPolicy.get(uid, StrictMode.NETWORK_POLICY_ACCEPT);
1888            if (oldPolicy == policy) {
1889                return;
1890            }
1891
1892            if (!mStrictEnabled) {
1893                // Module isn't enabled yet; stash the requested policy away to
1894                // apply later once the daemon is connected.
1895                mUidCleartextPolicy.put(uid, policy);
1896                return;
1897            }
1898
1899            final String policyString;
1900            switch (policy) {
1901                case StrictMode.NETWORK_POLICY_ACCEPT:
1902                    policyString = "accept";
1903                    break;
1904                case StrictMode.NETWORK_POLICY_LOG:
1905                    policyString = "log";
1906                    break;
1907                case StrictMode.NETWORK_POLICY_REJECT:
1908                    policyString = "reject";
1909                    break;
1910                default:
1911                    throw new IllegalArgumentException("Unknown policy " + policy);
1912            }
1913
1914            try {
1915                mConnector.execute("strict", "set_uid_cleartext_policy", uid, policyString);
1916                mUidCleartextPolicy.put(uid, policy);
1917            } catch (NativeDaemonConnectorException e) {
1918                throw e.rethrowAsParcelableException();
1919            }
1920        }
1921    }
1922
1923    @Override
1924    public boolean isBandwidthControlEnabled() {
1925        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1926        return mBandwidthControlEnabled;
1927    }
1928
1929    @Override
1930    public NetworkStats getNetworkStatsUidDetail(int uid) {
1931        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1932        try {
1933            return mStatsFactory.readNetworkStatsDetail(uid, null, TAG_ALL, null);
1934        } catch (IOException e) {
1935            throw new IllegalStateException(e);
1936        }
1937    }
1938
1939    @Override
1940    public NetworkStats getNetworkStatsTethering() {
1941        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1942
1943        final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1);
1944        try {
1945            final NativeDaemonEvent[] events = mConnector.executeForList(
1946                    "bandwidth", "gettetherstats");
1947            for (NativeDaemonEvent event : events) {
1948                if (event.getCode() != TetheringStatsListResult) continue;
1949
1950                // 114 ifaceIn ifaceOut rx_bytes rx_packets tx_bytes tx_packets
1951                final StringTokenizer tok = new StringTokenizer(event.getMessage());
1952                try {
1953                    final String ifaceIn = tok.nextToken();
1954                    final String ifaceOut = tok.nextToken();
1955
1956                    final NetworkStats.Entry entry = new NetworkStats.Entry();
1957                    entry.iface = ifaceOut;
1958                    entry.uid = UID_TETHERING;
1959                    entry.set = SET_DEFAULT;
1960                    entry.tag = TAG_NONE;
1961                    entry.rxBytes = Long.parseLong(tok.nextToken());
1962                    entry.rxPackets = Long.parseLong(tok.nextToken());
1963                    entry.txBytes = Long.parseLong(tok.nextToken());
1964                    entry.txPackets = Long.parseLong(tok.nextToken());
1965                    stats.combineValues(entry);
1966                } catch (NoSuchElementException e) {
1967                    throw new IllegalStateException("problem parsing tethering stats: " + event);
1968                } catch (NumberFormatException e) {
1969                    throw new IllegalStateException("problem parsing tethering stats: " + event);
1970                }
1971            }
1972        } catch (NativeDaemonConnectorException e) {
1973            throw e.rethrowAsParcelableException();
1974        }
1975        return stats;
1976    }
1977
1978    @Override
1979    public void setDnsConfigurationForNetwork(int netId, String[] servers, String domains) {
1980        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1981
1982        ContentResolver resolver = mContext.getContentResolver();
1983
1984        int sampleValidity = Settings.Global.getInt(resolver,
1985                Settings.Global.DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS,
1986                DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS);
1987        if (sampleValidity < 0 || sampleValidity > 65535) {
1988            Slog.w(TAG, "Invalid sampleValidity=" + sampleValidity + ", using default=" +
1989                    DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS);
1990            sampleValidity = DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS;
1991        }
1992
1993        int successThreshold = Settings.Global.getInt(resolver,
1994                Settings.Global.DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT,
1995                DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT);
1996        if (successThreshold < 0 || successThreshold > 100) {
1997            Slog.w(TAG, "Invalid successThreshold=" + successThreshold + ", using default=" +
1998                    DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT);
1999            successThreshold = DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT;
2000        }
2001
2002        int minSamples = Settings.Global.getInt(resolver,
2003                Settings.Global.DNS_RESOLVER_MIN_SAMPLES, DNS_RESOLVER_DEFAULT_MIN_SAMPLES);
2004        int maxSamples = Settings.Global.getInt(resolver,
2005                Settings.Global.DNS_RESOLVER_MAX_SAMPLES, DNS_RESOLVER_DEFAULT_MAX_SAMPLES);
2006        if (minSamples < 0 || minSamples > maxSamples || maxSamples > 64) {
2007            Slog.w(TAG, "Invalid sample count (min, max)=(" + minSamples + ", " + maxSamples +
2008                    "), using default=(" + DNS_RESOLVER_DEFAULT_MIN_SAMPLES + ", " +
2009                    DNS_RESOLVER_DEFAULT_MAX_SAMPLES + ")");
2010            minSamples = DNS_RESOLVER_DEFAULT_MIN_SAMPLES;
2011            maxSamples = DNS_RESOLVER_DEFAULT_MAX_SAMPLES;
2012        }
2013
2014        final String[] domainStrs = domains == null ? new String[0] : domains.split(" ");
2015        final int[] params = { sampleValidity, successThreshold, minSamples, maxSamples };
2016        try {
2017            mNetdService.setResolverConfiguration(netId, servers, domainStrs, params);
2018        } catch (RemoteException e) {
2019            throw new RuntimeException(e);
2020        }
2021    }
2022
2023    @Override
2024    public void setDnsServersForNetwork(int netId, String[] servers, String domains) {
2025        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2026
2027        Command cmd;
2028        if (servers.length > 0) {
2029            cmd = new Command("resolver", "setnetdns", netId,
2030                    (domains == null ? "" : domains));
2031            for (String s : servers) {
2032                InetAddress a = NetworkUtils.numericToInetAddress(s);
2033                if (a.isAnyLocalAddress() == false) {
2034                    cmd.appendArg(a.getHostAddress());
2035                }
2036            }
2037        } else {
2038            cmd = new Command("resolver", "clearnetdns", netId);
2039        }
2040
2041        try {
2042            mConnector.execute(cmd);
2043        } catch (NativeDaemonConnectorException e) {
2044            throw e.rethrowAsParcelableException();
2045        }
2046    }
2047
2048    @Override
2049    public void addVpnUidRanges(int netId, UidRange[] ranges) {
2050        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2051        Object[] argv = new Object[3 + MAX_UID_RANGES_PER_COMMAND];
2052        argv[0] = "users";
2053        argv[1] = "add";
2054        argv[2] = netId;
2055        int argc = 3;
2056        // Avoid overly long commands by limiting number of UID ranges per command.
2057        for (int i = 0; i < ranges.length; i++) {
2058            argv[argc++] = ranges[i].toString();
2059            if (i == (ranges.length - 1) || argc == argv.length) {
2060                try {
2061                    mConnector.execute("network", Arrays.copyOf(argv, argc));
2062                } catch (NativeDaemonConnectorException e) {
2063                    throw e.rethrowAsParcelableException();
2064                }
2065                argc = 3;
2066            }
2067        }
2068    }
2069
2070    @Override
2071    public void removeVpnUidRanges(int netId, UidRange[] ranges) {
2072        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2073        Object[] argv = new Object[3 + MAX_UID_RANGES_PER_COMMAND];
2074        argv[0] = "users";
2075        argv[1] = "remove";
2076        argv[2] = netId;
2077        int argc = 3;
2078        // Avoid overly long commands by limiting number of UID ranges per command.
2079        for (int i = 0; i < ranges.length; i++) {
2080            argv[argc++] = ranges[i].toString();
2081            if (i == (ranges.length - 1) || argc == argv.length) {
2082                try {
2083                    mConnector.execute("network", Arrays.copyOf(argv, argc));
2084                } catch (NativeDaemonConnectorException e) {
2085                    throw e.rethrowAsParcelableException();
2086                }
2087                argc = 3;
2088            }
2089        }
2090    }
2091
2092    @Override
2093    public void setFirewallEnabled(boolean enabled) {
2094        enforceSystemUid();
2095        try {
2096            mConnector.execute("firewall", "enable", enabled ? "whitelist" : "blacklist");
2097            mFirewallEnabled = enabled;
2098        } catch (NativeDaemonConnectorException e) {
2099            throw e.rethrowAsParcelableException();
2100        }
2101    }
2102
2103    @Override
2104    public boolean isFirewallEnabled() {
2105        enforceSystemUid();
2106        return mFirewallEnabled;
2107    }
2108
2109    @Override
2110    public void setFirewallInterfaceRule(String iface, boolean allow) {
2111        enforceSystemUid();
2112        Preconditions.checkState(mFirewallEnabled);
2113        final String rule = allow ? "allow" : "deny";
2114        try {
2115            mConnector.execute("firewall", "set_interface_rule", iface, rule);
2116        } catch (NativeDaemonConnectorException e) {
2117            throw e.rethrowAsParcelableException();
2118        }
2119    }
2120
2121    @Override
2122    public void setFirewallEgressSourceRule(String addr, boolean allow) {
2123        enforceSystemUid();
2124        Preconditions.checkState(mFirewallEnabled);
2125        final String rule = allow ? "allow" : "deny";
2126        try {
2127            mConnector.execute("firewall", "set_egress_source_rule", addr, rule);
2128        } catch (NativeDaemonConnectorException e) {
2129            throw e.rethrowAsParcelableException();
2130        }
2131    }
2132
2133    @Override
2134    public void setFirewallEgressDestRule(String addr, int port, boolean allow) {
2135        enforceSystemUid();
2136        Preconditions.checkState(mFirewallEnabled);
2137        final String rule = allow ? "allow" : "deny";
2138        try {
2139            mConnector.execute("firewall", "set_egress_dest_rule", addr, port, rule);
2140        } catch (NativeDaemonConnectorException e) {
2141            throw e.rethrowAsParcelableException();
2142        }
2143    }
2144
2145    private void closeSocketsForFirewallChainLocked(int chain, String chainName) {
2146        // UID ranges to close sockets on.
2147        UidRange[] ranges;
2148        // UID ranges whose sockets we won't touch.
2149        int[] exemptUids;
2150
2151        final SparseIntArray rules = getUidFirewallRules(chain);
2152        int numUids = 0;
2153
2154        if (getFirewallType(chain) == FIREWALL_TYPE_WHITELIST) {
2155            // Close all sockets on all non-system UIDs...
2156            ranges = new UidRange[] {
2157                // TODO: is there a better way of finding all existing users? If so, we could
2158                // specify their ranges here.
2159                new UidRange(Process.FIRST_APPLICATION_UID, Integer.MAX_VALUE),
2160            };
2161            // ... except for the UIDs that have allow rules.
2162            exemptUids = new int[rules.size()];
2163            for (int i = 0; i < exemptUids.length; i++) {
2164                if (rules.valueAt(i) == NetworkPolicyManager.FIREWALL_RULE_ALLOW) {
2165                    exemptUids[numUids] = rules.keyAt(i);
2166                    numUids++;
2167                }
2168            }
2169            // Normally, whitelist chains only contain deny rules, so numUids == exemptUids.length.
2170            // But the code does not guarantee this in any way, and at least in one case - if we add
2171            // a UID rule to the firewall, and then disable the firewall - the chains can contain
2172            // the wrong type of rule. In this case, don't close connections that we shouldn't.
2173            //
2174            // TODO: tighten up this code by ensuring we never set the wrong type of rule, and
2175            // fix setFirewallEnabled to grab mQuotaLock and clear rules.
2176            if (numUids != exemptUids.length) {
2177                exemptUids = Arrays.copyOf(exemptUids, numUids);
2178            }
2179        } else {
2180            // Close sockets for every UID that has a deny rule...
2181            ranges = new UidRange[rules.size()];
2182            for (int i = 0; i < ranges.length; i++) {
2183                if (rules.valueAt(i) == NetworkPolicyManager.FIREWALL_RULE_DENY) {
2184                    int uid = rules.keyAt(i);
2185                    ranges[numUids] = new UidRange(uid, uid);
2186                    numUids++;
2187                }
2188            }
2189            // As above; usually numUids == ranges.length, but not always.
2190            if (numUids != ranges.length) {
2191                ranges = Arrays.copyOf(ranges, numUids);
2192            }
2193            // ... with no exceptions.
2194            exemptUids = new int[0];
2195        }
2196
2197        try {
2198            mNetdService.socketDestroy(ranges, exemptUids);
2199        } catch(RemoteException | ServiceSpecificException e) {
2200            Slog.e(TAG, "Error closing sockets after enabling chain " + chainName + ": " + e);
2201        }
2202    }
2203
2204    @Override
2205    public void setFirewallChainEnabled(int chain, boolean enable) {
2206        enforceSystemUid();
2207        synchronized (mQuotaLock) {
2208            if (mFirewallChainStates.get(chain) == enable) {
2209                // All is the same, nothing to do.  This relies on the fact that netd has child
2210                // chains default detached.
2211                return;
2212            }
2213            mFirewallChainStates.put(chain, enable);
2214
2215            final String operation = enable ? "enable_chain" : "disable_chain";
2216            final String chainName;
2217            switch(chain) {
2218                case FIREWALL_CHAIN_STANDBY:
2219                    chainName = FIREWALL_CHAIN_NAME_STANDBY;
2220                    break;
2221                case FIREWALL_CHAIN_DOZABLE:
2222                    chainName = FIREWALL_CHAIN_NAME_DOZABLE;
2223                    break;
2224                case FIREWALL_CHAIN_POWERSAVE:
2225                    chainName = FIREWALL_CHAIN_NAME_POWERSAVE;
2226                    break;
2227                default:
2228                    throw new IllegalArgumentException("Bad child chain: " + chain);
2229            }
2230
2231            try {
2232                mConnector.execute("firewall", operation, chainName);
2233            } catch (NativeDaemonConnectorException e) {
2234                throw e.rethrowAsParcelableException();
2235            }
2236
2237            // Close any sockets that were opened by the affected UIDs. This has to be done after
2238            // disabling network connectivity, in case they react to the socket close by reopening
2239            // the connection and race with the iptables commands that enable the firewall. All
2240            // whitelist and blacklist chains allow RSTs through.
2241            if (enable) {
2242                if (DBG) Slog.d(TAG, "Closing sockets after enabling chain " + chainName);
2243                closeSocketsForFirewallChainLocked(chain, chainName);
2244            }
2245        }
2246    }
2247
2248    private int getFirewallType(int chain) {
2249        switch (chain) {
2250            case FIREWALL_CHAIN_STANDBY:
2251                return FIREWALL_TYPE_BLACKLIST;
2252            case FIREWALL_CHAIN_DOZABLE:
2253                return FIREWALL_TYPE_WHITELIST;
2254            case FIREWALL_CHAIN_POWERSAVE:
2255                return FIREWALL_TYPE_WHITELIST;
2256            default:
2257                return isFirewallEnabled() ? FIREWALL_TYPE_WHITELIST : FIREWALL_TYPE_BLACKLIST;
2258        }
2259    }
2260
2261    @Override
2262    public void setFirewallUidRules(int chain, int[] uids, int[] rules) {
2263        enforceSystemUid();
2264        synchronized (mQuotaLock) {
2265            SparseIntArray uidFirewallRules = getUidFirewallRules(chain);
2266            SparseIntArray newRules = new SparseIntArray();
2267            // apply new set of rules
2268            for (int index = uids.length - 1; index >= 0; --index) {
2269                int uid = uids[index];
2270                int rule = rules[index];
2271                updateFirewallUidRuleLocked(chain, uid, rule);
2272                newRules.put(uid, rule);
2273            }
2274            // collect the rules to remove.
2275            SparseIntArray rulesToRemove = new SparseIntArray();
2276            for (int index = uidFirewallRules.size() - 1; index >= 0; --index) {
2277                int uid = uidFirewallRules.keyAt(index);
2278                if (newRules.indexOfKey(uid) < 0) {
2279                    rulesToRemove.put(uid, FIREWALL_RULE_DEFAULT);
2280                }
2281            }
2282            // remove dead rules
2283            for (int index = rulesToRemove.size() - 1; index >= 0; --index) {
2284                int uid = rulesToRemove.keyAt(index);
2285                updateFirewallUidRuleLocked(chain, uid, FIREWALL_RULE_DEFAULT);
2286            }
2287            try {
2288                switch (chain) {
2289                    case FIREWALL_CHAIN_DOZABLE:
2290                        mNetdService.firewallReplaceUidChain("fw_dozable", true, uids);
2291                        break;
2292                    case FIREWALL_CHAIN_STANDBY:
2293                        mNetdService.firewallReplaceUidChain("fw_standby", false, uids);
2294                        break;
2295                    case FIREWALL_CHAIN_POWERSAVE:
2296                        mNetdService.firewallReplaceUidChain("fw_powersave", true, uids);
2297                        break;
2298                    case FIREWALL_CHAIN_NONE:
2299                    default:
2300                        Slog.d(TAG, "setFirewallUidRules() called on invalid chain: " + chain);
2301                }
2302            } catch (RemoteException e) {
2303                Slog.w(TAG, "Error flushing firewall chain " + chain, e);
2304            }
2305        }
2306    }
2307
2308    @Override
2309    public void setFirewallUidRule(int chain, int uid, int rule) {
2310        enforceSystemUid();
2311        synchronized (mQuotaLock) {
2312            setFirewallUidRuleLocked(chain, uid, rule);
2313        }
2314    }
2315
2316    private void setFirewallUidRuleLocked(int chain, int uid, int rule) {
2317        if (updateFirewallUidRuleLocked(chain, uid, rule)) {
2318            try {
2319                mConnector.execute("firewall", "set_uid_rule", getFirewallChainName(chain), uid,
2320                        getFirewallRuleName(chain, rule));
2321            } catch (NativeDaemonConnectorException e) {
2322                throw e.rethrowAsParcelableException();
2323            }
2324        }
2325    }
2326
2327    // TODO: now that netd supports batching, NMS should not keep these data structures anymore...
2328    private boolean updateFirewallUidRuleLocked(int chain, int uid, int rule) {
2329        SparseIntArray uidFirewallRules = getUidFirewallRules(chain);
2330
2331        final int oldUidFirewallRule = uidFirewallRules.get(uid, FIREWALL_RULE_DEFAULT);
2332        if (DBG) {
2333            Slog.d(TAG, "oldRule = " + oldUidFirewallRule
2334                    + ", newRule=" + rule + " for uid=" + uid + " on chain " + chain);
2335        }
2336        if (oldUidFirewallRule == rule) {
2337            if (DBG) Slog.d(TAG, "!!!!! Skipping change");
2338            // TODO: eventually consider throwing
2339            return false;
2340        }
2341
2342        String ruleName = getFirewallRuleName(chain, rule);
2343        String oldRuleName = getFirewallRuleName(chain, oldUidFirewallRule);
2344
2345        if (rule == NetworkPolicyManager.FIREWALL_RULE_DEFAULT) {
2346            uidFirewallRules.delete(uid);
2347        } else {
2348            uidFirewallRules.put(uid, rule);
2349        }
2350        return !ruleName.equals(oldRuleName);
2351    }
2352
2353    private @NonNull String getFirewallRuleName(int chain, int rule) {
2354        String ruleName;
2355        if (getFirewallType(chain) == FIREWALL_TYPE_WHITELIST) {
2356            if (rule == NetworkPolicyManager.FIREWALL_RULE_ALLOW) {
2357                ruleName = "allow";
2358            } else {
2359                ruleName = "deny";
2360            }
2361        } else { // Blacklist mode
2362            if (rule == NetworkPolicyManager.FIREWALL_RULE_DENY) {
2363                ruleName = "deny";
2364            } else {
2365                ruleName = "allow";
2366            }
2367        }
2368        return ruleName;
2369    }
2370
2371    private @NonNull SparseIntArray getUidFirewallRules(int chain) {
2372        switch (chain) {
2373            case FIREWALL_CHAIN_STANDBY:
2374                return mUidFirewallStandbyRules;
2375            case FIREWALL_CHAIN_DOZABLE:
2376                return mUidFirewallDozableRules;
2377            case FIREWALL_CHAIN_POWERSAVE:
2378                return mUidFirewallPowerSaveRules;
2379            case FIREWALL_CHAIN_NONE:
2380                return mUidFirewallRules;
2381            default:
2382                throw new IllegalArgumentException("Unknown chain:" + chain);
2383        }
2384    }
2385
2386    public @NonNull String getFirewallChainName(int chain) {
2387        switch (chain) {
2388            case FIREWALL_CHAIN_STANDBY:
2389                return FIREWALL_CHAIN_NAME_STANDBY;
2390            case FIREWALL_CHAIN_DOZABLE:
2391                return FIREWALL_CHAIN_NAME_DOZABLE;
2392            case FIREWALL_CHAIN_POWERSAVE:
2393                return FIREWALL_CHAIN_NAME_POWERSAVE;
2394            case FIREWALL_CHAIN_NONE:
2395                return FIREWALL_CHAIN_NAME_NONE;
2396            default:
2397                throw new IllegalArgumentException("Unknown chain:" + chain);
2398        }
2399    }
2400
2401    private static void enforceSystemUid() {
2402        final int uid = Binder.getCallingUid();
2403        if (uid != Process.SYSTEM_UID) {
2404            throw new SecurityException("Only available to AID_SYSTEM");
2405        }
2406    }
2407
2408    @Override
2409    public void startClatd(String interfaceName) throws IllegalStateException {
2410        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2411
2412        try {
2413            mConnector.execute("clatd", "start", interfaceName);
2414        } catch (NativeDaemonConnectorException e) {
2415            throw e.rethrowAsParcelableException();
2416        }
2417    }
2418
2419    @Override
2420    public void stopClatd(String interfaceName) throws IllegalStateException {
2421        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2422
2423        try {
2424            mConnector.execute("clatd", "stop", interfaceName);
2425        } catch (NativeDaemonConnectorException e) {
2426            throw e.rethrowAsParcelableException();
2427        }
2428    }
2429
2430    @Override
2431    public boolean isClatdStarted(String interfaceName) {
2432        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2433
2434        final NativeDaemonEvent event;
2435        try {
2436            event = mConnector.execute("clatd", "status", interfaceName);
2437        } catch (NativeDaemonConnectorException e) {
2438            throw e.rethrowAsParcelableException();
2439        }
2440
2441        event.checkCode(ClatdStatusResult);
2442        return event.getMessage().endsWith("started");
2443    }
2444
2445    @Override
2446    public void registerNetworkActivityListener(INetworkActivityListener listener) {
2447        mNetworkActivityListeners.register(listener);
2448    }
2449
2450    @Override
2451    public void unregisterNetworkActivityListener(INetworkActivityListener listener) {
2452        mNetworkActivityListeners.unregister(listener);
2453    }
2454
2455    @Override
2456    public boolean isNetworkActive() {
2457        synchronized (mNetworkActivityListeners) {
2458            return mNetworkActive || mActiveIdleTimers.isEmpty();
2459        }
2460    }
2461
2462    private void reportNetworkActive() {
2463        final int length = mNetworkActivityListeners.beginBroadcast();
2464        try {
2465            for (int i = 0; i < length; i++) {
2466                try {
2467                    mNetworkActivityListeners.getBroadcastItem(i).onNetworkActive();
2468                } catch (RemoteException | RuntimeException e) {
2469                }
2470            }
2471        } finally {
2472            mNetworkActivityListeners.finishBroadcast();
2473        }
2474    }
2475
2476    /** {@inheritDoc} */
2477    @Override
2478    public void monitor() {
2479        if (mConnector != null) {
2480            mConnector.monitor();
2481        }
2482    }
2483
2484    @Override
2485    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2486        mContext.enforceCallingOrSelfPermission(DUMP, TAG);
2487
2488        pw.println("NetworkManagementService NativeDaemonConnector Log:");
2489        mConnector.dump(fd, pw, args);
2490        pw.println();
2491
2492        pw.print("Bandwidth control enabled: "); pw.println(mBandwidthControlEnabled);
2493        pw.print("mMobileActivityFromRadio="); pw.print(mMobileActivityFromRadio);
2494                pw.print(" mLastPowerStateFromRadio="); pw.println(mLastPowerStateFromRadio);
2495        pw.print("mNetworkActive="); pw.println(mNetworkActive);
2496
2497        synchronized (mQuotaLock) {
2498            pw.print("Active quota ifaces: "); pw.println(mActiveQuotas.toString());
2499            pw.print("Active alert ifaces: "); pw.println(mActiveAlerts.toString());
2500            pw.print("Data saver mode: "); pw.println(mDataSaverMode);
2501            dumpUidRuleOnQuotaLocked(pw, "blacklist", mUidRejectOnMetered);
2502            dumpUidRuleOnQuotaLocked(pw, "whitelist", mUidAllowOnMetered);
2503        }
2504
2505        synchronized (mUidFirewallRules) {
2506            dumpUidFirewallRule(pw, "", mUidFirewallRules);
2507        }
2508
2509        pw.print("UID firewall standby chain enabled: "); pw.println(
2510                mFirewallChainStates.get(FIREWALL_CHAIN_STANDBY));
2511        synchronized (mUidFirewallStandbyRules) {
2512            dumpUidFirewallRule(pw, FIREWALL_CHAIN_NAME_STANDBY, mUidFirewallStandbyRules);
2513        }
2514
2515        pw.print("UID firewall dozable chain enabled: "); pw.println(
2516                mFirewallChainStates.get(FIREWALL_CHAIN_DOZABLE));
2517        synchronized (mUidFirewallDozableRules) {
2518            dumpUidFirewallRule(pw, FIREWALL_CHAIN_NAME_DOZABLE, mUidFirewallDozableRules);
2519        }
2520
2521        pw.println("UID firewall powersave chain enabled: " +
2522                mFirewallChainStates.get(FIREWALL_CHAIN_POWERSAVE));
2523        synchronized (mUidFirewallPowerSaveRules) {
2524            dumpUidFirewallRule(pw, FIREWALL_CHAIN_NAME_POWERSAVE, mUidFirewallPowerSaveRules);
2525        }
2526
2527        synchronized (mIdleTimerLock) {
2528            pw.println("Idle timers:");
2529            for (HashMap.Entry<String, IdleTimerParams> ent : mActiveIdleTimers.entrySet()) {
2530                pw.print("  "); pw.print(ent.getKey()); pw.println(":");
2531                IdleTimerParams params = ent.getValue();
2532                pw.print("    timeout="); pw.print(params.timeout);
2533                pw.print(" type="); pw.print(params.type);
2534                pw.print(" networkCount="); pw.println(params.networkCount);
2535            }
2536        }
2537
2538        pw.print("Firewall enabled: "); pw.println(mFirewallEnabled);
2539        pw.print("Netd service status: " );
2540        if (mNetdService == null) {
2541            pw.println("disconnected");
2542        } else {
2543            try {
2544                final boolean alive = mNetdService.isAlive();
2545                pw.println(alive ? "alive": "dead");
2546            } catch (RemoteException e) {
2547                pw.println("unreachable");
2548            }
2549        }
2550    }
2551
2552    private void dumpUidRuleOnQuotaLocked(PrintWriter pw, String name, SparseBooleanArray list) {
2553        pw.print("UID bandwith control ");
2554        pw.print(name);
2555        pw.print(" rule: [");
2556        final int size = list.size();
2557        for (int i = 0; i < size; i++) {
2558            pw.print(list.keyAt(i));
2559            if (i < size - 1) pw.print(",");
2560        }
2561        pw.println("]");
2562    }
2563
2564    private void dumpUidFirewallRule(PrintWriter pw, String name, SparseIntArray rules) {
2565        pw.print("UID firewall ");
2566        pw.print(name);
2567        pw.print(" rule: [");
2568        final int size = rules.size();
2569        for (int i = 0; i < size; i++) {
2570            pw.print(rules.keyAt(i));
2571            pw.print(":");
2572            pw.print(rules.valueAt(i));
2573            if (i < size - 1) pw.print(",");
2574        }
2575        pw.println("]");
2576    }
2577
2578    @Override
2579    public void createPhysicalNetwork(int netId, String permission) {
2580        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2581
2582        try {
2583            if (permission != null) {
2584                mConnector.execute("network", "create", netId, permission);
2585            } else {
2586                mConnector.execute("network", "create", netId);
2587            }
2588        } catch (NativeDaemonConnectorException e) {
2589            throw e.rethrowAsParcelableException();
2590        }
2591    }
2592
2593    @Override
2594    public void createVirtualNetwork(int netId, boolean hasDNS, boolean secure) {
2595        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2596
2597        try {
2598            mConnector.execute("network", "create", netId, "vpn", hasDNS ? "1" : "0",
2599                    secure ? "1" : "0");
2600        } catch (NativeDaemonConnectorException e) {
2601            throw e.rethrowAsParcelableException();
2602        }
2603    }
2604
2605    @Override
2606    public void removeNetwork(int netId) {
2607        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2608
2609        try {
2610            mConnector.execute("network", "destroy", netId);
2611        } catch (NativeDaemonConnectorException e) {
2612            throw e.rethrowAsParcelableException();
2613        }
2614    }
2615
2616    @Override
2617    public void addInterfaceToNetwork(String iface, int netId) {
2618        modifyInterfaceInNetwork("add", "" + netId, iface);
2619    }
2620
2621    @Override
2622    public void removeInterfaceFromNetwork(String iface, int netId) {
2623        modifyInterfaceInNetwork("remove", "" + netId, iface);
2624    }
2625
2626    private void modifyInterfaceInNetwork(String action, String netId, String iface) {
2627        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2628        try {
2629            mConnector.execute("network", "interface", action, netId, iface);
2630        } catch (NativeDaemonConnectorException e) {
2631            throw e.rethrowAsParcelableException();
2632        }
2633    }
2634
2635    @Override
2636    public void addLegacyRouteForNetId(int netId, RouteInfo routeInfo, int uid) {
2637        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2638
2639        final Command cmd = new Command("network", "route", "legacy", uid, "add", netId);
2640
2641        // create triplet: interface dest-ip-addr/prefixlength gateway-ip-addr
2642        final LinkAddress la = routeInfo.getDestinationLinkAddress();
2643        cmd.appendArg(routeInfo.getInterface());
2644        cmd.appendArg(la.getAddress().getHostAddress() + "/" + la.getPrefixLength());
2645        if (routeInfo.hasGateway()) {
2646            cmd.appendArg(routeInfo.getGateway().getHostAddress());
2647        }
2648
2649        try {
2650            mConnector.execute(cmd);
2651        } catch (NativeDaemonConnectorException e) {
2652            throw e.rethrowAsParcelableException();
2653        }
2654    }
2655
2656    @Override
2657    public void setDefaultNetId(int netId) {
2658        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2659
2660        try {
2661            mConnector.execute("network", "default", "set", netId);
2662        } catch (NativeDaemonConnectorException e) {
2663            throw e.rethrowAsParcelableException();
2664        }
2665    }
2666
2667    @Override
2668    public void clearDefaultNetId() {
2669        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2670
2671        try {
2672            mConnector.execute("network", "default", "clear");
2673        } catch (NativeDaemonConnectorException e) {
2674            throw e.rethrowAsParcelableException();
2675        }
2676    }
2677
2678    @Override
2679    public void setNetworkPermission(int netId, String permission) {
2680        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2681
2682        try {
2683            if (permission != null) {
2684                mConnector.execute("network", "permission", "network", "set", permission, netId);
2685            } else {
2686                mConnector.execute("network", "permission", "network", "clear", netId);
2687            }
2688        } catch (NativeDaemonConnectorException e) {
2689            throw e.rethrowAsParcelableException();
2690        }
2691    }
2692
2693
2694    @Override
2695    public void setPermission(String permission, int[] uids) {
2696        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2697
2698        Object[] argv = new Object[4 + MAX_UID_RANGES_PER_COMMAND];
2699        argv[0] = "permission";
2700        argv[1] = "user";
2701        argv[2] = "set";
2702        argv[3] = permission;
2703        int argc = 4;
2704        // Avoid overly long commands by limiting number of UIDs per command.
2705        for (int i = 0; i < uids.length; ++i) {
2706            argv[argc++] = uids[i];
2707            if (i == uids.length - 1 || argc == argv.length) {
2708                try {
2709                    mConnector.execute("network", Arrays.copyOf(argv, argc));
2710                } catch (NativeDaemonConnectorException e) {
2711                    throw e.rethrowAsParcelableException();
2712                }
2713                argc = 4;
2714            }
2715        }
2716    }
2717
2718    @Override
2719    public void clearPermission(int[] uids) {
2720        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2721
2722        Object[] argv = new Object[3 + MAX_UID_RANGES_PER_COMMAND];
2723        argv[0] = "permission";
2724        argv[1] = "user";
2725        argv[2] = "clear";
2726        int argc = 3;
2727        // Avoid overly long commands by limiting number of UIDs per command.
2728        for (int i = 0; i < uids.length; ++i) {
2729            argv[argc++] = uids[i];
2730            if (i == uids.length - 1 || argc == argv.length) {
2731                try {
2732                    mConnector.execute("network", Arrays.copyOf(argv, argc));
2733                } catch (NativeDaemonConnectorException e) {
2734                    throw e.rethrowAsParcelableException();
2735                }
2736                argc = 3;
2737            }
2738        }
2739    }
2740
2741    @Override
2742    public void allowProtect(int uid) {
2743        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2744
2745        try {
2746            mConnector.execute("network", "protect", "allow", uid);
2747        } catch (NativeDaemonConnectorException e) {
2748            throw e.rethrowAsParcelableException();
2749        }
2750    }
2751
2752    @Override
2753    public void denyProtect(int uid) {
2754        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2755
2756        try {
2757            mConnector.execute("network", "protect", "deny", uid);
2758        } catch (NativeDaemonConnectorException e) {
2759            throw e.rethrowAsParcelableException();
2760        }
2761    }
2762
2763    @Override
2764    public void addInterfaceToLocalNetwork(String iface, List<RouteInfo> routes) {
2765        modifyInterfaceInNetwork("add", "local", iface);
2766
2767        for (RouteInfo route : routes) {
2768            if (!route.isDefaultRoute()) {
2769                modifyRoute("add", "local", route);
2770            }
2771        }
2772    }
2773
2774    @Override
2775    public void removeInterfaceFromLocalNetwork(String iface) {
2776        modifyInterfaceInNetwork("remove", "local", iface);
2777    }
2778
2779    @Override
2780    public int removeRoutesFromLocalNetwork(List<RouteInfo> routes) {
2781        int failures = 0;
2782
2783        for (RouteInfo route : routes) {
2784            try {
2785                modifyRoute("remove", "local", route);
2786            } catch (IllegalStateException e) {
2787                failures++;
2788            }
2789        }
2790
2791        return failures;
2792    }
2793}
2794