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