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