NetworkManagementService.java revision e590373ea71251cfffc8f22f011e2e6335dce716
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 android.app.PendingIntent; 20import android.content.BroadcastReceiver; 21import android.content.Context; 22import android.content.Intent; 23import android.content.IntentFilter; 24import android.content.res.Resources; 25import android.content.pm.PackageManager; 26import android.net.Uri; 27import android.net.InterfaceConfiguration; 28import android.net.INetworkManagementEventObserver; 29import android.net.LinkAddress; 30import android.net.NetworkUtils; 31import android.net.wifi.WifiConfiguration; 32import android.net.wifi.WifiConfiguration.KeyMgmt; 33import android.os.INetworkManagementService; 34import android.os.Handler; 35import android.os.SystemProperties; 36import android.text.TextUtils; 37import android.util.Log; 38import android.util.Slog; 39import java.util.ArrayList; 40import java.util.NoSuchElementException; 41import java.util.StringTokenizer; 42import android.provider.Settings; 43import android.content.ContentResolver; 44import android.database.ContentObserver; 45 46import java.io.File; 47import java.io.FileReader; 48import java.lang.IllegalStateException; 49 50import java.net.InetAddress; 51import java.net.UnknownHostException; 52import java.util.concurrent.CountDownLatch; 53 54/** 55 * @hide 56 */ 57class NetworkManagementService extends INetworkManagementService.Stub { 58 59 private static final String TAG = "NetworkManagmentService"; 60 private static final boolean DBG = false; 61 private static final String NETD_TAG = "NetdConnector"; 62 63 class NetdResponseCode { 64 public static final int InterfaceListResult = 110; 65 public static final int TetherInterfaceListResult = 111; 66 public static final int TetherDnsFwdTgtListResult = 112; 67 public static final int TtyListResult = 113; 68 69 public static final int TetherStatusResult = 210; 70 public static final int IpFwdStatusResult = 211; 71 public static final int InterfaceGetCfgResult = 213; 72 public static final int SoftapStatusResult = 214; 73 public static final int UsbRNDISStatusResult = 215; 74 public static final int InterfaceRxCounterResult = 216; 75 public static final int InterfaceTxCounterResult = 217; 76 public static final int InterfaceRxThrottleResult = 218; 77 public static final int InterfaceTxThrottleResult = 219; 78 79 public static final int InterfaceChange = 600; 80 } 81 82 /** 83 * Binder context for this service 84 */ 85 private Context mContext; 86 87 /** 88 * connector object for communicating with netd 89 */ 90 private NativeDaemonConnector mConnector; 91 92 private Thread mThread; 93 private final CountDownLatch mConnectedSignal = new CountDownLatch(1); 94 95 private ArrayList<INetworkManagementEventObserver> mObservers; 96 97 /** 98 * Constructs a new NetworkManagementService instance 99 * 100 * @param context Binder context for this service 101 */ 102 private NetworkManagementService(Context context) { 103 mContext = context; 104 mObservers = new ArrayList<INetworkManagementEventObserver>(); 105 106 if ("simulator".equals(SystemProperties.get("ro.product.device"))) { 107 return; 108 } 109 110 mConnector = new NativeDaemonConnector( 111 new NetdCallbackReceiver(), "netd", 10, NETD_TAG); 112 mThread = new Thread(mConnector, NETD_TAG); 113 } 114 115 public static NetworkManagementService create(Context context) throws InterruptedException { 116 NetworkManagementService service = new NetworkManagementService(context); 117 if (DBG) Slog.d(TAG, "Creating NetworkManagementService"); 118 service.mThread.start(); 119 if (DBG) Slog.d(TAG, "Awaiting socket connection"); 120 service.mConnectedSignal.await(); 121 if (DBG) Slog.d(TAG, "Connected"); 122 return service; 123 } 124 125 public void registerObserver(INetworkManagementEventObserver obs) { 126 Slog.d(TAG, "Registering observer"); 127 mObservers.add(obs); 128 } 129 130 public void unregisterObserver(INetworkManagementEventObserver obs) { 131 Slog.d(TAG, "Unregistering observer"); 132 mObservers.remove(mObservers.indexOf(obs)); 133 } 134 135 /** 136 * Notify our observers of an interface link status change 137 */ 138 private void notifyInterfaceLinkStatusChanged(String iface, boolean link) { 139 for (INetworkManagementEventObserver obs : mObservers) { 140 try { 141 obs.interfaceLinkStatusChanged(iface, link); 142 } catch (Exception ex) { 143 Slog.w(TAG, "Observer notifier failed", ex); 144 } 145 } 146 } 147 148 /** 149 * Notify our observers of an interface addition. 150 */ 151 private void notifyInterfaceAdded(String iface) { 152 for (INetworkManagementEventObserver obs : mObservers) { 153 try { 154 obs.interfaceAdded(iface); 155 } catch (Exception ex) { 156 Slog.w(TAG, "Observer notifier failed", ex); 157 } 158 } 159 } 160 161 /** 162 * Notify our observers of an interface removal. 163 */ 164 private void notifyInterfaceRemoved(String iface) { 165 for (INetworkManagementEventObserver obs : mObservers) { 166 try { 167 obs.interfaceRemoved(iface); 168 } catch (Exception ex) { 169 Slog.w(TAG, "Observer notifier failed", ex); 170 } 171 } 172 } 173 174 /** 175 * Let us know the daemon is connected 176 */ 177 protected void onConnected() { 178 if (DBG) Slog.d(TAG, "onConnected"); 179 mConnectedSignal.countDown(); 180 } 181 182 183 // 184 // Netd Callback handling 185 // 186 187 class NetdCallbackReceiver implements INativeDaemonConnectorCallbacks { 188 public void onDaemonConnected() { 189 NetworkManagementService.this.onConnected(); 190 new Thread() { 191 public void run() { 192 } 193 }.start(); 194 } 195 public boolean onEvent(int code, String raw, String[] cooked) { 196 if (code == NetdResponseCode.InterfaceChange) { 197 /* 198 * a network interface change occured 199 * Format: "NNN Iface added <name>" 200 * "NNN Iface removed <name>" 201 * "NNN Iface changed <name> <up/down>" 202 */ 203 if (cooked.length < 4 || !cooked[1].equals("Iface")) { 204 throw new IllegalStateException( 205 String.format("Invalid event from daemon (%s)", raw)); 206 } 207 if (cooked[2].equals("added")) { 208 notifyInterfaceAdded(cooked[3]); 209 return true; 210 } else if (cooked[2].equals("removed")) { 211 notifyInterfaceRemoved(cooked[3]); 212 return true; 213 } else if (cooked[2].equals("changed") && cooked.length == 5) { 214 notifyInterfaceLinkStatusChanged(cooked[3], cooked[4].equals("up")); 215 return true; 216 } 217 throw new IllegalStateException( 218 String.format("Invalid event from daemon (%s)", raw)); 219 } 220 return false; 221 } 222 } 223 224 225 // 226 // INetworkManagementService members 227 // 228 229 public String[] listInterfaces() throws IllegalStateException { 230 mContext.enforceCallingOrSelfPermission( 231 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService"); 232 233 try { 234 return mConnector.doListCommand("interface list", NetdResponseCode.InterfaceListResult); 235 } catch (NativeDaemonConnectorException e) { 236 throw new IllegalStateException( 237 "Cannot communicate with native daemon to list interfaces"); 238 } 239 } 240 241 public InterfaceConfiguration getInterfaceConfig(String iface) throws IllegalStateException { 242 String rsp; 243 try { 244 rsp = mConnector.doCommand("interface getcfg " + iface).get(0); 245 } catch (NativeDaemonConnectorException e) { 246 throw new IllegalStateException( 247 "Cannot communicate with native daemon to get interface config"); 248 } 249 Slog.d(TAG, String.format("rsp <%s>", rsp)); 250 251 // Rsp: 213 xx:xx:xx:xx:xx:xx yyy.yyy.yyy.yyy zzz [flag1 flag2 flag3] 252 StringTokenizer st = new StringTokenizer(rsp); 253 254 InterfaceConfiguration cfg; 255 try { 256 try { 257 int code = Integer.parseInt(st.nextToken(" ")); 258 if (code != NetdResponseCode.InterfaceGetCfgResult) { 259 throw new IllegalStateException( 260 String.format("Expected code %d, but got %d", 261 NetdResponseCode.InterfaceGetCfgResult, code)); 262 } 263 } catch (NumberFormatException nfe) { 264 throw new IllegalStateException( 265 String.format("Invalid response from daemon (%s)", rsp)); 266 } 267 268 cfg = new InterfaceConfiguration(); 269 cfg.hwAddr = st.nextToken(" "); 270 InetAddress addr = null; 271 int prefixLength = 0; 272 try { 273 addr = NetworkUtils.numericToInetAddress(st.nextToken(" ")); 274 } catch (IllegalArgumentException iae) { 275 Slog.e(TAG, "Failed to parse ipaddr", iae); 276 } 277 278 try { 279 prefixLength = Integer.parseInt(st.nextToken(" ")); 280 } catch (NumberFormatException nfe) { 281 Slog.e(TAG, "Failed to parse prefixLength", nfe); 282 } 283 284 cfg.addr = new LinkAddress(addr, prefixLength); 285 cfg.interfaceFlags = st.nextToken("]").trim() +"]"; 286 } catch (NoSuchElementException nsee) { 287 throw new IllegalStateException( 288 String.format("Invalid response from daemon (%s)", rsp)); 289 } 290 Slog.d(TAG, String.format("flags <%s>", cfg.interfaceFlags)); 291 return cfg; 292 } 293 294 public void setInterfaceConfig( 295 String iface, InterfaceConfiguration cfg) throws IllegalStateException { 296 LinkAddress linkAddr = cfg.addr; 297 if (linkAddr == null || linkAddr.getAddress() == null) { 298 throw new IllegalStateException("Null LinkAddress given"); 299 } 300 String cmd = String.format("interface setcfg %s %s %d %s", iface, 301 linkAddr.getAddress().getHostAddress(), 302 linkAddr.getNetworkPrefixLength(), 303 cfg.interfaceFlags); 304 try { 305 mConnector.doCommand(cmd); 306 } catch (NativeDaemonConnectorException e) { 307 throw new IllegalStateException( 308 "Unable to communicate with native daemon to interface setcfg - " + e); 309 } 310 } 311 312 public void shutdown() { 313 if (mContext.checkCallingOrSelfPermission( 314 android.Manifest.permission.SHUTDOWN) 315 != PackageManager.PERMISSION_GRANTED) { 316 throw new SecurityException("Requires SHUTDOWN permission"); 317 } 318 319 Slog.d(TAG, "Shutting down"); 320 } 321 322 public boolean getIpForwardingEnabled() throws IllegalStateException{ 323 mContext.enforceCallingOrSelfPermission( 324 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService"); 325 326 ArrayList<String> rsp; 327 try { 328 rsp = mConnector.doCommand("ipfwd status"); 329 } catch (NativeDaemonConnectorException e) { 330 throw new IllegalStateException( 331 "Unable to communicate with native daemon to ipfwd status"); 332 } 333 334 for (String line : rsp) { 335 String[] tok = line.split(" "); 336 if (tok.length < 3) { 337 Slog.e(TAG, "Malformed response from native daemon: " + line); 338 return false; 339 } 340 341 int code = Integer.parseInt(tok[0]); 342 if (code == NetdResponseCode.IpFwdStatusResult) { 343 // 211 Forwarding <enabled/disabled> 344 return "enabled".equals(tok[2]); 345 } else { 346 throw new IllegalStateException(String.format("Unexpected response code %d", code)); 347 } 348 } 349 throw new IllegalStateException("Got an empty response"); 350 } 351 352 public void setIpForwardingEnabled(boolean enable) throws IllegalStateException { 353 mContext.enforceCallingOrSelfPermission( 354 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService"); 355 mConnector.doCommand(String.format("ipfwd %sable", (enable ? "en" : "dis"))); 356 } 357 358 public void startTethering(String[] dhcpRange) 359 throws IllegalStateException { 360 mContext.enforceCallingOrSelfPermission( 361 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService"); 362 // cmd is "tether start first_start first_stop second_start second_stop ..." 363 // an odd number of addrs will fail 364 String cmd = "tether start"; 365 for (String d : dhcpRange) { 366 cmd += " " + d; 367 } 368 369 try { 370 mConnector.doCommand(cmd); 371 } catch (NativeDaemonConnectorException e) { 372 throw new IllegalStateException("Unable to communicate to native daemon"); 373 } 374 } 375 376 public void stopTethering() throws IllegalStateException { 377 mContext.enforceCallingOrSelfPermission( 378 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService"); 379 try { 380 mConnector.doCommand("tether stop"); 381 } catch (NativeDaemonConnectorException e) { 382 throw new IllegalStateException("Unable to communicate to native daemon to stop tether"); 383 } 384 } 385 386 public boolean isTetheringStarted() throws IllegalStateException { 387 mContext.enforceCallingOrSelfPermission( 388 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService"); 389 390 ArrayList<String> rsp; 391 try { 392 rsp = mConnector.doCommand("tether status"); 393 } catch (NativeDaemonConnectorException e) { 394 throw new IllegalStateException( 395 "Unable to communicate to native daemon to get tether status"); 396 } 397 398 for (String line : rsp) { 399 String[] tok = line.split(" "); 400 if (tok.length < 3) { 401 throw new IllegalStateException("Malformed response for tether status: " + line); 402 } 403 int code = Integer.parseInt(tok[0]); 404 if (code == NetdResponseCode.TetherStatusResult) { 405 // XXX: Tethering services <started/stopped> <TBD>... 406 return "started".equals(tok[2]); 407 } else { 408 throw new IllegalStateException(String.format("Unexpected response code %d", code)); 409 } 410 } 411 throw new IllegalStateException("Got an empty response"); 412 } 413 414 public void tetherInterface(String iface) throws IllegalStateException { 415 mContext.enforceCallingOrSelfPermission( 416 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService"); 417 try { 418 mConnector.doCommand("tether interface add " + iface); 419 } catch (NativeDaemonConnectorException e) { 420 throw new IllegalStateException( 421 "Unable to communicate to native daemon for adding tether interface"); 422 } 423 } 424 425 public void untetherInterface(String iface) { 426 mContext.enforceCallingOrSelfPermission( 427 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService"); 428 try { 429 mConnector.doCommand("tether interface remove " + iface); 430 } catch (NativeDaemonConnectorException e) { 431 throw new IllegalStateException( 432 "Unable to communicate to native daemon for removing tether interface"); 433 } 434 } 435 436 public String[] listTetheredInterfaces() throws IllegalStateException { 437 mContext.enforceCallingOrSelfPermission( 438 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService"); 439 try { 440 return mConnector.doListCommand( 441 "tether interface list", NetdResponseCode.TetherInterfaceListResult); 442 } catch (NativeDaemonConnectorException e) { 443 throw new IllegalStateException( 444 "Unable to communicate to native daemon for listing tether interfaces"); 445 } 446 } 447 448 public void setDnsForwarders(String[] dns) throws IllegalStateException { 449 mContext.enforceCallingOrSelfPermission( 450 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService"); 451 try { 452 String cmd = "tether dns set"; 453 for (String s : dns) { 454 cmd += " " + NetworkUtils.numericToInetAddress(s).getHostAddress(); 455 } 456 try { 457 mConnector.doCommand(cmd); 458 } catch (NativeDaemonConnectorException e) { 459 throw new IllegalStateException( 460 "Unable to communicate to native daemon for setting tether dns"); 461 } 462 } catch (IllegalArgumentException e) { 463 throw new IllegalStateException("Error resolving dns name", e); 464 } 465 } 466 467 public String[] getDnsForwarders() throws IllegalStateException { 468 mContext.enforceCallingOrSelfPermission( 469 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService"); 470 try { 471 return mConnector.doListCommand( 472 "tether dns list", NetdResponseCode.TetherDnsFwdTgtListResult); 473 } catch (NativeDaemonConnectorException e) { 474 throw new IllegalStateException( 475 "Unable to communicate to native daemon for listing tether dns"); 476 } 477 } 478 479 public void enableNat(String internalInterface, String externalInterface) 480 throws IllegalStateException { 481 mContext.enforceCallingOrSelfPermission( 482 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService"); 483 try { 484 mConnector.doCommand( 485 String.format("nat enable %s %s", internalInterface, externalInterface)); 486 } catch (NativeDaemonConnectorException e) { 487 throw new IllegalStateException( 488 "Unable to communicate to native daemon for enabling NAT interface"); 489 } 490 } 491 492 public void disableNat(String internalInterface, String externalInterface) 493 throws IllegalStateException { 494 mContext.enforceCallingOrSelfPermission( 495 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService"); 496 try { 497 mConnector.doCommand( 498 String.format("nat disable %s %s", internalInterface, externalInterface)); 499 } catch (NativeDaemonConnectorException e) { 500 throw new IllegalStateException( 501 "Unable to communicate to native daemon for disabling NAT interface"); 502 } 503 } 504 505 public String[] listTtys() throws IllegalStateException { 506 mContext.enforceCallingOrSelfPermission( 507 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService"); 508 try { 509 return mConnector.doListCommand("list_ttys", NetdResponseCode.TtyListResult); 510 } catch (NativeDaemonConnectorException e) { 511 throw new IllegalStateException( 512 "Unable to communicate to native daemon for listing TTYs"); 513 } 514 } 515 516 public void attachPppd(String tty, String localAddr, String remoteAddr, String dns1Addr, 517 String dns2Addr) throws IllegalStateException { 518 try { 519 mContext.enforceCallingOrSelfPermission( 520 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService"); 521 mConnector.doCommand(String.format("pppd attach %s %s %s %s %s", tty, 522 NetworkUtils.numericToInetAddress(localAddr).getHostAddress(), 523 NetworkUtils.numericToInetAddress(remoteAddr).getHostAddress(), 524 NetworkUtils.numericToInetAddress(dns1Addr).getHostAddress(), 525 NetworkUtils.numericToInetAddress(dns2Addr).getHostAddress())); 526 } catch (IllegalArgumentException e) { 527 throw new IllegalStateException("Error resolving addr", e); 528 } catch (NativeDaemonConnectorException e) { 529 throw new IllegalStateException("Error communicating to native daemon to attach pppd", e); 530 } 531 } 532 533 public void detachPppd(String tty) throws IllegalStateException { 534 mContext.enforceCallingOrSelfPermission( 535 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService"); 536 try { 537 mConnector.doCommand(String.format("pppd detach %s", tty)); 538 } catch (NativeDaemonConnectorException e) { 539 throw new IllegalStateException("Error communicating to native daemon to detach pppd", e); 540 } 541 } 542 543 public void startUsbRNDIS() throws IllegalStateException { 544 mContext.enforceCallingOrSelfPermission( 545 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService"); 546 try { 547 mConnector.doCommand("usb startrndis"); 548 } catch (NativeDaemonConnectorException e) { 549 throw new IllegalStateException( 550 "Error communicating to native daemon for starting RNDIS", e); 551 } 552 } 553 554 public void stopUsbRNDIS() throws IllegalStateException { 555 mContext.enforceCallingOrSelfPermission( 556 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService"); 557 try { 558 mConnector.doCommand("usb stoprndis"); 559 } catch (NativeDaemonConnectorException e) { 560 throw new IllegalStateException("Error communicating to native daemon", e); 561 } 562 } 563 564 public boolean isUsbRNDISStarted() throws IllegalStateException { 565 mContext.enforceCallingOrSelfPermission( 566 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService"); 567 ArrayList<String> rsp; 568 try { 569 rsp = mConnector.doCommand("usb rndisstatus"); 570 } catch (NativeDaemonConnectorException e) { 571 throw new IllegalStateException( 572 "Error communicating to native daemon to check RNDIS status", e); 573 } 574 575 for (String line : rsp) { 576 String []tok = line.split(" "); 577 int code = Integer.parseInt(tok[0]); 578 if (code == NetdResponseCode.UsbRNDISStatusResult) { 579 if (tok[3].equals("started")) 580 return true; 581 return false; 582 } else { 583 throw new IllegalStateException(String.format("Unexpected response code %d", code)); 584 } 585 } 586 throw new IllegalStateException("Got an empty response"); 587 } 588 589 public void startAccessPoint(WifiConfiguration wifiConfig, String wlanIface, String softapIface) 590 throws IllegalStateException { 591 mContext.enforceCallingOrSelfPermission( 592 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService"); 593 mContext.enforceCallingOrSelfPermission( 594 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService"); 595 try { 596 mConnector.doCommand(String.format("softap stop " + wlanIface)); 597 mConnector.doCommand(String.format("softap fwreload " + wlanIface + " AP")); 598 mConnector.doCommand(String.format("softap start " + wlanIface)); 599 if (wifiConfig == null) { 600 mConnector.doCommand(String.format("softap set " + wlanIface + " " + softapIface)); 601 } else { 602 /** 603 * softap set arg1 arg2 arg3 [arg4 arg5 arg6 arg7 arg8] 604 * argv1 - wlan interface 605 * argv2 - softap interface 606 * argv3 - SSID 607 * argv4 - Security 608 * argv5 - Key 609 * argv6 - Channel 610 * argv7 - Preamble 611 * argv8 - Max SCB 612 */ 613 String str = String.format("softap set " + wlanIface + " " + softapIface + 614 " %s %s %s", convertQuotedString(wifiConfig.SSID), 615 getSecurityType(wifiConfig), 616 convertQuotedString(wifiConfig.preSharedKey)); 617 mConnector.doCommand(str); 618 } 619 mConnector.doCommand(String.format("softap startap")); 620 } catch (NativeDaemonConnectorException e) { 621 throw new IllegalStateException("Error communicating to native daemon to start softap", e); 622 } 623 } 624 625 private String convertQuotedString(String s) { 626 if (s == null) { 627 return s; 628 } 629 /* Replace \ with \\, then " with \" and add quotes at end */ 630 return '"' + s.replaceAll("\\\\","\\\\\\\\").replaceAll("\"","\\\\\"") + '"'; 631 } 632 633 private String getSecurityType(WifiConfiguration wifiConfig) { 634 switch (wifiConfig.getAuthType()) { 635 case KeyMgmt.WPA_PSK: 636 return "wpa-psk"; 637 case KeyMgmt.WPA2_PSK: 638 return "wpa2-psk"; 639 default: 640 return "open"; 641 } 642 } 643 644 public void stopAccessPoint() throws IllegalStateException { 645 mContext.enforceCallingOrSelfPermission( 646 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService"); 647 mContext.enforceCallingOrSelfPermission( 648 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService"); 649 try { 650 mConnector.doCommand("softap stopap"); 651 } catch (NativeDaemonConnectorException e) { 652 throw new IllegalStateException("Error communicating to native daemon to stop soft AP", 653 e); 654 } 655 } 656 657 public void setAccessPoint(WifiConfiguration wifiConfig, String wlanIface, String softapIface) 658 throws IllegalStateException { 659 mContext.enforceCallingOrSelfPermission( 660 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService"); 661 mContext.enforceCallingOrSelfPermission( 662 android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService"); 663 try { 664 if (wifiConfig == null) { 665 mConnector.doCommand(String.format("softap set " + wlanIface + " " + softapIface)); 666 } else { 667 String str = String.format("softap set " + wlanIface + " " + softapIface 668 + " %s %s %s", convertQuotedString(wifiConfig.SSID), 669 getSecurityType(wifiConfig), 670 convertQuotedString(wifiConfig.preSharedKey)); 671 mConnector.doCommand(str); 672 } 673 } catch (NativeDaemonConnectorException e) { 674 throw new IllegalStateException("Error communicating to native daemon to set soft AP", 675 e); 676 } 677 } 678 679 private long getInterfaceCounter(String iface, boolean rx) { 680 mContext.enforceCallingOrSelfPermission( 681 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService"); 682 try { 683 String rsp; 684 try { 685 rsp = mConnector.doCommand( 686 String.format("interface read%scounter %s", (rx ? "rx" : "tx"), iface)).get(0); 687 } catch (NativeDaemonConnectorException e1) { 688 Slog.e(TAG, "Error communicating with native daemon", e1); 689 return -1; 690 } 691 692 String[] tok = rsp.split(" "); 693 if (tok.length < 2) { 694 Slog.e(TAG, String.format("Malformed response for reading %s interface", 695 (rx ? "rx" : "tx"))); 696 return -1; 697 } 698 699 int code; 700 try { 701 code = Integer.parseInt(tok[0]); 702 } catch (NumberFormatException nfe) { 703 Slog.e(TAG, String.format("Error parsing code %s", tok[0])); 704 return -1; 705 } 706 if ((rx && code != NetdResponseCode.InterfaceRxCounterResult) || ( 707 !rx && code != NetdResponseCode.InterfaceTxCounterResult)) { 708 Slog.e(TAG, String.format("Unexpected response code %d", code)); 709 return -1; 710 } 711 return Long.parseLong(tok[1]); 712 } catch (Exception e) { 713 Slog.e(TAG, String.format( 714 "Failed to read interface %s counters", (rx ? "rx" : "tx")), e); 715 } 716 return -1; 717 } 718 719 public long getInterfaceRxCounter(String iface) { 720 return getInterfaceCounter(iface, true); 721 } 722 723 public long getInterfaceTxCounter(String iface) { 724 return getInterfaceCounter(iface, false); 725 } 726 727 public void setInterfaceThrottle(String iface, int rxKbps, int txKbps) { 728 mContext.enforceCallingOrSelfPermission( 729 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService"); 730 try { 731 mConnector.doCommand(String.format( 732 "interface setthrottle %s %d %d", iface, rxKbps, txKbps)); 733 } catch (NativeDaemonConnectorException e) { 734 Slog.e(TAG, "Error communicating with native daemon to set throttle", e); 735 } 736 } 737 738 private int getInterfaceThrottle(String iface, boolean rx) { 739 mContext.enforceCallingOrSelfPermission( 740 android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService"); 741 try { 742 String rsp; 743 try { 744 rsp = mConnector.doCommand( 745 String.format("interface getthrottle %s %s", iface, 746 (rx ? "rx" : "tx"))).get(0); 747 } catch (NativeDaemonConnectorException e) { 748 Slog.e(TAG, "Error communicating with native daemon to getthrottle", e); 749 return -1; 750 } 751 752 String[] tok = rsp.split(" "); 753 if (tok.length < 2) { 754 Slog.e(TAG, "Malformed response to getthrottle command"); 755 return -1; 756 } 757 758 int code; 759 try { 760 code = Integer.parseInt(tok[0]); 761 } catch (NumberFormatException nfe) { 762 Slog.e(TAG, String.format("Error parsing code %s", tok[0])); 763 return -1; 764 } 765 if ((rx && code != NetdResponseCode.InterfaceRxThrottleResult) || ( 766 !rx && code != NetdResponseCode.InterfaceTxThrottleResult)) { 767 Slog.e(TAG, String.format("Unexpected response code %d", code)); 768 return -1; 769 } 770 return Integer.parseInt(tok[1]); 771 } catch (Exception e) { 772 Slog.e(TAG, String.format( 773 "Failed to read interface %s throttle value", (rx ? "rx" : "tx")), e); 774 } 775 return -1; 776 } 777 778 public int getInterfaceRxThrottle(String iface) { 779 return getInterfaceThrottle(iface, true); 780 } 781 782 public int getInterfaceTxThrottle(String iface) { 783 return getInterfaceThrottle(iface, false); 784 } 785} 786