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