OSDN Git Service

bdbd06640e499be801517eb5d9a39a740e5cc5bf
[android-x86/frameworks-base.git] / services / core / java / com / android / server / NetworkManagementService.java
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 }