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