OSDN Git Service

DO NOT MERGE. Grant MMS Uri permissions as the calling UID.
[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);
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
975     @Override
976     public String[] listInterfaces() {
977         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
978         try {
979             return NativeDaemonEvent.filterMessageList(
980                     mConnector.executeForList("interface", "list"), InterfaceListResult);
981         } catch (NativeDaemonConnectorException e) {
982             throw e.rethrowAsParcelableException();
983         }
984     }
985
986     @Override
987     public InterfaceConfiguration getInterfaceConfig(String iface) {
988         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
989
990         final NativeDaemonEvent event;
991         try {
992             event = mConnector.execute("interface", "getcfg", iface);
993         } catch (NativeDaemonConnectorException e) {
994             throw e.rethrowAsParcelableException();
995         }
996
997         event.checkCode(InterfaceGetCfgResult);
998
999         // Rsp: 213 xx:xx:xx:xx:xx:xx yyy.yyy.yyy.yyy zzz flag1 flag2 flag3
1000         final StringTokenizer st = new StringTokenizer(event.getMessage());
1001
1002         InterfaceConfiguration cfg;
1003         try {
1004             cfg = new InterfaceConfiguration();
1005             cfg.setHardwareAddress(st.nextToken(" "));
1006             InetAddress addr = null;
1007             int prefixLength = 0;
1008             try {
1009                 addr = NetworkUtils.numericToInetAddress(st.nextToken());
1010             } catch (IllegalArgumentException iae) {
1011                 Slog.e(TAG, "Failed to parse ipaddr", iae);
1012             }
1013
1014             try {
1015                 prefixLength = Integer.parseInt(st.nextToken());
1016             } catch (NumberFormatException nfe) {
1017                 Slog.e(TAG, "Failed to parse prefixLength", nfe);
1018             }
1019
1020             cfg.setLinkAddress(new LinkAddress(addr, prefixLength));
1021             while (st.hasMoreTokens()) {
1022                 cfg.setFlag(st.nextToken());
1023             }
1024         } catch (NoSuchElementException nsee) {
1025             throw new IllegalStateException("Invalid response from daemon: " + event);
1026         }
1027         return cfg;
1028     }
1029
1030     @Override
1031     public void setInterfaceConfig(String iface, InterfaceConfiguration cfg) {
1032         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1033         LinkAddress linkAddr = cfg.getLinkAddress();
1034         if (linkAddr == null || linkAddr.getAddress() == null) {
1035             throw new IllegalStateException("Null LinkAddress given");
1036         }
1037
1038         final Command cmd = new Command("interface", "setcfg", iface,
1039                 linkAddr.getAddress().getHostAddress(),
1040                 linkAddr.getPrefixLength());
1041         for (String flag : cfg.getFlags()) {
1042             cmd.appendArg(flag);
1043         }
1044
1045         try {
1046             mConnector.execute(cmd);
1047         } catch (NativeDaemonConnectorException e) {
1048             throw e.rethrowAsParcelableException();
1049         }
1050     }
1051
1052     @Override
1053     public void setInterfaceDown(String iface) {
1054         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1055         final InterfaceConfiguration ifcg = getInterfaceConfig(iface);
1056         ifcg.setInterfaceDown();
1057         setInterfaceConfig(iface, ifcg);
1058     }
1059
1060     @Override
1061     public void setInterfaceUp(String iface) {
1062         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1063         final InterfaceConfiguration ifcg = getInterfaceConfig(iface);
1064         ifcg.setInterfaceUp();
1065         setInterfaceConfig(iface, ifcg);
1066     }
1067
1068     @Override
1069     public void setInterfaceIpv6PrivacyExtensions(String iface, boolean enable) {
1070         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1071         try {
1072             mConnector.execute(
1073                     "interface", "ipv6privacyextensions", iface, enable ? "enable" : "disable");
1074         } catch (NativeDaemonConnectorException e) {
1075             throw e.rethrowAsParcelableException();
1076         }
1077     }
1078
1079     /* TODO: This is right now a IPv4 only function. Works for wifi which loses its
1080        IPv6 addresses on interface down, but we need to do full clean up here */
1081     @Override
1082     public void clearInterfaceAddresses(String iface) {
1083         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1084         try {
1085             mConnector.execute("interface", "clearaddrs", iface);
1086         } catch (NativeDaemonConnectorException e) {
1087             throw e.rethrowAsParcelableException();
1088         }
1089     }
1090
1091     @Override
1092     public void enableIpv6(String iface) {
1093         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1094         try {
1095             mConnector.execute("interface", "ipv6", iface, "enable");
1096         } catch (NativeDaemonConnectorException e) {
1097             throw e.rethrowAsParcelableException();
1098         }
1099     }
1100
1101     @Override
1102     public void disableIpv6(String iface) {
1103         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1104         try {
1105             mConnector.execute("interface", "ipv6", iface, "disable");
1106         } catch (NativeDaemonConnectorException e) {
1107             throw e.rethrowAsParcelableException();
1108         }
1109     }
1110
1111     @Override
1112     public void setInterfaceIpv6NdOffload(String iface, boolean enable) {
1113         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1114         try {
1115             mConnector.execute(
1116                     "interface", "ipv6ndoffload", iface, (enable ? "enable" : "disable"));
1117         } catch (NativeDaemonConnectorException e) {
1118             throw e.rethrowAsParcelableException();
1119         }
1120     }
1121
1122     @Override
1123     public void addRoute(int netId, RouteInfo route) {
1124         modifyRoute("add", "" + netId, route);
1125     }
1126
1127     @Override
1128     public void removeRoute(int netId, RouteInfo route) {
1129         modifyRoute("remove", "" + netId, route);
1130     }
1131
1132     private void modifyRoute(String action, String netId, RouteInfo route) {
1133         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1134
1135         final Command cmd = new Command("network", "route", action, netId);
1136
1137         // create triplet: interface dest-ip-addr/prefixlength gateway-ip-addr
1138         cmd.appendArg(route.getInterface());
1139         cmd.appendArg(route.getDestination().toString());
1140
1141         switch (route.getType()) {
1142             case RouteInfo.RTN_UNICAST:
1143                 if (route.hasGateway()) {
1144                     cmd.appendArg(route.getGateway().getHostAddress());
1145                 }
1146                 break;
1147             case RouteInfo.RTN_UNREACHABLE:
1148                 cmd.appendArg("unreachable");
1149                 break;
1150             case RouteInfo.RTN_THROW:
1151                 cmd.appendArg("throw");
1152                 break;
1153         }
1154
1155         try {
1156             mConnector.execute(cmd);
1157         } catch (NativeDaemonConnectorException e) {
1158             throw e.rethrowAsParcelableException();
1159         }
1160     }
1161
1162     private ArrayList<String> readRouteList(String filename) {
1163         FileInputStream fstream = null;
1164         ArrayList<String> list = new ArrayList<String>();
1165
1166         try {
1167             fstream = new FileInputStream(filename);
1168             DataInputStream in = new DataInputStream(fstream);
1169             BufferedReader br = new BufferedReader(new InputStreamReader(in));
1170             String s;
1171
1172             // throw away the title line
1173
1174             while (((s = br.readLine()) != null) && (s.length() != 0)) {
1175                 list.add(s);
1176             }
1177         } catch (IOException ex) {
1178             // return current list, possibly empty
1179         } finally {
1180             if (fstream != null) {
1181                 try {
1182                     fstream.close();
1183                 } catch (IOException ex) {}
1184             }
1185         }
1186
1187         return list;
1188     }
1189
1190     @Override
1191     public void setMtu(String iface, int mtu) {
1192         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1193
1194         final NativeDaemonEvent event;
1195         try {
1196             event = mConnector.execute("interface", "setmtu", iface, mtu);
1197         } catch (NativeDaemonConnectorException e) {
1198             throw e.rethrowAsParcelableException();
1199         }
1200     }
1201
1202     @Override
1203     public void shutdown() {
1204         // TODO: remove from aidl if nobody calls externally
1205         mContext.enforceCallingOrSelfPermission(SHUTDOWN, TAG);
1206
1207         Slog.i(TAG, "Shutting down");
1208     }
1209
1210     @Override
1211     public boolean getIpForwardingEnabled() throws IllegalStateException{
1212         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1213
1214         final NativeDaemonEvent event;
1215         try {
1216             event = mConnector.execute("ipfwd", "status");
1217         } catch (NativeDaemonConnectorException e) {
1218             throw e.rethrowAsParcelableException();
1219         }
1220
1221         // 211 Forwarding enabled
1222         event.checkCode(IpFwdStatusResult);
1223         return event.getMessage().endsWith("enabled");
1224     }
1225
1226     @Override
1227     public void setIpForwardingEnabled(boolean enable) {
1228         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1229         try {
1230             mConnector.execute("ipfwd", enable ? "enable" : "disable", "tethering");
1231         } catch (NativeDaemonConnectorException e) {
1232             throw e.rethrowAsParcelableException();
1233         }
1234     }
1235
1236     @Override
1237     public void startTethering(String[] dhcpRange) {
1238         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1239         // cmd is "tether start first_start first_stop second_start second_stop ..."
1240         // an odd number of addrs will fail
1241
1242         final Command cmd = new Command("tether", "start");
1243         for (String d : dhcpRange) {
1244             cmd.appendArg(d);
1245         }
1246
1247         try {
1248             mConnector.execute(cmd);
1249         } catch (NativeDaemonConnectorException e) {
1250             throw e.rethrowAsParcelableException();
1251         }
1252     }
1253
1254     @Override
1255     public void stopTethering() {
1256         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1257         try {
1258             mConnector.execute("tether", "stop");
1259         } catch (NativeDaemonConnectorException e) {
1260             throw e.rethrowAsParcelableException();
1261         }
1262     }
1263
1264     @Override
1265     public boolean isTetheringStarted() {
1266         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1267
1268         final NativeDaemonEvent event;
1269         try {
1270             event = mConnector.execute("tether", "status");
1271         } catch (NativeDaemonConnectorException e) {
1272             throw e.rethrowAsParcelableException();
1273         }
1274
1275         // 210 Tethering services started
1276         event.checkCode(TetherStatusResult);
1277         return event.getMessage().endsWith("started");
1278     }
1279
1280     @Override
1281     public void tetherInterface(String iface) {
1282         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1283         try {
1284             mConnector.execute("tether", "interface", "add", iface);
1285         } catch (NativeDaemonConnectorException e) {
1286             throw e.rethrowAsParcelableException();
1287         }
1288         List<RouteInfo> routes = new ArrayList<RouteInfo>();
1289         // The RouteInfo constructor truncates the LinkAddress to a network prefix, thus making it
1290         // suitable to use as a route destination.
1291         routes.add(new RouteInfo(getInterfaceConfig(iface).getLinkAddress(), null, iface));
1292         addInterfaceToLocalNetwork(iface, routes);
1293     }
1294
1295     @Override
1296     public void untetherInterface(String iface) {
1297         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1298         try {
1299             mConnector.execute("tether", "interface", "remove", iface);
1300         } catch (NativeDaemonConnectorException e) {
1301             throw e.rethrowAsParcelableException();
1302         }
1303         removeInterfaceFromLocalNetwork(iface);
1304     }
1305
1306     @Override
1307     public String[] listTetheredInterfaces() {
1308         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1309         try {
1310             return NativeDaemonEvent.filterMessageList(
1311                     mConnector.executeForList("tether", "interface", "list"),
1312                     TetherInterfaceListResult);
1313         } catch (NativeDaemonConnectorException e) {
1314             throw e.rethrowAsParcelableException();
1315         }
1316     }
1317
1318     @Override
1319     public void setDnsForwarders(Network network, String[] dns) {
1320         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1321
1322         int netId = (network != null) ? network.netId : ConnectivityManager.NETID_UNSET;
1323         final Command cmd = new Command("tether", "dns", "set", netId);
1324
1325         for (String s : dns) {
1326             cmd.appendArg(NetworkUtils.numericToInetAddress(s).getHostAddress());
1327         }
1328
1329         try {
1330             mConnector.execute(cmd);
1331         } catch (NativeDaemonConnectorException e) {
1332             throw e.rethrowAsParcelableException();
1333         }
1334     }
1335
1336     @Override
1337     public String[] getDnsForwarders() {
1338         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1339         try {
1340             return NativeDaemonEvent.filterMessageList(
1341                     mConnector.executeForList("tether", "dns", "list"), TetherDnsFwdTgtListResult);
1342         } catch (NativeDaemonConnectorException e) {
1343             throw e.rethrowAsParcelableException();
1344         }
1345     }
1346
1347     private List<InterfaceAddress> excludeLinkLocal(List<InterfaceAddress> addresses) {
1348         ArrayList<InterfaceAddress> filtered = new ArrayList<InterfaceAddress>(addresses.size());
1349         for (InterfaceAddress ia : addresses) {
1350             if (!ia.getAddress().isLinkLocalAddress())
1351                 filtered.add(ia);
1352         }
1353         return filtered;
1354     }
1355
1356     private void modifyInterfaceForward(boolean add, String fromIface, String toIface) {
1357         final Command cmd = new Command("ipfwd", add ? "add" : "remove", fromIface, toIface);
1358         try {
1359             mConnector.execute(cmd);
1360         } catch (NativeDaemonConnectorException e) {
1361             throw e.rethrowAsParcelableException();
1362         }
1363     }
1364
1365     @Override
1366     public void startInterfaceForwarding(String fromIface, String toIface) {
1367         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1368         modifyInterfaceForward(true, fromIface, toIface);
1369     }
1370
1371     @Override
1372     public void stopInterfaceForwarding(String fromIface, String toIface) {
1373         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1374         modifyInterfaceForward(false, fromIface, toIface);
1375     }
1376
1377     private void modifyNat(String action, String internalInterface, String externalInterface)
1378             throws SocketException {
1379         final Command cmd = new Command("nat", action, internalInterface, externalInterface);
1380
1381         final NetworkInterface internalNetworkInterface = NetworkInterface.getByName(
1382                 internalInterface);
1383         if (internalNetworkInterface == null) {
1384             cmd.appendArg("0");
1385         } else {
1386             // Don't touch link-local routes, as link-local addresses aren't routable,
1387             // kernel creates link-local routes on all interfaces automatically
1388             List<InterfaceAddress> interfaceAddresses = excludeLinkLocal(
1389                     internalNetworkInterface.getInterfaceAddresses());
1390             cmd.appendArg(interfaceAddresses.size());
1391             for (InterfaceAddress ia : interfaceAddresses) {
1392                 InetAddress addr = NetworkUtils.getNetworkPart(
1393                         ia.getAddress(), ia.getNetworkPrefixLength());
1394                 cmd.appendArg(addr.getHostAddress() + "/" + ia.getNetworkPrefixLength());
1395             }
1396         }
1397
1398         try {
1399             mConnector.execute(cmd);
1400         } catch (NativeDaemonConnectorException e) {
1401             throw e.rethrowAsParcelableException();
1402         }
1403     }
1404
1405     @Override
1406     public void enableNat(String internalInterface, String externalInterface) {
1407         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1408         try {
1409             modifyNat("enable", internalInterface, externalInterface);
1410         } catch (SocketException e) {
1411             throw new IllegalStateException(e);
1412         }
1413     }
1414
1415     @Override
1416     public void disableNat(String internalInterface, String externalInterface) {
1417         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1418         try {
1419             modifyNat("disable", internalInterface, externalInterface);
1420         } catch (SocketException e) {
1421             throw new IllegalStateException(e);
1422         }
1423     }
1424
1425     @Override
1426     public String[] listTtys() {
1427         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1428         try {
1429             return NativeDaemonEvent.filterMessageList(
1430                     mConnector.executeForList("list_ttys"), TtyListResult);
1431         } catch (NativeDaemonConnectorException e) {
1432             throw e.rethrowAsParcelableException();
1433         }
1434     }
1435
1436     @Override
1437     public void attachPppd(
1438             String tty, String localAddr, String remoteAddr, String dns1Addr, String dns2Addr) {
1439         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1440         try {
1441             mConnector.execute("pppd", "attach", tty,
1442                     NetworkUtils.numericToInetAddress(localAddr).getHostAddress(),
1443                     NetworkUtils.numericToInetAddress(remoteAddr).getHostAddress(),
1444                     NetworkUtils.numericToInetAddress(dns1Addr).getHostAddress(),
1445                     NetworkUtils.numericToInetAddress(dns2Addr).getHostAddress());
1446         } catch (NativeDaemonConnectorException e) {
1447             throw e.rethrowAsParcelableException();
1448         }
1449     }
1450
1451     @Override
1452     public void detachPppd(String tty) {
1453         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1454         try {
1455             mConnector.execute("pppd", "detach", tty);
1456         } catch (NativeDaemonConnectorException e) {
1457             throw e.rethrowAsParcelableException();
1458         }
1459     }
1460
1461     /**
1462      * Private method used to call execute for a command given the provided arguments.
1463      *
1464      * This function checks the returned NativeDaemonEvent for the provided expected response code
1465      * and message.  If either of these is not correct, an error is logged.
1466      *
1467      * @param String command The command to execute.
1468      * @param Object[] args If needed, arguments for the command to execute.
1469      * @param int expectedResponseCode The code expected to be returned in the corresponding event.
1470      * @param String expectedResponseMessage The message expected in the returned event.
1471      * @param String logMsg The message to log as an error (TAG will be applied).
1472      */
1473     private void executeOrLogWithMessage(String command, Object[] args,
1474             int expectedResponseCode, String expectedResponseMessage, String logMsg)
1475             throws NativeDaemonConnectorException {
1476         NativeDaemonEvent event = mConnector.execute(command, args);
1477         if (event.getCode() != expectedResponseCode
1478                 || !event.getMessage().equals(expectedResponseMessage)) {
1479             Log.e(TAG, logMsg + ": event = " + event);
1480         }
1481     }
1482
1483     @Override
1484     public void startAccessPoint(WifiConfiguration wifiConfig, String wlanIface) {
1485         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1486         Object[] args;
1487         String logMsg = "startAccessPoint Error setting up softap";
1488         try {
1489             if (wifiConfig == null) {
1490                 args = new Object[] {"set", wlanIface};
1491             } else {
1492                 args = new Object[] {"set", wlanIface, wifiConfig.SSID,
1493                         "broadcast", Integer.toString(wifiConfig.apChannel),
1494                         getSecurityType(wifiConfig), new SensitiveArg(wifiConfig.preSharedKey)};
1495             }
1496             executeOrLogWithMessage(SOFT_AP_COMMAND, args, NetdResponseCode.SoftapStatusResult,
1497                     SOFT_AP_COMMAND_SUCCESS, logMsg);
1498
1499             logMsg = "startAccessPoint Error starting softap";
1500             args = new Object[] {"startap"};
1501             executeOrLogWithMessage(SOFT_AP_COMMAND, args, NetdResponseCode.SoftapStatusResult,
1502                     SOFT_AP_COMMAND_SUCCESS, logMsg);
1503         } catch (NativeDaemonConnectorException e) {
1504             throw e.rethrowAsParcelableException();
1505         }
1506     }
1507
1508     private static String getSecurityType(WifiConfiguration wifiConfig) {
1509         switch (wifiConfig.getAuthType()) {
1510             case KeyMgmt.WPA_PSK:
1511                 return "wpa-psk";
1512             case KeyMgmt.WPA2_PSK:
1513                 return "wpa2-psk";
1514             default:
1515                 return "open";
1516         }
1517     }
1518
1519     /* @param mode can be "AP", "STA" or "P2P" */
1520     @Override
1521     public void wifiFirmwareReload(String wlanIface, String mode) {
1522         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1523         Object[] args = {"fwreload", wlanIface, mode};
1524         String logMsg = "wifiFirmwareReload Error reloading "
1525                 + wlanIface + " fw in " + mode + " mode";
1526         try {
1527             executeOrLogWithMessage(SOFT_AP_COMMAND, args, NetdResponseCode.SoftapStatusResult,
1528                     SOFT_AP_COMMAND_SUCCESS, logMsg);
1529         } catch (NativeDaemonConnectorException e) {
1530             throw e.rethrowAsParcelableException();
1531         }
1532
1533         // Ensure that before we return from this command, any asynchronous
1534         // notifications generated before the command completed have been
1535         // processed by all NetworkManagementEventObservers.
1536         mConnector.waitForCallbacks();
1537     }
1538
1539     @Override
1540     public void stopAccessPoint(String wlanIface) {
1541         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1542         Object[] args = {"stopap"};
1543         String logMsg = "stopAccessPoint Error stopping softap";
1544
1545         try {
1546             executeOrLogWithMessage(SOFT_AP_COMMAND, args, NetdResponseCode.SoftapStatusResult,
1547                     SOFT_AP_COMMAND_SUCCESS, logMsg);
1548             wifiFirmwareReload(wlanIface, "STA");
1549         } catch (NativeDaemonConnectorException e) {
1550             throw e.rethrowAsParcelableException();
1551         }
1552     }
1553
1554     @Override
1555     public void setAccessPoint(WifiConfiguration wifiConfig, String wlanIface) {
1556         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1557         Object[] args;
1558         String logMsg = "startAccessPoint Error setting up softap";
1559         try {
1560             if (wifiConfig == null) {
1561                 args = new Object[] {"set", wlanIface};
1562             } else {
1563                 // TODO: understand why this is set to "6" instead of
1564                 // Integer.toString(wifiConfig.apChannel) as in startAccessPoint
1565                 // TODO: should startAccessPoint call this instead of repeating code?
1566                 args = new Object[] {"set", wlanIface, wifiConfig.SSID,
1567                         "broadcast", "6",
1568                         getSecurityType(wifiConfig), new SensitiveArg(wifiConfig.preSharedKey)};
1569             }
1570             executeOrLogWithMessage(SOFT_AP_COMMAND, args, NetdResponseCode.SoftapStatusResult,
1571                     SOFT_AP_COMMAND_SUCCESS, logMsg);
1572         } catch (NativeDaemonConnectorException e) {
1573             throw e.rethrowAsParcelableException();
1574         }
1575     }
1576
1577     @Override
1578     public void addIdleTimer(String iface, int timeout, final int type) {
1579         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1580
1581         if (DBG) Slog.d(TAG, "Adding idletimer");
1582
1583         synchronized (mIdleTimerLock) {
1584             IdleTimerParams params = mActiveIdleTimers.get(iface);
1585             if (params != null) {
1586                 // the interface already has idletimer, update network count
1587                 params.networkCount++;
1588                 return;
1589             }
1590
1591             try {
1592                 mConnector.execute("idletimer", "add", iface, Integer.toString(timeout),
1593                         Integer.toString(type));
1594             } catch (NativeDaemonConnectorException e) {
1595                 throw e.rethrowAsParcelableException();
1596             }
1597             mActiveIdleTimers.put(iface, new IdleTimerParams(timeout, type));
1598
1599             // Networks start up.
1600             if (ConnectivityManager.isNetworkTypeMobile(type)) {
1601                 mNetworkActive = false;
1602             }
1603             mDaemonHandler.post(new Runnable() {
1604                 @Override public void run() {
1605                     notifyInterfaceClassActivity(type,
1606                             DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH,
1607                             SystemClock.elapsedRealtimeNanos(), -1, false);
1608                 }
1609             });
1610         }
1611     }
1612
1613     @Override
1614     public void removeIdleTimer(String iface) {
1615         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1616
1617         if (DBG) Slog.d(TAG, "Removing idletimer");
1618
1619         synchronized (mIdleTimerLock) {
1620             final IdleTimerParams params = mActiveIdleTimers.get(iface);
1621             if (params == null || --(params.networkCount) > 0) {
1622                 return;
1623             }
1624
1625             try {
1626                 mConnector.execute("idletimer", "remove", iface,
1627                         Integer.toString(params.timeout), Integer.toString(params.type));
1628             } catch (NativeDaemonConnectorException e) {
1629                 throw e.rethrowAsParcelableException();
1630             }
1631             mActiveIdleTimers.remove(iface);
1632             mDaemonHandler.post(new Runnable() {
1633                 @Override public void run() {
1634                     notifyInterfaceClassActivity(params.type,
1635                             DataConnectionRealTimeInfo.DC_POWER_STATE_LOW,
1636                             SystemClock.elapsedRealtimeNanos(), -1, false);
1637                 }
1638             });
1639         }
1640     }
1641
1642     @Override
1643     public NetworkStats getNetworkStatsSummaryDev() {
1644         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1645         try {
1646             return mStatsFactory.readNetworkStatsSummaryDev();
1647         } catch (IOException e) {
1648             throw new IllegalStateException(e);
1649         }
1650     }
1651
1652     @Override
1653     public NetworkStats getNetworkStatsSummaryXt() {
1654         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1655         try {
1656             return mStatsFactory.readNetworkStatsSummaryXt();
1657         } catch (IOException e) {
1658             throw new IllegalStateException(e);
1659         }
1660     }
1661
1662     @Override
1663     public NetworkStats getNetworkStatsDetail() {
1664         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1665         try {
1666             return mStatsFactory.readNetworkStatsDetail(UID_ALL, null, TAG_ALL, null);
1667         } catch (IOException e) {
1668             throw new IllegalStateException(e);
1669         }
1670     }
1671
1672     @Override
1673     public void setInterfaceQuota(String iface, long quotaBytes) {
1674         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1675
1676         // silently discard when control disabled
1677         // TODO: eventually migrate to be always enabled
1678         if (!mBandwidthControlEnabled) return;
1679
1680         synchronized (mQuotaLock) {
1681             if (mActiveQuotas.containsKey(iface)) {
1682                 throw new IllegalStateException("iface " + iface + " already has quota");
1683             }
1684
1685             try {
1686                 // TODO: support quota shared across interfaces
1687                 mConnector.execute("bandwidth", "setiquota", iface, quotaBytes);
1688                 mActiveQuotas.put(iface, quotaBytes);
1689             } catch (NativeDaemonConnectorException e) {
1690                 throw e.rethrowAsParcelableException();
1691             }
1692         }
1693     }
1694
1695     @Override
1696     public void removeInterfaceQuota(String iface) {
1697         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1698
1699         // silently discard when control disabled
1700         // TODO: eventually migrate to be always enabled
1701         if (!mBandwidthControlEnabled) return;
1702
1703         synchronized (mQuotaLock) {
1704             if (!mActiveQuotas.containsKey(iface)) {
1705                 // TODO: eventually consider throwing
1706                 return;
1707             }
1708
1709             mActiveQuotas.remove(iface);
1710             mActiveAlerts.remove(iface);
1711
1712             try {
1713                 // TODO: support quota shared across interfaces
1714                 mConnector.execute("bandwidth", "removeiquota", iface);
1715             } catch (NativeDaemonConnectorException e) {
1716                 throw e.rethrowAsParcelableException();
1717             }
1718         }
1719     }
1720
1721     @Override
1722     public void setInterfaceAlert(String iface, long alertBytes) {
1723         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1724
1725         // silently discard when control disabled
1726         // TODO: eventually migrate to be always enabled
1727         if (!mBandwidthControlEnabled) return;
1728
1729         // quick sanity check
1730         if (!mActiveQuotas.containsKey(iface)) {
1731             throw new IllegalStateException("setting alert requires existing quota on iface");
1732         }
1733
1734         synchronized (mQuotaLock) {
1735             if (mActiveAlerts.containsKey(iface)) {
1736                 throw new IllegalStateException("iface " + iface + " already has alert");
1737             }
1738
1739             try {
1740                 // TODO: support alert shared across interfaces
1741                 mConnector.execute("bandwidth", "setinterfacealert", iface, alertBytes);
1742                 mActiveAlerts.put(iface, alertBytes);
1743             } catch (NativeDaemonConnectorException e) {
1744                 throw e.rethrowAsParcelableException();
1745             }
1746         }
1747     }
1748
1749     @Override
1750     public void removeInterfaceAlert(String iface) {
1751         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1752
1753         // silently discard when control disabled
1754         // TODO: eventually migrate to be always enabled
1755         if (!mBandwidthControlEnabled) return;
1756
1757         synchronized (mQuotaLock) {
1758             if (!mActiveAlerts.containsKey(iface)) {
1759                 // TODO: eventually consider throwing
1760                 return;
1761             }
1762
1763             try {
1764                 // TODO: support alert shared across interfaces
1765                 mConnector.execute("bandwidth", "removeinterfacealert", iface);
1766                 mActiveAlerts.remove(iface);
1767             } catch (NativeDaemonConnectorException e) {
1768                 throw e.rethrowAsParcelableException();
1769             }
1770         }
1771     }
1772
1773     @Override
1774     public void setGlobalAlert(long alertBytes) {
1775         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1776
1777         // silently discard when control disabled
1778         // TODO: eventually migrate to be always enabled
1779         if (!mBandwidthControlEnabled) return;
1780
1781         try {
1782             mConnector.execute("bandwidth", "setglobalalert", alertBytes);
1783         } catch (NativeDaemonConnectorException e) {
1784             throw e.rethrowAsParcelableException();
1785         }
1786     }
1787
1788     private void setUidOnMeteredNetworkList(SparseBooleanArray quotaList, int uid,
1789             boolean blacklist, boolean enable) {
1790         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1791
1792         // silently discard when control disabled
1793         // TODO: eventually migrate to be always enabled
1794         if (!mBandwidthControlEnabled) return;
1795
1796         final String chain = blacklist ? "naughtyapps" : "niceapps";
1797         final String suffix = enable ? "add" : "remove";
1798
1799         synchronized (mQuotaLock) {
1800             final boolean oldEnable = quotaList.get(uid, false);
1801             if (oldEnable == enable) {
1802                 // TODO: eventually consider throwing
1803                 return;
1804             }
1805
1806             try {
1807                 mConnector.execute("bandwidth", suffix + chain, uid);
1808                 if (enable) {
1809                     quotaList.put(uid, true);
1810                 } else {
1811                     quotaList.delete(uid);
1812                 }
1813             } catch (NativeDaemonConnectorException e) {
1814                 throw e.rethrowAsParcelableException();
1815             }
1816         }
1817     }
1818
1819     @Override
1820     public void setUidMeteredNetworkBlacklist(int uid, boolean enable) {
1821         setUidOnMeteredNetworkList(mUidRejectOnMetered, uid, true, enable);
1822     }
1823
1824     @Override
1825     public void setUidMeteredNetworkWhitelist(int uid, boolean enable) {
1826         setUidOnMeteredNetworkList(mUidAllowOnMetered, uid, false, enable);
1827     }
1828
1829     @Override
1830     public boolean setDataSaverModeEnabled(boolean enable) {
1831         if (DBG) Log.d(TAG, "setDataSaverMode: " + enable);
1832         synchronized (mQuotaLock) {
1833             if (mDataSaverMode == enable) {
1834                 Log.w(TAG, "setDataSaverMode(): already " + mDataSaverMode);
1835                 return true;
1836             }
1837             try {
1838                 final boolean changed = mNetdService.bandwidthEnableDataSaver(enable);
1839                 if (changed) {
1840                     mDataSaverMode = enable;
1841                 } else {
1842                     Log.w(TAG, "setDataSaverMode(" + enable + "): netd command silently failed");
1843                 }
1844                 return changed;
1845             } catch (RemoteException e) {
1846                 Log.w(TAG, "setDataSaverMode(" + enable + "): netd command failed", e);
1847                 return false;
1848             }
1849         }
1850     }
1851
1852     @Override
1853     public void setAllowOnlyVpnForUids(boolean add, UidRange[] uidRanges)
1854             throws ServiceSpecificException {
1855         try {
1856             mNetdService.networkRejectNonSecureVpn(add, uidRanges);
1857         } catch (ServiceSpecificException e) {
1858             Log.w(TAG, "setAllowOnlyVpnForUids(" + add + ", " + Arrays.toString(uidRanges) + ")"
1859                     + ": netd command failed", e);
1860             throw e;
1861         } catch (RemoteException e) {
1862             Log.w(TAG, "setAllowOnlyVpnForUids(" + add + ", " + Arrays.toString(uidRanges) + ")"
1863                     + ": netd command failed", e);
1864             throw e.rethrowAsRuntimeException();
1865         }
1866     }
1867
1868     @Override
1869     public void setUidCleartextNetworkPolicy(int uid, int policy) {
1870         if (Binder.getCallingUid() != uid) {
1871             mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1872         }
1873
1874         synchronized (mQuotaLock) {
1875             final int oldPolicy = mUidCleartextPolicy.get(uid, StrictMode.NETWORK_POLICY_ACCEPT);
1876             if (oldPolicy == policy) {
1877                 return;
1878             }
1879
1880             if (!mStrictEnabled) {
1881                 // Module isn't enabled yet; stash the requested policy away to
1882                 // apply later once the daemon is connected.
1883                 mUidCleartextPolicy.put(uid, policy);
1884                 return;
1885             }
1886
1887             final String policyString;
1888             switch (policy) {
1889                 case StrictMode.NETWORK_POLICY_ACCEPT:
1890                     policyString = "accept";
1891                     break;
1892                 case StrictMode.NETWORK_POLICY_LOG:
1893                     policyString = "log";
1894                     break;
1895                 case StrictMode.NETWORK_POLICY_REJECT:
1896                     policyString = "reject";
1897                     break;
1898                 default:
1899                     throw new IllegalArgumentException("Unknown policy " + policy);
1900             }
1901
1902             try {
1903                 mConnector.execute("strict", "set_uid_cleartext_policy", uid, policyString);
1904                 mUidCleartextPolicy.put(uid, policy);
1905             } catch (NativeDaemonConnectorException e) {
1906                 throw e.rethrowAsParcelableException();
1907             }
1908         }
1909     }
1910
1911     @Override
1912     public boolean isBandwidthControlEnabled() {
1913         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1914         return mBandwidthControlEnabled;
1915     }
1916
1917     @Override
1918     public NetworkStats getNetworkStatsUidDetail(int uid) {
1919         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1920         try {
1921             return mStatsFactory.readNetworkStatsDetail(uid, null, TAG_ALL, null);
1922         } catch (IOException e) {
1923             throw new IllegalStateException(e);
1924         }
1925     }
1926
1927     @Override
1928     public NetworkStats getNetworkStatsTethering() {
1929         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1930
1931         final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1);
1932         try {
1933             final NativeDaemonEvent[] events = mConnector.executeForList(
1934                     "bandwidth", "gettetherstats");
1935             for (NativeDaemonEvent event : events) {
1936                 if (event.getCode() != TetheringStatsListResult) continue;
1937
1938                 // 114 ifaceIn ifaceOut rx_bytes rx_packets tx_bytes tx_packets
1939                 final StringTokenizer tok = new StringTokenizer(event.getMessage());
1940                 try {
1941                     final String ifaceIn = tok.nextToken();
1942                     final String ifaceOut = tok.nextToken();
1943
1944                     final NetworkStats.Entry entry = new NetworkStats.Entry();
1945                     entry.iface = ifaceOut;
1946                     entry.uid = UID_TETHERING;
1947                     entry.set = SET_DEFAULT;
1948                     entry.tag = TAG_NONE;
1949                     entry.rxBytes = Long.parseLong(tok.nextToken());
1950                     entry.rxPackets = Long.parseLong(tok.nextToken());
1951                     entry.txBytes = Long.parseLong(tok.nextToken());
1952                     entry.txPackets = Long.parseLong(tok.nextToken());
1953                     stats.combineValues(entry);
1954                 } catch (NoSuchElementException e) {
1955                     throw new IllegalStateException("problem parsing tethering stats: " + event);
1956                 } catch (NumberFormatException e) {
1957                     throw new IllegalStateException("problem parsing tethering stats: " + event);
1958                 }
1959             }
1960         } catch (NativeDaemonConnectorException e) {
1961             throw e.rethrowAsParcelableException();
1962         }
1963         return stats;
1964     }
1965
1966     @Override
1967     public void setDnsConfigurationForNetwork(int netId, String[] servers, String domains) {
1968         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
1969
1970         ContentResolver resolver = mContext.getContentResolver();
1971
1972         int sampleValidity = Settings.Global.getInt(resolver,
1973                 Settings.Global.DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS,
1974                 DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS);
1975         if (sampleValidity < 0 || sampleValidity > 65535) {
1976             Slog.w(TAG, "Invalid sampleValidity=" + sampleValidity + ", using default=" +
1977                     DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS);
1978             sampleValidity = DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS;
1979         }
1980
1981         int successThreshold = Settings.Global.getInt(resolver,
1982                 Settings.Global.DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT,
1983                 DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT);
1984         if (successThreshold < 0 || successThreshold > 100) {
1985             Slog.w(TAG, "Invalid successThreshold=" + successThreshold + ", using default=" +
1986                     DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT);
1987             successThreshold = DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT;
1988         }
1989
1990         int minSamples = Settings.Global.getInt(resolver,
1991                 Settings.Global.DNS_RESOLVER_MIN_SAMPLES, DNS_RESOLVER_DEFAULT_MIN_SAMPLES);
1992         int maxSamples = Settings.Global.getInt(resolver,
1993                 Settings.Global.DNS_RESOLVER_MAX_SAMPLES, DNS_RESOLVER_DEFAULT_MAX_SAMPLES);
1994         if (minSamples < 0 || minSamples > maxSamples || maxSamples > 64) {
1995             Slog.w(TAG, "Invalid sample count (min, max)=(" + minSamples + ", " + maxSamples +
1996                     "), using default=(" + DNS_RESOLVER_DEFAULT_MIN_SAMPLES + ", " +
1997                     DNS_RESOLVER_DEFAULT_MAX_SAMPLES + ")");
1998             minSamples = DNS_RESOLVER_DEFAULT_MIN_SAMPLES;
1999             maxSamples = DNS_RESOLVER_DEFAULT_MAX_SAMPLES;
2000         }
2001
2002         final String[] domainStrs = domains == null ? new String[0] : domains.split(" ");
2003         final int[] params = { sampleValidity, successThreshold, minSamples, maxSamples };
2004         try {
2005             mNetdService.setResolverConfiguration(netId, servers, domainStrs, params);
2006         } catch (RemoteException e) {
2007             throw new RuntimeException(e);
2008         }
2009     }
2010
2011     @Override
2012     public void setDnsServersForNetwork(int netId, String[] servers, String domains) {
2013         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2014
2015         Command cmd;
2016         if (servers.length > 0) {
2017             cmd = new Command("resolver", "setnetdns", netId,
2018                     (domains == null ? "" : domains));
2019             for (String s : servers) {
2020                 InetAddress a = NetworkUtils.numericToInetAddress(s);
2021                 if (a.isAnyLocalAddress() == false) {
2022                     cmd.appendArg(a.getHostAddress());
2023                 }
2024             }
2025         } else {
2026             cmd = new Command("resolver", "clearnetdns", netId);
2027         }
2028
2029         try {
2030             mConnector.execute(cmd);
2031         } catch (NativeDaemonConnectorException e) {
2032             throw e.rethrowAsParcelableException();
2033         }
2034     }
2035
2036     @Override
2037     public void addVpnUidRanges(int netId, UidRange[] ranges) {
2038         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2039         Object[] argv = new Object[3 + MAX_UID_RANGES_PER_COMMAND];
2040         argv[0] = "users";
2041         argv[1] = "add";
2042         argv[2] = netId;
2043         int argc = 3;
2044         // Avoid overly long commands by limiting number of UID ranges per command.
2045         for (int i = 0; i < ranges.length; i++) {
2046             argv[argc++] = ranges[i].toString();
2047             if (i == (ranges.length - 1) || argc == argv.length) {
2048                 try {
2049                     mConnector.execute("network", Arrays.copyOf(argv, argc));
2050                 } catch (NativeDaemonConnectorException e) {
2051                     throw e.rethrowAsParcelableException();
2052                 }
2053                 argc = 3;
2054             }
2055         }
2056     }
2057
2058     @Override
2059     public void removeVpnUidRanges(int netId, UidRange[] ranges) {
2060         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2061         Object[] argv = new Object[3 + MAX_UID_RANGES_PER_COMMAND];
2062         argv[0] = "users";
2063         argv[1] = "remove";
2064         argv[2] = netId;
2065         int argc = 3;
2066         // Avoid overly long commands by limiting number of UID ranges per command.
2067         for (int i = 0; i < ranges.length; i++) {
2068             argv[argc++] = ranges[i].toString();
2069             if (i == (ranges.length - 1) || argc == argv.length) {
2070                 try {
2071                     mConnector.execute("network", Arrays.copyOf(argv, argc));
2072                 } catch (NativeDaemonConnectorException e) {
2073                     throw e.rethrowAsParcelableException();
2074                 }
2075                 argc = 3;
2076             }
2077         }
2078     }
2079
2080     @Override
2081     public void setFirewallEnabled(boolean enabled) {
2082         enforceSystemUid();
2083         try {
2084             mConnector.execute("firewall", "enable", enabled ? "whitelist" : "blacklist");
2085             mFirewallEnabled = enabled;
2086         } catch (NativeDaemonConnectorException e) {
2087             throw e.rethrowAsParcelableException();
2088         }
2089     }
2090
2091     @Override
2092     public boolean isFirewallEnabled() {
2093         enforceSystemUid();
2094         return mFirewallEnabled;
2095     }
2096
2097     @Override
2098     public void setFirewallInterfaceRule(String iface, boolean allow) {
2099         enforceSystemUid();
2100         Preconditions.checkState(mFirewallEnabled);
2101         final String rule = allow ? "allow" : "deny";
2102         try {
2103             mConnector.execute("firewall", "set_interface_rule", iface, rule);
2104         } catch (NativeDaemonConnectorException e) {
2105             throw e.rethrowAsParcelableException();
2106         }
2107     }
2108
2109     @Override
2110     public void setFirewallEgressSourceRule(String addr, boolean allow) {
2111         enforceSystemUid();
2112         Preconditions.checkState(mFirewallEnabled);
2113         final String rule = allow ? "allow" : "deny";
2114         try {
2115             mConnector.execute("firewall", "set_egress_source_rule", addr, rule);
2116         } catch (NativeDaemonConnectorException e) {
2117             throw e.rethrowAsParcelableException();
2118         }
2119     }
2120
2121     @Override
2122     public void setFirewallEgressDestRule(String addr, int port, boolean allow) {
2123         enforceSystemUid();
2124         Preconditions.checkState(mFirewallEnabled);
2125         final String rule = allow ? "allow" : "deny";
2126         try {
2127             mConnector.execute("firewall", "set_egress_dest_rule", addr, port, rule);
2128         } catch (NativeDaemonConnectorException e) {
2129             throw e.rethrowAsParcelableException();
2130         }
2131     }
2132
2133     private void closeSocketsForFirewallChainLocked(int chain, String chainName) {
2134         // UID ranges to close sockets on.
2135         UidRange[] ranges;
2136         // UID ranges whose sockets we won't touch.
2137         int[] exemptUids;
2138
2139         final SparseIntArray rules = getUidFirewallRules(chain);
2140         int numUids = 0;
2141
2142         if (getFirewallType(chain) == FIREWALL_TYPE_WHITELIST) {
2143             // Close all sockets on all non-system UIDs...
2144             ranges = new UidRange[] {
2145                 // TODO: is there a better way of finding all existing users? If so, we could
2146                 // specify their ranges here.
2147                 new UidRange(Process.FIRST_APPLICATION_UID, Integer.MAX_VALUE),
2148             };
2149             // ... except for the UIDs that have allow rules.
2150             exemptUids = new int[rules.size()];
2151             for (int i = 0; i < exemptUids.length; i++) {
2152                 if (rules.valueAt(i) == NetworkPolicyManager.FIREWALL_RULE_ALLOW) {
2153                     exemptUids[numUids] = rules.keyAt(i);
2154                     numUids++;
2155                 }
2156             }
2157             // Normally, whitelist chains only contain deny rules, so numUids == exemptUids.length.
2158             // But the code does not guarantee this in any way, and at least in one case - if we add
2159             // a UID rule to the firewall, and then disable the firewall - the chains can contain
2160             // the wrong type of rule. In this case, don't close connections that we shouldn't.
2161             //
2162             // TODO: tighten up this code by ensuring we never set the wrong type of rule, and
2163             // fix setFirewallEnabled to grab mQuotaLock and clear rules.
2164             if (numUids != exemptUids.length) {
2165                 exemptUids = Arrays.copyOf(exemptUids, numUids);
2166             }
2167         } else {
2168             // Close sockets for every UID that has a deny rule...
2169             ranges = new UidRange[rules.size()];
2170             for (int i = 0; i < ranges.length; i++) {
2171                 if (rules.valueAt(i) == NetworkPolicyManager.FIREWALL_RULE_DENY) {
2172                     int uid = rules.keyAt(i);
2173                     ranges[numUids] = new UidRange(uid, uid);
2174                     numUids++;
2175                 }
2176             }
2177             // As above; usually numUids == ranges.length, but not always.
2178             if (numUids != ranges.length) {
2179                 ranges = Arrays.copyOf(ranges, numUids);
2180             }
2181             // ... with no exceptions.
2182             exemptUids = new int[0];
2183         }
2184
2185         try {
2186             mNetdService.socketDestroy(ranges, exemptUids);
2187         } catch(RemoteException | ServiceSpecificException e) {
2188             Slog.e(TAG, "Error closing sockets after enabling chain " + chainName + ": " + e);
2189         }
2190     }
2191
2192     @Override
2193     public void setFirewallChainEnabled(int chain, boolean enable) {
2194         enforceSystemUid();
2195         synchronized (mQuotaLock) {
2196             if (mFirewallChainStates.get(chain) == enable) {
2197                 // All is the same, nothing to do.  This relies on the fact that netd has child
2198                 // chains default detached.
2199                 return;
2200             }
2201             mFirewallChainStates.put(chain, enable);
2202
2203             final String operation = enable ? "enable_chain" : "disable_chain";
2204             final String chainName;
2205             switch(chain) {
2206                 case FIREWALL_CHAIN_STANDBY:
2207                     chainName = FIREWALL_CHAIN_NAME_STANDBY;
2208                     break;
2209                 case FIREWALL_CHAIN_DOZABLE:
2210                     chainName = FIREWALL_CHAIN_NAME_DOZABLE;
2211                     break;
2212                 case FIREWALL_CHAIN_POWERSAVE:
2213                     chainName = FIREWALL_CHAIN_NAME_POWERSAVE;
2214                     break;
2215                 default:
2216                     throw new IllegalArgumentException("Bad child chain: " + chain);
2217             }
2218
2219             try {
2220                 mConnector.execute("firewall", operation, chainName);
2221             } catch (NativeDaemonConnectorException e) {
2222                 throw e.rethrowAsParcelableException();
2223             }
2224
2225             // Close any sockets that were opened by the affected UIDs. This has to be done after
2226             // disabling network connectivity, in case they react to the socket close by reopening
2227             // the connection and race with the iptables commands that enable the firewall. All
2228             // whitelist and blacklist chains allow RSTs through.
2229             if (enable) {
2230                 if (DBG) Slog.d(TAG, "Closing sockets after enabling chain " + chainName);
2231                 closeSocketsForFirewallChainLocked(chain, chainName);
2232             }
2233         }
2234     }
2235
2236     private int getFirewallType(int chain) {
2237         switch (chain) {
2238             case FIREWALL_CHAIN_STANDBY:
2239                 return FIREWALL_TYPE_BLACKLIST;
2240             case FIREWALL_CHAIN_DOZABLE:
2241                 return FIREWALL_TYPE_WHITELIST;
2242             case FIREWALL_CHAIN_POWERSAVE:
2243                 return FIREWALL_TYPE_WHITELIST;
2244             default:
2245                 return isFirewallEnabled() ? FIREWALL_TYPE_WHITELIST : FIREWALL_TYPE_BLACKLIST;
2246         }
2247     }
2248
2249     @Override
2250     public void setFirewallUidRules(int chain, int[] uids, int[] rules) {
2251         enforceSystemUid();
2252         synchronized (mQuotaLock) {
2253             SparseIntArray uidFirewallRules = getUidFirewallRules(chain);
2254             SparseIntArray newRules = new SparseIntArray();
2255             // apply new set of rules
2256             for (int index = uids.length - 1; index >= 0; --index) {
2257                 int uid = uids[index];
2258                 int rule = rules[index];
2259                 updateFirewallUidRuleLocked(chain, uid, rule);
2260                 newRules.put(uid, rule);
2261             }
2262             // collect the rules to remove.
2263             SparseIntArray rulesToRemove = new SparseIntArray();
2264             for (int index = uidFirewallRules.size() - 1; index >= 0; --index) {
2265                 int uid = uidFirewallRules.keyAt(index);
2266                 if (newRules.indexOfKey(uid) < 0) {
2267                     rulesToRemove.put(uid, FIREWALL_RULE_DEFAULT);
2268                 }
2269             }
2270             // remove dead rules
2271             for (int index = rulesToRemove.size() - 1; index >= 0; --index) {
2272                 int uid = rulesToRemove.keyAt(index);
2273                 updateFirewallUidRuleLocked(chain, uid, FIREWALL_RULE_DEFAULT);
2274             }
2275             try {
2276                 switch (chain) {
2277                     case FIREWALL_CHAIN_DOZABLE:
2278                         mNetdService.firewallReplaceUidChain("fw_dozable", true, uids);
2279                         break;
2280                     case FIREWALL_CHAIN_STANDBY:
2281                         mNetdService.firewallReplaceUidChain("fw_standby", false, uids);
2282                         break;
2283                     case FIREWALL_CHAIN_POWERSAVE:
2284                         mNetdService.firewallReplaceUidChain("fw_powersave", true, uids);
2285                         break;
2286                     case FIREWALL_CHAIN_NONE:
2287                     default:
2288                         Slog.d(TAG, "setFirewallUidRules() called on invalid chain: " + chain);
2289                 }
2290             } catch (RemoteException e) {
2291                 Slog.w(TAG, "Error flushing firewall chain " + chain, e);
2292             }
2293         }
2294     }
2295
2296     @Override
2297     public void setFirewallUidRule(int chain, int uid, int rule) {
2298         enforceSystemUid();
2299         synchronized (mQuotaLock) {
2300             setFirewallUidRuleLocked(chain, uid, rule);
2301         }
2302     }
2303
2304     private void setFirewallUidRuleLocked(int chain, int uid, int rule) {
2305         if (updateFirewallUidRuleLocked(chain, uid, rule)) {
2306             try {
2307                 mConnector.execute("firewall", "set_uid_rule", getFirewallChainName(chain), uid,
2308                         getFirewallRuleName(chain, rule));
2309             } catch (NativeDaemonConnectorException e) {
2310                 throw e.rethrowAsParcelableException();
2311             }
2312         }
2313     }
2314
2315     // TODO: now that netd supports batching, NMS should not keep these data structures anymore...
2316     private boolean updateFirewallUidRuleLocked(int chain, int uid, int rule) {
2317         SparseIntArray uidFirewallRules = getUidFirewallRules(chain);
2318
2319         final int oldUidFirewallRule = uidFirewallRules.get(uid, FIREWALL_RULE_DEFAULT);
2320         if (DBG) {
2321             Slog.d(TAG, "oldRule = " + oldUidFirewallRule
2322                     + ", newRule=" + rule + " for uid=" + uid + " on chain " + chain);
2323         }
2324         if (oldUidFirewallRule == rule) {
2325             if (DBG) Slog.d(TAG, "!!!!! Skipping change");
2326             // TODO: eventually consider throwing
2327             return false;
2328         }
2329
2330         String ruleName = getFirewallRuleName(chain, rule);
2331         String oldRuleName = getFirewallRuleName(chain, oldUidFirewallRule);
2332
2333         if (rule == NetworkPolicyManager.FIREWALL_RULE_DEFAULT) {
2334             uidFirewallRules.delete(uid);
2335         } else {
2336             uidFirewallRules.put(uid, rule);
2337         }
2338         return !ruleName.equals(oldRuleName);
2339     }
2340
2341     private @NonNull String getFirewallRuleName(int chain, int rule) {
2342         String ruleName;
2343         if (getFirewallType(chain) == FIREWALL_TYPE_WHITELIST) {
2344             if (rule == NetworkPolicyManager.FIREWALL_RULE_ALLOW) {
2345                 ruleName = "allow";
2346             } else {
2347                 ruleName = "deny";
2348             }
2349         } else { // Blacklist mode
2350             if (rule == NetworkPolicyManager.FIREWALL_RULE_DENY) {
2351                 ruleName = "deny";
2352             } else {
2353                 ruleName = "allow";
2354             }
2355         }
2356         return ruleName;
2357     }
2358
2359     private @NonNull SparseIntArray getUidFirewallRules(int chain) {
2360         switch (chain) {
2361             case FIREWALL_CHAIN_STANDBY:
2362                 return mUidFirewallStandbyRules;
2363             case FIREWALL_CHAIN_DOZABLE:
2364                 return mUidFirewallDozableRules;
2365             case FIREWALL_CHAIN_POWERSAVE:
2366                 return mUidFirewallPowerSaveRules;
2367             case FIREWALL_CHAIN_NONE:
2368                 return mUidFirewallRules;
2369             default:
2370                 throw new IllegalArgumentException("Unknown chain:" + chain);
2371         }
2372     }
2373
2374     public @NonNull String getFirewallChainName(int chain) {
2375         switch (chain) {
2376             case FIREWALL_CHAIN_STANDBY:
2377                 return FIREWALL_CHAIN_NAME_STANDBY;
2378             case FIREWALL_CHAIN_DOZABLE:
2379                 return FIREWALL_CHAIN_NAME_DOZABLE;
2380             case FIREWALL_CHAIN_POWERSAVE:
2381                 return FIREWALL_CHAIN_NAME_POWERSAVE;
2382             case FIREWALL_CHAIN_NONE:
2383                 return FIREWALL_CHAIN_NAME_NONE;
2384             default:
2385                 throw new IllegalArgumentException("Unknown chain:" + chain);
2386         }
2387     }
2388
2389     private static void enforceSystemUid() {
2390         final int uid = Binder.getCallingUid();
2391         if (uid != Process.SYSTEM_UID) {
2392             throw new SecurityException("Only available to AID_SYSTEM");
2393         }
2394     }
2395
2396     @Override
2397     public void startClatd(String interfaceName) throws IllegalStateException {
2398         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2399
2400         try {
2401             mConnector.execute("clatd", "start", interfaceName);
2402         } catch (NativeDaemonConnectorException e) {
2403             throw e.rethrowAsParcelableException();
2404         }
2405     }
2406
2407     @Override
2408     public void stopClatd(String interfaceName) throws IllegalStateException {
2409         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2410
2411         try {
2412             mConnector.execute("clatd", "stop", interfaceName);
2413         } catch (NativeDaemonConnectorException e) {
2414             throw e.rethrowAsParcelableException();
2415         }
2416     }
2417
2418     @Override
2419     public boolean isClatdStarted(String interfaceName) {
2420         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2421
2422         final NativeDaemonEvent event;
2423         try {
2424             event = mConnector.execute("clatd", "status", interfaceName);
2425         } catch (NativeDaemonConnectorException e) {
2426             throw e.rethrowAsParcelableException();
2427         }
2428
2429         event.checkCode(ClatdStatusResult);
2430         return event.getMessage().endsWith("started");
2431     }
2432
2433     @Override
2434     public void registerNetworkActivityListener(INetworkActivityListener listener) {
2435         mNetworkActivityListeners.register(listener);
2436     }
2437
2438     @Override
2439     public void unregisterNetworkActivityListener(INetworkActivityListener listener) {
2440         mNetworkActivityListeners.unregister(listener);
2441     }
2442
2443     @Override
2444     public boolean isNetworkActive() {
2445         synchronized (mNetworkActivityListeners) {
2446             return mNetworkActive || mActiveIdleTimers.isEmpty();
2447         }
2448     }
2449
2450     private void reportNetworkActive() {
2451         final int length = mNetworkActivityListeners.beginBroadcast();
2452         try {
2453             for (int i = 0; i < length; i++) {
2454                 try {
2455                     mNetworkActivityListeners.getBroadcastItem(i).onNetworkActive();
2456                 } catch (RemoteException | RuntimeException e) {
2457                 }
2458             }
2459         } finally {
2460             mNetworkActivityListeners.finishBroadcast();
2461         }
2462     }
2463
2464     /** {@inheritDoc} */
2465     @Override
2466     public void monitor() {
2467         if (mConnector != null) {
2468             mConnector.monitor();
2469         }
2470     }
2471
2472     @Override
2473     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2474         mContext.enforceCallingOrSelfPermission(DUMP, TAG);
2475
2476         pw.println("NetworkManagementService NativeDaemonConnector Log:");
2477         mConnector.dump(fd, pw, args);
2478         pw.println();
2479
2480         pw.print("Bandwidth control enabled: "); pw.println(mBandwidthControlEnabled);
2481         pw.print("mMobileActivityFromRadio="); pw.print(mMobileActivityFromRadio);
2482                 pw.print(" mLastPowerStateFromRadio="); pw.println(mLastPowerStateFromRadio);
2483         pw.print("mNetworkActive="); pw.println(mNetworkActive);
2484
2485         synchronized (mQuotaLock) {
2486             pw.print("Active quota ifaces: "); pw.println(mActiveQuotas.toString());
2487             pw.print("Active alert ifaces: "); pw.println(mActiveAlerts.toString());
2488             pw.print("Data saver mode: "); pw.println(mDataSaverMode);
2489             dumpUidRuleOnQuotaLocked(pw, "blacklist", mUidRejectOnMetered);
2490             dumpUidRuleOnQuotaLocked(pw, "whitelist", mUidAllowOnMetered);
2491         }
2492
2493         synchronized (mUidFirewallRules) {
2494             dumpUidFirewallRule(pw, "", mUidFirewallRules);
2495         }
2496
2497         pw.print("UID firewall standby chain enabled: "); pw.println(
2498                 mFirewallChainStates.get(FIREWALL_CHAIN_STANDBY));
2499         synchronized (mUidFirewallStandbyRules) {
2500             dumpUidFirewallRule(pw, FIREWALL_CHAIN_NAME_STANDBY, mUidFirewallStandbyRules);
2501         }
2502
2503         pw.print("UID firewall dozable chain enabled: "); pw.println(
2504                 mFirewallChainStates.get(FIREWALL_CHAIN_DOZABLE));
2505         synchronized (mUidFirewallDozableRules) {
2506             dumpUidFirewallRule(pw, FIREWALL_CHAIN_NAME_DOZABLE, mUidFirewallDozableRules);
2507         }
2508
2509         pw.println("UID firewall powersave chain enabled: " +
2510                 mFirewallChainStates.get(FIREWALL_CHAIN_POWERSAVE));
2511         synchronized (mUidFirewallPowerSaveRules) {
2512             dumpUidFirewallRule(pw, FIREWALL_CHAIN_NAME_POWERSAVE, mUidFirewallPowerSaveRules);
2513         }
2514
2515         synchronized (mIdleTimerLock) {
2516             pw.println("Idle timers:");
2517             for (HashMap.Entry<String, IdleTimerParams> ent : mActiveIdleTimers.entrySet()) {
2518                 pw.print("  "); pw.print(ent.getKey()); pw.println(":");
2519                 IdleTimerParams params = ent.getValue();
2520                 pw.print("    timeout="); pw.print(params.timeout);
2521                 pw.print(" type="); pw.print(params.type);
2522                 pw.print(" networkCount="); pw.println(params.networkCount);
2523             }
2524         }
2525
2526         pw.print("Firewall enabled: "); pw.println(mFirewallEnabled);
2527         pw.print("Netd service status: " );
2528         if (mNetdService == null) {
2529             pw.println("disconnected");
2530         } else {
2531             try {
2532                 final boolean alive = mNetdService.isAlive();
2533                 pw.println(alive ? "alive": "dead");
2534             } catch (RemoteException e) {
2535                 pw.println("unreachable");
2536             }
2537         }
2538     }
2539
2540     private void dumpUidRuleOnQuotaLocked(PrintWriter pw, String name, SparseBooleanArray list) {
2541         pw.print("UID bandwith control ");
2542         pw.print(name);
2543         pw.print(" rule: [");
2544         final int size = list.size();
2545         for (int i = 0; i < size; i++) {
2546             pw.print(list.keyAt(i));
2547             if (i < size - 1) pw.print(",");
2548         }
2549         pw.println("]");
2550     }
2551
2552     private void dumpUidFirewallRule(PrintWriter pw, String name, SparseIntArray rules) {
2553         pw.print("UID firewall ");
2554         pw.print(name);
2555         pw.print(" rule: [");
2556         final int size = rules.size();
2557         for (int i = 0; i < size; i++) {
2558             pw.print(rules.keyAt(i));
2559             pw.print(":");
2560             pw.print(rules.valueAt(i));
2561             if (i < size - 1) pw.print(",");
2562         }
2563         pw.println("]");
2564     }
2565
2566     @Override
2567     public void createPhysicalNetwork(int netId, String permission) {
2568         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2569
2570         try {
2571             if (permission != null) {
2572                 mConnector.execute("network", "create", netId, permission);
2573             } else {
2574                 mConnector.execute("network", "create", netId);
2575             }
2576         } catch (NativeDaemonConnectorException e) {
2577             throw e.rethrowAsParcelableException();
2578         }
2579     }
2580
2581     @Override
2582     public void createVirtualNetwork(int netId, boolean hasDNS, boolean secure) {
2583         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2584
2585         try {
2586             mConnector.execute("network", "create", netId, "vpn", hasDNS ? "1" : "0",
2587                     secure ? "1" : "0");
2588         } catch (NativeDaemonConnectorException e) {
2589             throw e.rethrowAsParcelableException();
2590         }
2591     }
2592
2593     @Override
2594     public void removeNetwork(int netId) {
2595         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2596
2597         try {
2598             mConnector.execute("network", "destroy", netId);
2599         } catch (NativeDaemonConnectorException e) {
2600             throw e.rethrowAsParcelableException();
2601         }
2602     }
2603
2604     @Override
2605     public void addInterfaceToNetwork(String iface, int netId) {
2606         modifyInterfaceInNetwork("add", "" + netId, iface);
2607     }
2608
2609     @Override
2610     public void removeInterfaceFromNetwork(String iface, int netId) {
2611         modifyInterfaceInNetwork("remove", "" + netId, iface);
2612     }
2613
2614     private void modifyInterfaceInNetwork(String action, String netId, String iface) {
2615         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2616         try {
2617             mConnector.execute("network", "interface", action, netId, iface);
2618         } catch (NativeDaemonConnectorException e) {
2619             throw e.rethrowAsParcelableException();
2620         }
2621     }
2622
2623     @Override
2624     public void addLegacyRouteForNetId(int netId, RouteInfo routeInfo, int uid) {
2625         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2626
2627         final Command cmd = new Command("network", "route", "legacy", uid, "add", netId);
2628
2629         // create triplet: interface dest-ip-addr/prefixlength gateway-ip-addr
2630         final LinkAddress la = routeInfo.getDestinationLinkAddress();
2631         cmd.appendArg(routeInfo.getInterface());
2632         cmd.appendArg(la.getAddress().getHostAddress() + "/" + la.getPrefixLength());
2633         if (routeInfo.hasGateway()) {
2634             cmd.appendArg(routeInfo.getGateway().getHostAddress());
2635         }
2636
2637         try {
2638             mConnector.execute(cmd);
2639         } catch (NativeDaemonConnectorException e) {
2640             throw e.rethrowAsParcelableException();
2641         }
2642     }
2643
2644     @Override
2645     public void setDefaultNetId(int netId) {
2646         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2647
2648         try {
2649             mConnector.execute("network", "default", "set", netId);
2650         } catch (NativeDaemonConnectorException e) {
2651             throw e.rethrowAsParcelableException();
2652         }
2653     }
2654
2655     @Override
2656     public void clearDefaultNetId() {
2657         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2658
2659         try {
2660             mConnector.execute("network", "default", "clear");
2661         } catch (NativeDaemonConnectorException e) {
2662             throw e.rethrowAsParcelableException();
2663         }
2664     }
2665
2666     @Override
2667     public void setNetworkPermission(int netId, String permission) {
2668         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2669
2670         try {
2671             if (permission != null) {
2672                 mConnector.execute("network", "permission", "network", "set", permission, netId);
2673             } else {
2674                 mConnector.execute("network", "permission", "network", "clear", netId);
2675             }
2676         } catch (NativeDaemonConnectorException e) {
2677             throw e.rethrowAsParcelableException();
2678         }
2679     }
2680
2681
2682     @Override
2683     public void setPermission(String permission, int[] uids) {
2684         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2685
2686         Object[] argv = new Object[4 + MAX_UID_RANGES_PER_COMMAND];
2687         argv[0] = "permission";
2688         argv[1] = "user";
2689         argv[2] = "set";
2690         argv[3] = permission;
2691         int argc = 4;
2692         // Avoid overly long commands by limiting number of UIDs per command.
2693         for (int i = 0; i < uids.length; ++i) {
2694             argv[argc++] = uids[i];
2695             if (i == uids.length - 1 || argc == argv.length) {
2696                 try {
2697                     mConnector.execute("network", Arrays.copyOf(argv, argc));
2698                 } catch (NativeDaemonConnectorException e) {
2699                     throw e.rethrowAsParcelableException();
2700                 }
2701                 argc = 4;
2702             }
2703         }
2704     }
2705
2706     @Override
2707     public void clearPermission(int[] uids) {
2708         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2709
2710         Object[] argv = new Object[3 + MAX_UID_RANGES_PER_COMMAND];
2711         argv[0] = "permission";
2712         argv[1] = "user";
2713         argv[2] = "clear";
2714         int argc = 3;
2715         // Avoid overly long commands by limiting number of UIDs per command.
2716         for (int i = 0; i < uids.length; ++i) {
2717             argv[argc++] = uids[i];
2718             if (i == uids.length - 1 || argc == argv.length) {
2719                 try {
2720                     mConnector.execute("network", Arrays.copyOf(argv, argc));
2721                 } catch (NativeDaemonConnectorException e) {
2722                     throw e.rethrowAsParcelableException();
2723                 }
2724                 argc = 3;
2725             }
2726         }
2727     }
2728
2729     @Override
2730     public void allowProtect(int uid) {
2731         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2732
2733         try {
2734             mConnector.execute("network", "protect", "allow", uid);
2735         } catch (NativeDaemonConnectorException e) {
2736             throw e.rethrowAsParcelableException();
2737         }
2738     }
2739
2740     @Override
2741     public void denyProtect(int uid) {
2742         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
2743
2744         try {
2745             mConnector.execute("network", "protect", "deny", uid);
2746         } catch (NativeDaemonConnectorException e) {
2747             throw e.rethrowAsParcelableException();
2748         }
2749     }
2750
2751     @Override
2752     public void addInterfaceToLocalNetwork(String iface, List<RouteInfo> routes) {
2753         modifyInterfaceInNetwork("add", "local", iface);
2754
2755         for (RouteInfo route : routes) {
2756             if (!route.isDefaultRoute()) {
2757                 modifyRoute("add", "local", route);
2758             }
2759         }
2760     }
2761
2762     @Override
2763     public void removeInterfaceFromLocalNetwork(String iface) {
2764         modifyInterfaceInNetwork("remove", "local", iface);
2765     }
2766 }