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