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