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