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