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