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_SUB_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 addRoute(int netId, RouteInfo route) {
    944         modifyRoute("add", "" + netId, route);
    945     }
    946 
    947     @Override
    948     public void removeRoute(int netId, RouteInfo route) {
    949         modifyRoute("remove", "" + netId, route);
    950     }
    951 
    952     private void modifyRoute(String action, String netId, RouteInfo route) {
    953         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
    954 
    955         final Command cmd = new Command("network", "route", action, netId);
    956 
    957         // create triplet: interface dest-ip-addr/prefixlength gateway-ip-addr
    958         cmd.appendArg(route.getInterface());
    959         cmd.appendArg(route.getDestination().toString());
    960 
    961         switch (route.getType()) {
    962             case RouteInfo.RTN_UNICAST:
    963                 if (route.hasGateway()) {
    964                     cmd.appendArg(route.getGateway().getHostAddress());
    965                 }
    966                 break;
    967             case RouteInfo.RTN_UNREACHABLE:
    968                 cmd.appendArg("unreachable");
    969                 break;
    970             case RouteInfo.RTN_THROW:
    971                 cmd.appendArg("throw");
    972                 break;
    973         }
    974 
    975         try {
    976             mConnector.execute(cmd);
    977         } catch (NativeDaemonConnectorException e) {
    978             throw e.rethrowAsParcelableException();
    979         }
    980     }
    981 
    982     private ArrayList<String> readRouteList(String filename) {
    983         FileInputStream fstream = null;
    984         ArrayList<String> list = new ArrayList<String>();
    985 
    986         try {
    987             fstream = new FileInputStream(filename);
    988             DataInputStream in = new DataInputStream(fstream);
    989             BufferedReader br = new BufferedReader(new InputStreamReader(in));
    990             String s;
    991 
    992             // throw away the title line
    993 
    994             while (((s = br.readLine()) != null) && (s.length() != 0)) {
    995                 list.add(s);
    996             }
    997         } catch (IOException ex) {
    998             // return current list, possibly empty
    999         } finally {
   1000             if (fstream != null) {
   1001                 try {
   1002                     fstream.close();
   1003                 } catch (IOException ex) {}
   1004             }
   1005         }
   1006 
   1007         return list;
   1008     }
   1009 
   1010     @Override
   1011     public RouteInfo[] getRoutes(String interfaceName) {
   1012         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
   1013         ArrayList<RouteInfo> routes = new ArrayList<RouteInfo>();
   1014 
   1015         // v4 routes listed as:
   1016         // iface dest-addr gateway-addr flags refcnt use metric netmask mtu window IRTT
   1017         for (String s : readRouteList("/proc/net/route")) {
   1018             String[] fields = s.split("\t");
   1019 
   1020             if (fields.length > 7) {
   1021                 String iface = fields[0];
   1022 
   1023                 if (interfaceName.equals(iface)) {
   1024                     String dest = fields[1];
   1025                     String gate = fields[2];
   1026                     String flags = fields[3]; // future use?
   1027                     String mask = fields[7];
   1028                     try {
   1029                         // address stored as a hex string, ex: 0014A8C0
   1030                         InetAddress destAddr =
   1031                                 NetworkUtils.intToInetAddress((int)Long.parseLong(dest, 16));
   1032                         int prefixLength =
   1033                                 NetworkUtils.netmaskIntToPrefixLength(
   1034                                 (int)Long.parseLong(mask, 16));
   1035                         LinkAddress linkAddress = new LinkAddress(destAddr, prefixLength);
   1036 
   1037                         // address stored as a hex string, ex 0014A8C0
   1038                         InetAddress gatewayAddr =
   1039                                 NetworkUtils.intToInetAddress((int)Long.parseLong(gate, 16));
   1040 
   1041                         RouteInfo route = new RouteInfo(linkAddress, gatewayAddr);
   1042                         routes.add(route);
   1043                     } catch (Exception e) {
   1044                         Log.e(TAG, "Error parsing route " + s + " : " + e);
   1045                         continue;
   1046                     }
   1047                 }
   1048             }
   1049         }
   1050 
   1051         // v6 routes listed as:
   1052         // dest-addr prefixlength ?? ?? gateway-addr ?? ?? ?? ?? iface
   1053         for (String s : readRouteList("/proc/net/ipv6_route")) {
   1054             String[]fields = s.split("\\s+");
   1055             if (fields.length > 9) {
   1056                 String iface = fields[9].trim();
   1057                 if (interfaceName.equals(iface)) {
   1058                     String dest = fields[0];
   1059                     String prefix = fields[1];
   1060                     String gate = fields[4];
   1061 
   1062                     try {
   1063                         // prefix length stored as a hex string, ex 40
   1064                         int prefixLength = Integer.parseInt(prefix, 16);
   1065 
   1066                         // address stored as a 32 char hex string
   1067                         // ex fe800000000000000000000000000000
   1068                         InetAddress destAddr = NetworkUtils.hexToInet6Address(dest);
   1069                         LinkAddress linkAddress = new LinkAddress(destAddr, prefixLength);
   1070 
   1071                         InetAddress gateAddr = NetworkUtils.hexToInet6Address(gate);
   1072 
   1073                         RouteInfo route = new RouteInfo(linkAddress, gateAddr);
   1074                         routes.add(route);
   1075                     } catch (Exception e) {
   1076                         Log.e(TAG, "Error parsing route " + s + " : " + e);
   1077                         continue;
   1078                     }
   1079                 }
   1080             }
   1081         }
   1082         return routes.toArray(new RouteInfo[routes.size()]);
   1083     }
   1084 
   1085     @Override
   1086     public void setMtu(String iface, int mtu) {
   1087         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
   1088 
   1089         final NativeDaemonEvent event;
   1090         try {
   1091             event = mConnector.execute("interface", "setmtu", iface, mtu);
   1092         } catch (NativeDaemonConnectorException e) {
   1093             throw e.rethrowAsParcelableException();
   1094         }
   1095     }
   1096 
   1097     @Override
   1098     public void shutdown() {
   1099         // TODO: remove from aidl if nobody calls externally
   1100         mContext.enforceCallingOrSelfPermission(SHUTDOWN, TAG);
   1101 
   1102         Slog.d(TAG, "Shutting down");
   1103     }
   1104 
   1105     @Override
   1106     public boolean getIpForwardingEnabled() throws IllegalStateException{
   1107         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
   1108 
   1109         final NativeDaemonEvent event;
   1110         try {
   1111             event = mConnector.execute("ipfwd", "status");
   1112         } catch (NativeDaemonConnectorException e) {
   1113             throw e.rethrowAsParcelableException();
   1114         }
   1115 
   1116         // 211 Forwarding enabled
   1117         event.checkCode(IpFwdStatusResult);
   1118         return event.getMessage().endsWith("enabled");
   1119     }
   1120 
   1121     @Override
   1122     public void setIpForwardingEnabled(boolean enable) {
   1123         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
   1124         try {
   1125             mConnector.execute("ipfwd", enable ? "enable" : "disable");
   1126         } catch (NativeDaemonConnectorException e) {
   1127             throw e.rethrowAsParcelableException();
   1128         }
   1129     }
   1130 
   1131     @Override
   1132     public void startTethering(String[] dhcpRange) {
   1133         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
   1134         // cmd is "tether start first_start first_stop second_start second_stop ..."
   1135         // an odd number of addrs will fail
   1136 
   1137         final Command cmd = new Command("tether", "start");
   1138         for (String d : dhcpRange) {
   1139             cmd.appendArg(d);
   1140         }
   1141 
   1142         try {
   1143             mConnector.execute(cmd);
   1144         } catch (NativeDaemonConnectorException e) {
   1145             throw e.rethrowAsParcelableException();
   1146         }
   1147     }
   1148 
   1149     @Override
   1150     public void stopTethering() {
   1151         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
   1152         try {
   1153             mConnector.execute("tether", "stop");
   1154         } catch (NativeDaemonConnectorException e) {
   1155             throw e.rethrowAsParcelableException();
   1156         }
   1157     }
   1158 
   1159     @Override
   1160     public boolean isTetheringStarted() {
   1161         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
   1162 
   1163         final NativeDaemonEvent event;
   1164         try {
   1165             event = mConnector.execute("tether", "status");
   1166         } catch (NativeDaemonConnectorException e) {
   1167             throw e.rethrowAsParcelableException();
   1168         }
   1169 
   1170         // 210 Tethering services started
   1171         event.checkCode(TetherStatusResult);
   1172         return event.getMessage().endsWith("started");
   1173     }
   1174 
   1175     @Override
   1176     public void tetherInterface(String iface) {
   1177         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
   1178         try {
   1179             mConnector.execute("tether", "interface", "add", iface);
   1180         } catch (NativeDaemonConnectorException e) {
   1181             throw e.rethrowAsParcelableException();
   1182         }
   1183         List<RouteInfo> routes = new ArrayList<RouteInfo>();
   1184         // The RouteInfo constructor truncates the LinkAddress to a network prefix, thus making it
   1185         // suitable to use as a route destination.
   1186         routes.add(new RouteInfo(getInterfaceConfig(iface).getLinkAddress(), null, iface));
   1187         addInterfaceToLocalNetwork(iface, routes);
   1188     }
   1189 
   1190     @Override
   1191     public void untetherInterface(String iface) {
   1192         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
   1193         try {
   1194             mConnector.execute("tether", "interface", "remove", iface);
   1195         } catch (NativeDaemonConnectorException e) {
   1196             throw e.rethrowAsParcelableException();
   1197         }
   1198         removeInterfaceFromLocalNetwork(iface);
   1199     }
   1200 
   1201     @Override
   1202     public String[] listTetheredInterfaces() {
   1203         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
   1204         try {
   1205             return NativeDaemonEvent.filterMessageList(
   1206                     mConnector.executeForList("tether", "interface", "list"),
   1207                     TetherInterfaceListResult);
   1208         } catch (NativeDaemonConnectorException e) {
   1209             throw e.rethrowAsParcelableException();
   1210         }
   1211     }
   1212 
   1213     @Override
   1214     public void setDnsForwarders(Network network, String[] dns) {
   1215         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
   1216 
   1217         int netId = (network != null) ? network.netId : ConnectivityManager.NETID_UNSET;
   1218         final Command cmd = new Command("tether", "dns", "set", netId);
   1219 
   1220         for (String s : dns) {
   1221             cmd.appendArg(NetworkUtils.numericToInetAddress(s).getHostAddress());
   1222         }
   1223 
   1224         try {
   1225             mConnector.execute(cmd);
   1226         } catch (NativeDaemonConnectorException e) {
   1227             throw e.rethrowAsParcelableException();
   1228         }
   1229     }
   1230 
   1231     @Override
   1232     public String[] getDnsForwarders() {
   1233         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
   1234         try {
   1235             return NativeDaemonEvent.filterMessageList(
   1236                     mConnector.executeForList("tether", "dns", "list"), TetherDnsFwdTgtListResult);
   1237         } catch (NativeDaemonConnectorException e) {
   1238             throw e.rethrowAsParcelableException();
   1239         }
   1240     }
   1241 
   1242     private List<InterfaceAddress> excludeLinkLocal(List<InterfaceAddress> addresses) {
   1243         ArrayList<InterfaceAddress> filtered = new ArrayList<InterfaceAddress>(addresses.size());
   1244         for (InterfaceAddress ia : addresses) {
   1245             if (!ia.getAddress().isLinkLocalAddress())
   1246                 filtered.add(ia);
   1247         }
   1248         return filtered;
   1249     }
   1250 
   1251     private void modifyNat(String action, String internalInterface, String externalInterface)
   1252             throws SocketException {
   1253         final Command cmd = new Command("nat", action, internalInterface, externalInterface);
   1254 
   1255         final NetworkInterface internalNetworkInterface = NetworkInterface.getByName(
   1256                 internalInterface);
   1257         if (internalNetworkInterface == null) {
   1258             cmd.appendArg("0");
   1259         } else {
   1260             // Don't touch link-local routes, as link-local addresses aren't routable,
   1261             // kernel creates link-local routes on all interfaces automatically
   1262             List<InterfaceAddress> interfaceAddresses = excludeLinkLocal(
   1263                     internalNetworkInterface.getInterfaceAddresses());
   1264             cmd.appendArg(interfaceAddresses.size());
   1265             for (InterfaceAddress ia : interfaceAddresses) {
   1266                 InetAddress addr = NetworkUtils.getNetworkPart(
   1267                         ia.getAddress(), ia.getNetworkPrefixLength());
   1268                 cmd.appendArg(addr.getHostAddress() + "/" + ia.getNetworkPrefixLength());
   1269             }
   1270         }
   1271 
   1272         try {
   1273             mConnector.execute(cmd);
   1274         } catch (NativeDaemonConnectorException e) {
   1275             throw e.rethrowAsParcelableException();
   1276         }
   1277     }
   1278 
   1279     @Override
   1280     public void enableNat(String internalInterface, String externalInterface) {
   1281         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
   1282         try {
   1283             modifyNat("enable", internalInterface, externalInterface);
   1284         } catch (SocketException e) {
   1285             throw new IllegalStateException(e);
   1286         }
   1287     }
   1288 
   1289     @Override
   1290     public void disableNat(String internalInterface, String externalInterface) {
   1291         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
   1292         try {
   1293             modifyNat("disable", internalInterface, externalInterface);
   1294         } catch (SocketException e) {
   1295             throw new IllegalStateException(e);
   1296         }
   1297     }
   1298 
   1299     @Override
   1300     public String[] listTtys() {
   1301         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
   1302         try {
   1303             return NativeDaemonEvent.filterMessageList(
   1304                     mConnector.executeForList("list_ttys"), TtyListResult);
   1305         } catch (NativeDaemonConnectorException e) {
   1306             throw e.rethrowAsParcelableException();
   1307         }
   1308     }
   1309 
   1310     @Override
   1311     public void attachPppd(
   1312             String tty, String localAddr, String remoteAddr, String dns1Addr, String dns2Addr) {
   1313         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
   1314         try {
   1315             mConnector.execute("pppd", "attach", tty,
   1316                     NetworkUtils.numericToInetAddress(localAddr).getHostAddress(),
   1317                     NetworkUtils.numericToInetAddress(remoteAddr).getHostAddress(),
   1318                     NetworkUtils.numericToInetAddress(dns1Addr).getHostAddress(),
   1319                     NetworkUtils.numericToInetAddress(dns2Addr).getHostAddress());
   1320         } catch (NativeDaemonConnectorException e) {
   1321             throw e.rethrowAsParcelableException();
   1322         }
   1323     }
   1324 
   1325     @Override
   1326     public void detachPppd(String tty) {
   1327         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
   1328         try {
   1329             mConnector.execute("pppd", "detach", tty);
   1330         } catch (NativeDaemonConnectorException e) {
   1331             throw e.rethrowAsParcelableException();
   1332         }
   1333     }
   1334 
   1335     @Override
   1336     public void startAccessPoint(
   1337             WifiConfiguration wifiConfig, String wlanIface) {
   1338         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
   1339         try {
   1340             wifiFirmwareReload(wlanIface, "AP");
   1341             if (wifiConfig == null) {
   1342                 mConnector.execute("softap", "set", wlanIface);
   1343             } else {
   1344                 mConnector.execute("softap", "set", wlanIface, wifiConfig.SSID,
   1345                                    "broadcast", "6", getSecurityType(wifiConfig),
   1346                                    new SensitiveArg(wifiConfig.preSharedKey));
   1347             }
   1348             mConnector.execute("softap", "startap");
   1349         } catch (NativeDaemonConnectorException e) {
   1350             throw e.rethrowAsParcelableException();
   1351         }
   1352     }
   1353 
   1354     private static String getSecurityType(WifiConfiguration wifiConfig) {
   1355         switch (wifiConfig.getAuthType()) {
   1356             case KeyMgmt.WPA_PSK:
   1357                 return "wpa-psk";
   1358             case KeyMgmt.WPA2_PSK:
   1359                 return "wpa2-psk";
   1360             default:
   1361                 return "open";
   1362         }
   1363     }
   1364 
   1365     /* @param mode can be "AP", "STA" or "P2P" */
   1366     @Override
   1367     public void wifiFirmwareReload(String wlanIface, String mode) {
   1368         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
   1369         try {
   1370             mConnector.execute("softap", "fwreload", wlanIface, mode);
   1371         } catch (NativeDaemonConnectorException e) {
   1372             throw e.rethrowAsParcelableException();
   1373         }
   1374     }
   1375 
   1376     @Override
   1377     public void stopAccessPoint(String wlanIface) {
   1378         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
   1379         try {
   1380             mConnector.execute("softap", "stopap");
   1381             wifiFirmwareReload(wlanIface, "STA");
   1382         } catch (NativeDaemonConnectorException e) {
   1383             throw e.rethrowAsParcelableException();
   1384         }
   1385     }
   1386 
   1387     @Override
   1388     public void setAccessPoint(WifiConfiguration wifiConfig, String wlanIface) {
   1389         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
   1390         try {
   1391             if (wifiConfig == null) {
   1392                 mConnector.execute("softap", "set", wlanIface);
   1393             } else {
   1394                 mConnector.execute("softap", "set", wlanIface, wifiConfig.SSID,
   1395                                    "broadcast", "6", getSecurityType(wifiConfig),
   1396                                    new SensitiveArg(wifiConfig.preSharedKey));
   1397             }
   1398         } catch (NativeDaemonConnectorException e) {
   1399             throw e.rethrowAsParcelableException();
   1400         }
   1401     }
   1402 
   1403     @Override
   1404     public void addIdleTimer(String iface, int timeout, final int type) {
   1405         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
   1406 
   1407         if (DBG) Slog.d(TAG, "Adding idletimer");
   1408 
   1409         synchronized (mIdleTimerLock) {
   1410             IdleTimerParams params = mActiveIdleTimers.get(iface);
   1411             if (params != null) {
   1412                 // the interface already has idletimer, update network count
   1413                 params.networkCount++;
   1414                 return;
   1415             }
   1416 
   1417             try {
   1418                 mConnector.execute("idletimer", "add", iface, Integer.toString(timeout),
   1419                         Integer.toString(type));
   1420             } catch (NativeDaemonConnectorException e) {
   1421                 throw e.rethrowAsParcelableException();
   1422             }
   1423             mActiveIdleTimers.put(iface, new IdleTimerParams(timeout, type));
   1424 
   1425             // Networks start up.
   1426             if (ConnectivityManager.isNetworkTypeMobile(type)) {
   1427                 mNetworkActive = false;
   1428             }
   1429             mDaemonHandler.post(new Runnable() {
   1430                 @Override public void run() {
   1431                     notifyInterfaceClassActivity(type,
   1432                             DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH,
   1433                             SystemClock.elapsedRealtimeNanos(), false);
   1434                 }
   1435             });
   1436         }
   1437     }
   1438 
   1439     @Override
   1440     public void removeIdleTimer(String iface) {
   1441         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
   1442 
   1443         if (DBG) Slog.d(TAG, "Removing idletimer");
   1444 
   1445         synchronized (mIdleTimerLock) {
   1446             final IdleTimerParams params = mActiveIdleTimers.get(iface);
   1447             if (params == null || --(params.networkCount) > 0) {
   1448                 return;
   1449             }
   1450 
   1451             try {
   1452                 mConnector.execute("idletimer", "remove", iface,
   1453                         Integer.toString(params.timeout), Integer.toString(params.type));
   1454             } catch (NativeDaemonConnectorException e) {
   1455                 throw e.rethrowAsParcelableException();
   1456             }
   1457             mActiveIdleTimers.remove(iface);
   1458             mDaemonHandler.post(new Runnable() {
   1459                 @Override public void run() {
   1460                     notifyInterfaceClassActivity(params.type,
   1461                             DataConnectionRealTimeInfo.DC_POWER_STATE_LOW,
   1462                             SystemClock.elapsedRealtimeNanos(), false);
   1463                 }
   1464             });
   1465         }
   1466     }
   1467 
   1468     @Override
   1469     public NetworkStats getNetworkStatsSummaryDev() {
   1470         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
   1471         try {
   1472             return mStatsFactory.readNetworkStatsSummaryDev();
   1473         } catch (IOException e) {
   1474             throw new IllegalStateException(e);
   1475         }
   1476     }
   1477 
   1478     @Override
   1479     public NetworkStats getNetworkStatsSummaryXt() {
   1480         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
   1481         try {
   1482             return mStatsFactory.readNetworkStatsSummaryXt();
   1483         } catch (IOException e) {
   1484             throw new IllegalStateException(e);
   1485         }
   1486     }
   1487 
   1488     @Override
   1489     public NetworkStats getNetworkStatsDetail() {
   1490         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
   1491         try {
   1492             return mStatsFactory.readNetworkStatsDetail(UID_ALL, null, TAG_ALL, null);
   1493         } catch (IOException e) {
   1494             throw new IllegalStateException(e);
   1495         }
   1496     }
   1497 
   1498     @Override
   1499     public void setInterfaceQuota(String iface, long quotaBytes) {
   1500         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
   1501 
   1502         // silently discard when control disabled
   1503         // TODO: eventually migrate to be always enabled
   1504         if (!mBandwidthControlEnabled) return;
   1505 
   1506         synchronized (mQuotaLock) {
   1507             if (mActiveQuotas.containsKey(iface)) {
   1508                 throw new IllegalStateException("iface " + iface + " already has quota");
   1509             }
   1510 
   1511             try {
   1512                 // TODO: support quota shared across interfaces
   1513                 mConnector.execute("bandwidth", "setiquota", iface, quotaBytes);
   1514                 mActiveQuotas.put(iface, quotaBytes);
   1515             } catch (NativeDaemonConnectorException e) {
   1516                 throw e.rethrowAsParcelableException();
   1517             }
   1518         }
   1519     }
   1520 
   1521     @Override
   1522     public void removeInterfaceQuota(String iface) {
   1523         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
   1524 
   1525         // silently discard when control disabled
   1526         // TODO: eventually migrate to be always enabled
   1527         if (!mBandwidthControlEnabled) return;
   1528 
   1529         synchronized (mQuotaLock) {
   1530             if (!mActiveQuotas.containsKey(iface)) {
   1531                 // TODO: eventually consider throwing
   1532                 return;
   1533             }
   1534 
   1535             mActiveQuotas.remove(iface);
   1536             mActiveAlerts.remove(iface);
   1537 
   1538             try {
   1539                 // TODO: support quota shared across interfaces
   1540                 mConnector.execute("bandwidth", "removeiquota", iface);
   1541             } catch (NativeDaemonConnectorException e) {
   1542                 throw e.rethrowAsParcelableException();
   1543             }
   1544         }
   1545     }
   1546 
   1547     @Override
   1548     public void setInterfaceAlert(String iface, long alertBytes) {
   1549         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
   1550 
   1551         // silently discard when control disabled
   1552         // TODO: eventually migrate to be always enabled
   1553         if (!mBandwidthControlEnabled) return;
   1554 
   1555         // quick sanity check
   1556         if (!mActiveQuotas.containsKey(iface)) {
   1557             throw new IllegalStateException("setting alert requires existing quota on iface");
   1558         }
   1559 
   1560         synchronized (mQuotaLock) {
   1561             if (mActiveAlerts.containsKey(iface)) {
   1562                 throw new IllegalStateException("iface " + iface + " already has alert");
   1563             }
   1564 
   1565             try {
   1566                 // TODO: support alert shared across interfaces
   1567                 mConnector.execute("bandwidth", "setinterfacealert", iface, alertBytes);
   1568                 mActiveAlerts.put(iface, alertBytes);
   1569             } catch (NativeDaemonConnectorException e) {
   1570                 throw e.rethrowAsParcelableException();
   1571             }
   1572         }
   1573     }
   1574 
   1575     @Override
   1576     public void removeInterfaceAlert(String iface) {
   1577         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
   1578 
   1579         // silently discard when control disabled
   1580         // TODO: eventually migrate to be always enabled
   1581         if (!mBandwidthControlEnabled) return;
   1582 
   1583         synchronized (mQuotaLock) {
   1584             if (!mActiveAlerts.containsKey(iface)) {
   1585                 // TODO: eventually consider throwing
   1586                 return;
   1587             }
   1588 
   1589             try {
   1590                 // TODO: support alert shared across interfaces
   1591                 mConnector.execute("bandwidth", "removeinterfacealert", iface);
   1592                 mActiveAlerts.remove(iface);
   1593             } catch (NativeDaemonConnectorException e) {
   1594                 throw e.rethrowAsParcelableException();
   1595             }
   1596         }
   1597     }
   1598 
   1599     @Override
   1600     public void setGlobalAlert(long alertBytes) {
   1601         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
   1602 
   1603         // silently discard when control disabled
   1604         // TODO: eventually migrate to be always enabled
   1605         if (!mBandwidthControlEnabled) return;
   1606 
   1607         try {
   1608             mConnector.execute("bandwidth", "setglobalalert", alertBytes);
   1609         } catch (NativeDaemonConnectorException e) {
   1610             throw e.rethrowAsParcelableException();
   1611         }
   1612     }
   1613 
   1614     @Override
   1615     public void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces) {
   1616         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
   1617 
   1618         // silently discard when control disabled
   1619         // TODO: eventually migrate to be always enabled
   1620         if (!mBandwidthControlEnabled) return;
   1621 
   1622         synchronized (mQuotaLock) {
   1623             final boolean oldRejectOnQuota = mUidRejectOnQuota.get(uid, false);
   1624             if (oldRejectOnQuota == rejectOnQuotaInterfaces) {
   1625                 // TODO: eventually consider throwing
   1626                 return;
   1627             }
   1628 
   1629             try {
   1630                 mConnector.execute("bandwidth",
   1631                         rejectOnQuotaInterfaces ? "addnaughtyapps" : "removenaughtyapps", uid);
   1632                 if (rejectOnQuotaInterfaces) {
   1633                     mUidRejectOnQuota.put(uid, true);
   1634                 } else {
   1635                     mUidRejectOnQuota.delete(uid);
   1636                 }
   1637             } catch (NativeDaemonConnectorException e) {
   1638                 throw e.rethrowAsParcelableException();
   1639             }
   1640         }
   1641     }
   1642 
   1643     @Override
   1644     public boolean isBandwidthControlEnabled() {
   1645         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
   1646         return mBandwidthControlEnabled;
   1647     }
   1648 
   1649     @Override
   1650     public NetworkStats getNetworkStatsUidDetail(int uid) {
   1651         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
   1652         try {
   1653             return mStatsFactory.readNetworkStatsDetail(uid, null, TAG_ALL, null);
   1654         } catch (IOException e) {
   1655             throw new IllegalStateException(e);
   1656         }
   1657     }
   1658 
   1659     @Override
   1660     public NetworkStats getNetworkStatsTethering() {
   1661         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
   1662 
   1663         final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1);
   1664         try {
   1665             final NativeDaemonEvent[] events = mConnector.executeForList(
   1666                     "bandwidth", "gettetherstats");
   1667             for (NativeDaemonEvent event : events) {
   1668                 if (event.getCode() != TetheringStatsListResult) continue;
   1669 
   1670                 // 114 ifaceIn ifaceOut rx_bytes rx_packets tx_bytes tx_packets
   1671                 final StringTokenizer tok = new StringTokenizer(event.getMessage());
   1672                 try {
   1673                     final String ifaceIn = tok.nextToken();
   1674                     final String ifaceOut = tok.nextToken();
   1675 
   1676                     final NetworkStats.Entry entry = new NetworkStats.Entry();
   1677                     entry.iface = ifaceOut;
   1678                     entry.uid = UID_TETHERING;
   1679                     entry.set = SET_DEFAULT;
   1680                     entry.tag = TAG_NONE;
   1681                     entry.rxBytes = Long.parseLong(tok.nextToken());
   1682                     entry.rxPackets = Long.parseLong(tok.nextToken());
   1683                     entry.txBytes = Long.parseLong(tok.nextToken());
   1684                     entry.txPackets = Long.parseLong(tok.nextToken());
   1685                     stats.combineValues(entry);
   1686                 } catch (NoSuchElementException e) {
   1687                     throw new IllegalStateException("problem parsing tethering stats: " + event);
   1688                 } catch (NumberFormatException e) {
   1689                     throw new IllegalStateException("problem parsing tethering stats: " + event);
   1690                 }
   1691             }
   1692         } catch (NativeDaemonConnectorException e) {
   1693             throw e.rethrowAsParcelableException();
   1694         }
   1695         return stats;
   1696     }
   1697 
   1698     @Override
   1699     public void setDnsServersForNetwork(int netId, String[] servers, String domains) {
   1700         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
   1701 
   1702         final Command cmd = new Command("resolver", "setnetdns", netId,
   1703                 (domains == null ? "" : domains));
   1704 
   1705         for (String s : servers) {
   1706             InetAddress a = NetworkUtils.numericToInetAddress(s);
   1707             if (a.isAnyLocalAddress() == false) {
   1708                 cmd.appendArg(a.getHostAddress());
   1709             }
   1710         }
   1711 
   1712         try {
   1713             mConnector.execute(cmd);
   1714         } catch (NativeDaemonConnectorException e) {
   1715             throw e.rethrowAsParcelableException();
   1716         }
   1717     }
   1718 
   1719     @Override
   1720     public void addVpnUidRanges(int netId, UidRange[] ranges) {
   1721         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
   1722         Object[] argv = new Object[3 + MAX_UID_RANGES_PER_COMMAND];
   1723         argv[0] = "users";
   1724         argv[1] = "add";
   1725         argv[2] = netId;
   1726         int argc = 3;
   1727         // Avoid overly long commands by limiting number of UID ranges per command.
   1728         for (int i = 0; i < ranges.length; i++) {
   1729             argv[argc++] = ranges[i].toString();
   1730             if (i == (ranges.length - 1) || argc == argv.length) {
   1731                 try {
   1732                     mConnector.execute("network", Arrays.copyOf(argv, argc));
   1733                 } catch (NativeDaemonConnectorException e) {
   1734                     throw e.rethrowAsParcelableException();
   1735                 }
   1736                 argc = 3;
   1737             }
   1738         }
   1739     }
   1740 
   1741     @Override
   1742     public void removeVpnUidRanges(int netId, UidRange[] ranges) {
   1743         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
   1744         Object[] argv = new Object[3 + MAX_UID_RANGES_PER_COMMAND];
   1745         argv[0] = "users";
   1746         argv[1] = "remove";
   1747         argv[2] = netId;
   1748         int argc = 3;
   1749         // Avoid overly long commands by limiting number of UID ranges per command.
   1750         for (int i = 0; i < ranges.length; i++) {
   1751             argv[argc++] = ranges[i].toString();
   1752             if (i == (ranges.length - 1) || argc == argv.length) {
   1753                 try {
   1754                     mConnector.execute("network", Arrays.copyOf(argv, argc));
   1755                 } catch (NativeDaemonConnectorException e) {
   1756                     throw e.rethrowAsParcelableException();
   1757                 }
   1758                 argc = 3;
   1759             }
   1760         }
   1761     }
   1762 
   1763     @Override
   1764     public void flushNetworkDnsCache(int netId) {
   1765         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
   1766         try {
   1767             mConnector.execute("resolver", "flushnet", netId);
   1768         } catch (NativeDaemonConnectorException e) {
   1769             throw e.rethrowAsParcelableException();
   1770         }
   1771     }
   1772 
   1773     @Override
   1774     public void setFirewallEnabled(boolean enabled) {
   1775         enforceSystemUid();
   1776         try {
   1777             mConnector.execute("firewall", enabled ? "enable" : "disable");
   1778             mFirewallEnabled = enabled;
   1779         } catch (NativeDaemonConnectorException e) {
   1780             throw e.rethrowAsParcelableException();
   1781         }
   1782     }
   1783 
   1784     @Override
   1785     public boolean isFirewallEnabled() {
   1786         enforceSystemUid();
   1787         return mFirewallEnabled;
   1788     }
   1789 
   1790     @Override
   1791     public void setFirewallInterfaceRule(String iface, boolean allow) {
   1792         enforceSystemUid();
   1793         Preconditions.checkState(mFirewallEnabled);
   1794         final String rule = allow ? "allow" : "deny";
   1795         try {
   1796             mConnector.execute("firewall", "set_interface_rule", iface, rule);
   1797         } catch (NativeDaemonConnectorException e) {
   1798             throw e.rethrowAsParcelableException();
   1799         }
   1800     }
   1801 
   1802     @Override
   1803     public void setFirewallEgressSourceRule(String addr, boolean allow) {
   1804         enforceSystemUid();
   1805         Preconditions.checkState(mFirewallEnabled);
   1806         final String rule = allow ? "allow" : "deny";
   1807         try {
   1808             mConnector.execute("firewall", "set_egress_source_rule", addr, rule);
   1809         } catch (NativeDaemonConnectorException e) {
   1810             throw e.rethrowAsParcelableException();
   1811         }
   1812     }
   1813 
   1814     @Override
   1815     public void setFirewallEgressDestRule(String addr, int port, boolean allow) {
   1816         enforceSystemUid();
   1817         Preconditions.checkState(mFirewallEnabled);
   1818         final String rule = allow ? "allow" : "deny";
   1819         try {
   1820             mConnector.execute("firewall", "set_egress_dest_rule", addr, port, rule);
   1821         } catch (NativeDaemonConnectorException e) {
   1822             throw e.rethrowAsParcelableException();
   1823         }
   1824     }
   1825 
   1826     @Override
   1827     public void setFirewallUidRule(int uid, boolean allow) {
   1828         enforceSystemUid();
   1829         Preconditions.checkState(mFirewallEnabled);
   1830         final String rule = allow ? "allow" : "deny";
   1831         try {
   1832             mConnector.execute("firewall", "set_uid_rule", uid, rule);
   1833         } catch (NativeDaemonConnectorException e) {
   1834             throw e.rethrowAsParcelableException();
   1835         }
   1836     }
   1837 
   1838     private static void enforceSystemUid() {
   1839         final int uid = Binder.getCallingUid();
   1840         if (uid != Process.SYSTEM_UID) {
   1841             throw new SecurityException("Only available to AID_SYSTEM");
   1842         }
   1843     }
   1844 
   1845     @Override
   1846     public void startClatd(String interfaceName) throws IllegalStateException {
   1847         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
   1848 
   1849         try {
   1850             mConnector.execute("clatd", "start", interfaceName);
   1851         } catch (NativeDaemonConnectorException e) {
   1852             throw e.rethrowAsParcelableException();
   1853         }
   1854     }
   1855 
   1856     @Override
   1857     public void stopClatd() throws IllegalStateException {
   1858         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
   1859 
   1860         try {
   1861             mConnector.execute("clatd", "stop");
   1862         } catch (NativeDaemonConnectorException e) {
   1863             throw e.rethrowAsParcelableException();
   1864         }
   1865     }
   1866 
   1867     @Override
   1868     public boolean isClatdStarted() {
   1869         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
   1870 
   1871         final NativeDaemonEvent event;
   1872         try {
   1873             event = mConnector.execute("clatd", "status");
   1874         } catch (NativeDaemonConnectorException e) {
   1875             throw e.rethrowAsParcelableException();
   1876         }
   1877 
   1878         event.checkCode(ClatdStatusResult);
   1879         return event.getMessage().endsWith("started");
   1880     }
   1881 
   1882     @Override
   1883     public void registerNetworkActivityListener(INetworkActivityListener listener) {
   1884         mNetworkActivityListeners.register(listener);
   1885     }
   1886 
   1887     @Override
   1888     public void unregisterNetworkActivityListener(INetworkActivityListener listener) {
   1889         mNetworkActivityListeners.unregister(listener);
   1890     }
   1891 
   1892     @Override
   1893     public boolean isNetworkActive() {
   1894         synchronized (mNetworkActivityListeners) {
   1895             return mNetworkActive || mActiveIdleTimers.isEmpty();
   1896         }
   1897     }
   1898 
   1899     private void reportNetworkActive() {
   1900         final int length = mNetworkActivityListeners.beginBroadcast();
   1901         try {
   1902             for (int i = 0; i < length; i++) {
   1903                 try {
   1904                     mNetworkActivityListeners.getBroadcastItem(i).onNetworkActive();
   1905                 } catch (RemoteException e) {
   1906                 } catch (RuntimeException e) {
   1907                 }
   1908             }
   1909         } finally {
   1910             mNetworkActivityListeners.finishBroadcast();
   1911         }
   1912     }
   1913 
   1914     /** {@inheritDoc} */
   1915     @Override
   1916     public void monitor() {
   1917         if (mConnector != null) {
   1918             mConnector.monitor();
   1919         }
   1920     }
   1921 
   1922     @Override
   1923     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
   1924         mContext.enforceCallingOrSelfPermission(DUMP, TAG);
   1925 
   1926         pw.println("NetworkManagementService NativeDaemonConnector Log:");
   1927         mConnector.dump(fd, pw, args);
   1928         pw.println();
   1929 
   1930         pw.print("Bandwidth control enabled: "); pw.println(mBandwidthControlEnabled);
   1931         pw.print("mMobileActivityFromRadio="); pw.print(mMobileActivityFromRadio);
   1932                 pw.print(" mLastPowerStateFromRadio="); pw.println(mLastPowerStateFromRadio);
   1933         pw.print("mNetworkActive="); pw.println(mNetworkActive);
   1934 
   1935         synchronized (mQuotaLock) {
   1936             pw.print("Active quota ifaces: "); pw.println(mActiveQuotas.toString());
   1937             pw.print("Active alert ifaces: "); pw.println(mActiveAlerts.toString());
   1938         }
   1939 
   1940         synchronized (mUidRejectOnQuota) {
   1941             pw.print("UID reject on quota ifaces: [");
   1942             final int size = mUidRejectOnQuota.size();
   1943             for (int i = 0; i < size; i++) {
   1944                 pw.print(mUidRejectOnQuota.keyAt(i));
   1945                 if (i < size - 1) pw.print(",");
   1946             }
   1947             pw.println("]");
   1948         }
   1949 
   1950         synchronized (mIdleTimerLock) {
   1951             pw.println("Idle timers:");
   1952             for (HashMap.Entry<String, IdleTimerParams> ent : mActiveIdleTimers.entrySet()) {
   1953                 pw.print("  "); pw.print(ent.getKey()); pw.println(":");
   1954                 IdleTimerParams params = ent.getValue();
   1955                 pw.print("    timeout="); pw.print(params.timeout);
   1956                 pw.print(" type="); pw.print(params.type);
   1957                 pw.print(" networkCount="); pw.println(params.networkCount);
   1958             }
   1959         }
   1960 
   1961         pw.print("Firewall enabled: "); pw.println(mFirewallEnabled);
   1962     }
   1963 
   1964     @Override
   1965     public void createPhysicalNetwork(int netId) {
   1966         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
   1967 
   1968         try {
   1969             mConnector.execute("network", "create", netId);
   1970         } catch (NativeDaemonConnectorException e) {
   1971             throw e.rethrowAsParcelableException();
   1972         }
   1973     }
   1974 
   1975     @Override
   1976     public void createVirtualNetwork(int netId, boolean hasDNS, boolean secure) {
   1977         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
   1978 
   1979         try {
   1980             mConnector.execute("network", "create", netId, "vpn", hasDNS ? "1" : "0",
   1981                     secure ? "1" : "0");
   1982         } catch (NativeDaemonConnectorException e) {
   1983             throw e.rethrowAsParcelableException();
   1984         }
   1985     }
   1986 
   1987     @Override
   1988     public void removeNetwork(int netId) {
   1989         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
   1990 
   1991         try {
   1992             mConnector.execute("network", "destroy", netId);
   1993         } catch (NativeDaemonConnectorException e) {
   1994             throw e.rethrowAsParcelableException();
   1995         }
   1996     }
   1997 
   1998     @Override
   1999     public void addInterfaceToNetwork(String iface, int netId) {
   2000         modifyInterfaceInNetwork("add", "" + netId, iface);
   2001     }
   2002 
   2003     @Override
   2004     public void removeInterfaceFromNetwork(String iface, int netId) {
   2005         modifyInterfaceInNetwork("remove", "" + netId, iface);
   2006     }
   2007 
   2008     private void modifyInterfaceInNetwork(String action, String netId, String iface) {
   2009         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
   2010         try {
   2011             mConnector.execute("network", "interface", action, netId, iface);
   2012         } catch (NativeDaemonConnectorException e) {
   2013             throw e.rethrowAsParcelableException();
   2014         }
   2015     }
   2016 
   2017     @Override
   2018     public void addLegacyRouteForNetId(int netId, RouteInfo routeInfo, int uid) {
   2019         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
   2020 
   2021         final Command cmd = new Command("network", "route", "legacy", uid, "add", netId);
   2022 
   2023         // create triplet: interface dest-ip-addr/prefixlength gateway-ip-addr
   2024         final LinkAddress la = routeInfo.getDestinationLinkAddress();
   2025         cmd.appendArg(routeInfo.getInterface());
   2026         cmd.appendArg(la.getAddress().getHostAddress() + "/" + la.getPrefixLength());
   2027         if (routeInfo.hasGateway()) {
   2028             cmd.appendArg(routeInfo.getGateway().getHostAddress());
   2029         }
   2030 
   2031         try {
   2032             mConnector.execute(cmd);
   2033         } catch (NativeDaemonConnectorException e) {
   2034             throw e.rethrowAsParcelableException();
   2035         }
   2036     }
   2037 
   2038     @Override
   2039     public void setDefaultNetId(int netId) {
   2040         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
   2041 
   2042         try {
   2043             mConnector.execute("network", "default", "set", netId);
   2044         } catch (NativeDaemonConnectorException e) {
   2045             throw e.rethrowAsParcelableException();
   2046         }
   2047     }
   2048 
   2049     @Override
   2050     public void clearDefaultNetId() {
   2051         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
   2052 
   2053         try {
   2054             mConnector.execute("network", "default", "clear");
   2055         } catch (NativeDaemonConnectorException e) {
   2056             throw e.rethrowAsParcelableException();
   2057         }
   2058     }
   2059 
   2060     @Override
   2061     public void setPermission(String permission, int[] uids) {
   2062         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
   2063 
   2064         Object[] argv = new Object[4 + MAX_UID_RANGES_PER_COMMAND];
   2065         argv[0] = "permission";
   2066         argv[1] = "user";
   2067         argv[2] = "set";
   2068         argv[3] = permission;
   2069         int argc = 4;
   2070         // Avoid overly long commands by limiting number of UIDs per command.
   2071         for (int i = 0; i < uids.length; ++i) {
   2072             argv[argc++] = uids[i];
   2073             if (i == uids.length - 1 || argc == argv.length) {
   2074                 try {
   2075                     mConnector.execute("network", Arrays.copyOf(argv, argc));
   2076                 } catch (NativeDaemonConnectorException e) {
   2077                     throw e.rethrowAsParcelableException();
   2078                 }
   2079                 argc = 4;
   2080             }
   2081         }
   2082     }
   2083 
   2084     @Override
   2085     public void clearPermission(int[] uids) {
   2086         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
   2087 
   2088         Object[] argv = new Object[3 + MAX_UID_RANGES_PER_COMMAND];
   2089         argv[0] = "permission";
   2090         argv[1] = "user";
   2091         argv[2] = "clear";
   2092         int argc = 3;
   2093         // Avoid overly long commands by limiting number of UIDs per command.
   2094         for (int i = 0; i < uids.length; ++i) {
   2095             argv[argc++] = uids[i];
   2096             if (i == uids.length - 1 || argc == argv.length) {
   2097                 try {
   2098                     mConnector.execute("network", Arrays.copyOf(argv, argc));
   2099                 } catch (NativeDaemonConnectorException e) {
   2100                     throw e.rethrowAsParcelableException();
   2101                 }
   2102                 argc = 3;
   2103             }
   2104         }
   2105     }
   2106 
   2107     @Override
   2108     public void allowProtect(int uid) {
   2109         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
   2110 
   2111         try {
   2112             mConnector.execute("network", "protect", "allow", uid);
   2113         } catch (NativeDaemonConnectorException e) {
   2114             throw e.rethrowAsParcelableException();
   2115         }
   2116     }
   2117 
   2118     @Override
   2119     public void denyProtect(int uid) {
   2120         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
   2121 
   2122         try {
   2123             mConnector.execute("network", "protect", "deny", uid);
   2124         } catch (NativeDaemonConnectorException e) {
   2125             throw e.rethrowAsParcelableException();
   2126         }
   2127     }
   2128 
   2129     @Override
   2130     public void addInterfaceToLocalNetwork(String iface, List<RouteInfo> routes) {
   2131         modifyInterfaceInNetwork("add", "local", iface);
   2132 
   2133         for (RouteInfo route : routes) {
   2134             if (!route.isDefaultRoute()) {
   2135                 modifyRoute("add", "local", route);
   2136             }
   2137         }
   2138     }
   2139 
   2140     @Override
   2141     public void removeInterfaceFromLocalNetwork(String iface) {
   2142         modifyInterfaceInNetwork("remove", "local", iface);
   2143     }
   2144 }
   2145