1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.bluetooth.pan; 18 19 import android.bluetooth.BluetoothDevice; 20 import android.bluetooth.BluetoothPan; 21 import android.bluetooth.BluetoothProfile; 22 import android.bluetooth.IBluetoothPan; 23 import android.content.Context; 24 import android.content.Intent; 25 import android.content.res.Resources.NotFoundException; 26 import android.net.ConnectivityManager; 27 import android.net.InterfaceConfiguration; 28 import android.net.LinkAddress; 29 import android.net.NetworkUtils; 30 import android.os.Binder; 31 import android.os.Handler; 32 import android.os.IBinder; 33 import android.os.INetworkManagementService; 34 import android.os.Message; 35 import android.os.ServiceManager; 36 import android.os.UserManager; 37 import android.util.Log; 38 39 import com.android.bluetooth.BluetoothMetricsProto; 40 import com.android.bluetooth.Utils; 41 import com.android.bluetooth.btservice.AdapterService; 42 import com.android.bluetooth.btservice.MetricsLogger; 43 import com.android.bluetooth.btservice.ProfileService; 44 45 import java.net.InetAddress; 46 import java.util.ArrayList; 47 import java.util.HashMap; 48 import java.util.List; 49 50 /** 51 * Provides Bluetooth Pan Device profile, as a service in 52 * the Bluetooth application. 53 * @hide 54 */ 55 public class PanService extends ProfileService { 56 private static final String TAG = "PanService"; 57 private static final boolean DBG = false; 58 private static PanService sPanService; 59 60 private static final String BLUETOOTH_IFACE_ADDR_START = "192.168.44.1"; 61 private static final int BLUETOOTH_MAX_PAN_CONNECTIONS = 5; 62 private static final int BLUETOOTH_PREFIX_LENGTH = 24; 63 64 private HashMap<BluetoothDevice, BluetoothPanDevice> mPanDevices; 65 private ArrayList<String> mBluetoothIfaceAddresses; 66 private int mMaxPanDevices; 67 private String mPanIfName; 68 private String mNapIfaceAddr; 69 private boolean mNativeAvailable; 70 71 private static final int MESSAGE_CONNECT = 1; 72 private static final int MESSAGE_DISCONNECT = 2; 73 private static final int MESSAGE_CONNECT_STATE_CHANGED = 11; 74 private boolean mTetherOn = false; 75 76 private BluetoothTetheringNetworkFactory mNetworkFactory; 77 78 79 static { classInitNative()80 classInitNative(); 81 } 82 83 @Override initBinder()84 public IProfileServiceBinder initBinder() { 85 return new BluetoothPanBinder(this); 86 } 87 getPanService()88 public static synchronized PanService getPanService() { 89 if (sPanService == null) { 90 Log.w(TAG, "getPanService(): service is null"); 91 return null; 92 } 93 if (!sPanService.isAvailable()) { 94 Log.w(TAG, "getPanService(): service is not available "); 95 return null; 96 } 97 return sPanService; 98 } 99 setPanService(PanService instance)100 private static synchronized void setPanService(PanService instance) { 101 if (DBG) { 102 Log.d(TAG, "setPanService(): set to: " + instance); 103 } 104 sPanService = instance; 105 } 106 107 @Override start()108 protected boolean start() { 109 mPanDevices = new HashMap<BluetoothDevice, BluetoothPanDevice>(); 110 mBluetoothIfaceAddresses = new ArrayList<String>(); 111 try { 112 mMaxPanDevices = getResources().getInteger( 113 com.android.internal.R.integer.config_max_pan_devices); 114 } catch (NotFoundException e) { 115 mMaxPanDevices = BLUETOOTH_MAX_PAN_CONNECTIONS; 116 } 117 initializeNative(); 118 mNativeAvailable = true; 119 120 mNetworkFactory = 121 new BluetoothTetheringNetworkFactory(getBaseContext(), getMainLooper(), this); 122 setPanService(this); 123 124 return true; 125 } 126 127 @Override stop()128 protected boolean stop() { 129 mHandler.removeCallbacksAndMessages(null); 130 return true; 131 } 132 133 @Override cleanup()134 protected void cleanup() { 135 // TODO(b/72948646): this should be moved to stop() 136 setPanService(null); 137 if (mNativeAvailable) { 138 cleanupNative(); 139 mNativeAvailable = false; 140 } 141 if (mPanDevices != null) { 142 int[] desiredStates = {BluetoothProfile.STATE_CONNECTING, BluetoothProfile.STATE_CONNECTED, 143 BluetoothProfile.STATE_DISCONNECTING}; 144 List<BluetoothDevice> devList = 145 getDevicesMatchingConnectionStates(desiredStates); 146 for (BluetoothDevice device : devList) { 147 BluetoothPanDevice panDevice = mPanDevices.get(device); 148 Log.d(TAG, "panDevice: " + panDevice + " device address: " + device); 149 if (panDevice != null) { 150 handlePanDeviceStateChange(device, mPanIfName, 151 BluetoothProfile.STATE_DISCONNECTED, 152 panDevice.mLocalRole, panDevice.mRemoteRole); 153 } 154 } 155 mPanDevices.clear(); 156 } 157 } 158 159 private final Handler mHandler = new Handler() { 160 @Override 161 public void handleMessage(Message msg) { 162 switch (msg.what) { 163 case MESSAGE_CONNECT: { 164 BluetoothDevice device = (BluetoothDevice) msg.obj; 165 if (!connectPanNative(Utils.getByteAddress(device), 166 BluetoothPan.LOCAL_PANU_ROLE, BluetoothPan.REMOTE_NAP_ROLE)) { 167 handlePanDeviceStateChange(device, null, BluetoothProfile.STATE_CONNECTING, 168 BluetoothPan.LOCAL_PANU_ROLE, BluetoothPan.REMOTE_NAP_ROLE); 169 handlePanDeviceStateChange(device, null, 170 BluetoothProfile.STATE_DISCONNECTED, BluetoothPan.LOCAL_PANU_ROLE, 171 BluetoothPan.REMOTE_NAP_ROLE); 172 break; 173 } 174 } 175 break; 176 case MESSAGE_DISCONNECT: { 177 BluetoothDevice device = (BluetoothDevice) msg.obj; 178 if (!disconnectPanNative(Utils.getByteAddress(device))) { 179 handlePanDeviceStateChange(device, mPanIfName, 180 BluetoothProfile.STATE_DISCONNECTING, BluetoothPan.LOCAL_PANU_ROLE, 181 BluetoothPan.REMOTE_NAP_ROLE); 182 handlePanDeviceStateChange(device, mPanIfName, 183 BluetoothProfile.STATE_DISCONNECTED, BluetoothPan.LOCAL_PANU_ROLE, 184 BluetoothPan.REMOTE_NAP_ROLE); 185 break; 186 } 187 } 188 break; 189 case MESSAGE_CONNECT_STATE_CHANGED: { 190 ConnectState cs = (ConnectState) msg.obj; 191 BluetoothDevice device = getDevice(cs.addr); 192 // TBD get iface from the msg 193 if (DBG) { 194 Log.d(TAG, 195 "MESSAGE_CONNECT_STATE_CHANGED: " + device + " state: " + cs.state); 196 } 197 handlePanDeviceStateChange(device, mPanIfName /* iface */, 198 convertHalState(cs.state), cs.local_role, cs.remote_role); 199 } 200 break; 201 } 202 } 203 }; 204 205 /** 206 * Handlers for incoming service calls 207 */ 208 private static class BluetoothPanBinder extends IBluetoothPan.Stub 209 implements IProfileServiceBinder { 210 private PanService mService; 211 BluetoothPanBinder(PanService svc)212 BluetoothPanBinder(PanService svc) { 213 mService = svc; 214 } 215 216 @Override cleanup()217 public void cleanup() { 218 mService = null; 219 } 220 getService()221 private PanService getService() { 222 if (!Utils.checkCaller()) { 223 Log.w(TAG, "Pan call not allowed for non-active user"); 224 return null; 225 } 226 227 if (mService != null && mService.isAvailable()) { 228 return mService; 229 } 230 return null; 231 } 232 233 @Override connect(BluetoothDevice device)234 public boolean connect(BluetoothDevice device) { 235 PanService service = getService(); 236 if (service == null) { 237 return false; 238 } 239 return service.connect(device); 240 } 241 242 @Override disconnect(BluetoothDevice device)243 public boolean disconnect(BluetoothDevice device) { 244 PanService service = getService(); 245 if (service == null) { 246 return false; 247 } 248 return service.disconnect(device); 249 } 250 251 @Override getConnectionState(BluetoothDevice device)252 public int getConnectionState(BluetoothDevice device) { 253 PanService service = getService(); 254 if (service == null) { 255 return BluetoothPan.STATE_DISCONNECTED; 256 } 257 return service.getConnectionState(device); 258 } 259 isPanNapOn()260 private boolean isPanNapOn() { 261 PanService service = getService(); 262 if (service == null) { 263 return false; 264 } 265 return service.isPanNapOn(); 266 } 267 isPanUOn()268 private boolean isPanUOn() { 269 if (DBG) { 270 Log.d(TAG, "isTetheringOn call getPanLocalRoleNative"); 271 } 272 PanService service = getService(); 273 if (service == null) { 274 return false; 275 } 276 return service.isPanUOn(); 277 } 278 279 @Override isTetheringOn()280 public boolean isTetheringOn() { 281 // TODO(BT) have a variable marking the on/off state 282 PanService service = getService(); 283 if (service == null) { 284 return false; 285 } 286 return service.isTetheringOn(); 287 } 288 289 @Override setBluetoothTethering(boolean value)290 public void setBluetoothTethering(boolean value) { 291 PanService service = getService(); 292 if (service == null) { 293 return; 294 } 295 Log.d(TAG, "setBluetoothTethering: " + value + ", mTetherOn: " + service.mTetherOn); 296 service.setBluetoothTethering(value); 297 } 298 299 @Override getConnectedDevices()300 public List<BluetoothDevice> getConnectedDevices() { 301 PanService service = getService(); 302 if (service == null) { 303 return new ArrayList<BluetoothDevice>(0); 304 } 305 return service.getConnectedDevices(); 306 } 307 308 @Override getDevicesMatchingConnectionStates(int[] states)309 public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { 310 PanService service = getService(); 311 if (service == null) { 312 return new ArrayList<BluetoothDevice>(0); 313 } 314 return service.getDevicesMatchingConnectionStates(states); 315 } 316 } 317 318 ; 319 connect(BluetoothDevice device)320 public boolean connect(BluetoothDevice device) { 321 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 322 if (getConnectionState(device) != BluetoothProfile.STATE_DISCONNECTED) { 323 Log.e(TAG, "Pan Device not disconnected: " + device); 324 return false; 325 } 326 Message msg = mHandler.obtainMessage(MESSAGE_CONNECT, device); 327 mHandler.sendMessage(msg); 328 return true; 329 } 330 disconnect(BluetoothDevice device)331 public boolean disconnect(BluetoothDevice device) { 332 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 333 Message msg = mHandler.obtainMessage(MESSAGE_DISCONNECT, device); 334 mHandler.sendMessage(msg); 335 return true; 336 } 337 getConnectionState(BluetoothDevice device)338 public int getConnectionState(BluetoothDevice device) { 339 BluetoothPanDevice panDevice = mPanDevices.get(device); 340 if (panDevice == null) { 341 return BluetoothPan.STATE_DISCONNECTED; 342 } 343 return panDevice.mState; 344 } 345 isPanNapOn()346 boolean isPanNapOn() { 347 if (DBG) { 348 Log.d(TAG, "isTetheringOn call getPanLocalRoleNative"); 349 } 350 return (getPanLocalRoleNative() & BluetoothPan.LOCAL_NAP_ROLE) != 0; 351 } 352 isPanUOn()353 boolean isPanUOn() { 354 if (DBG) { 355 Log.d(TAG, "isTetheringOn call getPanLocalRoleNative"); 356 } 357 return (getPanLocalRoleNative() & BluetoothPan.LOCAL_PANU_ROLE) != 0; 358 } 359 isTetheringOn()360 public boolean isTetheringOn() { 361 // TODO(BT) have a variable marking the on/off state 362 return mTetherOn; 363 } 364 setBluetoothTethering(boolean value)365 void setBluetoothTethering(boolean value) { 366 if (DBG) { 367 Log.d(TAG, "setBluetoothTethering: " + value + ", mTetherOn: " + mTetherOn); 368 } 369 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); 370 final Context context = getBaseContext(); 371 String pkgName = context.getOpPackageName(); 372 373 // Clear caller identity temporarily so enforceTetherChangePermission UID checks work 374 // correctly 375 final long identityToken = Binder.clearCallingIdentity(); 376 try { 377 ConnectivityManager.enforceTetherChangePermission(context, pkgName); 378 } finally { 379 Binder.restoreCallingIdentity(identityToken); 380 } 381 382 UserManager um = (UserManager) getSystemService(Context.USER_SERVICE); 383 if (um.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING) && value) { 384 throw new SecurityException("DISALLOW_CONFIG_TETHERING is enabled for this user."); 385 } 386 if (mTetherOn != value) { 387 //drop any existing panu or pan-nap connection when changing the tethering state 388 mTetherOn = value; 389 List<BluetoothDevice> devList = getConnectedDevices(); 390 for (BluetoothDevice dev : devList) { 391 disconnect(dev); 392 } 393 } 394 } 395 setPriority(BluetoothDevice device, int priority)396 public boolean setPriority(BluetoothDevice device, int priority) { 397 if (device == null) { 398 throw new IllegalArgumentException("Null device"); 399 } 400 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); 401 if (DBG) { 402 Log.d(TAG, "Saved priority " + device + " = " + priority); 403 } 404 AdapterService.getAdapterService().getDatabase() 405 .setProfilePriority(device, BluetoothProfile.PAN, priority); 406 return true; 407 } 408 getPriority(BluetoothDevice device)409 public int getPriority(BluetoothDevice device) { 410 if (device == null) { 411 throw new IllegalArgumentException("Null device"); 412 } 413 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); 414 return AdapterService.getAdapterService().getDatabase() 415 .getProfilePriority(device, BluetoothProfile.PAN); 416 } 417 getConnectedDevices()418 public List<BluetoothDevice> getConnectedDevices() { 419 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 420 List<BluetoothDevice> devices = 421 getDevicesMatchingConnectionStates(new int[]{BluetoothProfile.STATE_CONNECTED}); 422 return devices; 423 } 424 getDevicesMatchingConnectionStates(int[] states)425 List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { 426 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 427 List<BluetoothDevice> panDevices = new ArrayList<BluetoothDevice>(); 428 429 for (BluetoothDevice device : mPanDevices.keySet()) { 430 int panDeviceState = getConnectionState(device); 431 for (int state : states) { 432 if (state == panDeviceState) { 433 panDevices.add(device); 434 break; 435 } 436 } 437 } 438 return panDevices; 439 } 440 441 protected static class ConnectState { ConnectState(byte[] address, int state, int error, int localRole, int remoteRole)442 public ConnectState(byte[] address, int state, int error, int localRole, int remoteRole) { 443 this.addr = address; 444 this.state = state; 445 this.error = error; 446 this.local_role = localRole; 447 this.remote_role = remoteRole; 448 } 449 450 public byte[] addr; 451 public int state; 452 public int error; 453 public int local_role; 454 public int remote_role; 455 } 456 457 ; 458 onConnectStateChanged(byte[] address, int state, int error, int localRole, int remoteRole)459 private void onConnectStateChanged(byte[] address, int state, int error, int localRole, 460 int remoteRole) { 461 if (DBG) { 462 Log.d(TAG, "onConnectStateChanged: " + state + ", local role:" + localRole 463 + ", remoteRole: " + remoteRole); 464 } 465 Message msg = mHandler.obtainMessage(MESSAGE_CONNECT_STATE_CHANGED); 466 msg.obj = new ConnectState(address, state, error, localRole, remoteRole); 467 mHandler.sendMessage(msg); 468 } 469 onControlStateChanged(int localRole, int state, int error, String ifname)470 private void onControlStateChanged(int localRole, int state, int error, String ifname) { 471 if (DBG) { 472 Log.d(TAG, "onControlStateChanged: " + state + ", error: " + error + ", ifname: " 473 + ifname); 474 } 475 if (error == 0) { 476 mPanIfName = ifname; 477 } 478 } 479 convertHalState(int halState)480 private static int convertHalState(int halState) { 481 switch (halState) { 482 case CONN_STATE_CONNECTED: 483 return BluetoothProfile.STATE_CONNECTED; 484 case CONN_STATE_CONNECTING: 485 return BluetoothProfile.STATE_CONNECTING; 486 case CONN_STATE_DISCONNECTED: 487 return BluetoothProfile.STATE_DISCONNECTED; 488 case CONN_STATE_DISCONNECTING: 489 return BluetoothProfile.STATE_DISCONNECTING; 490 default: 491 Log.e(TAG, "bad pan connection state: " + halState); 492 return BluetoothProfile.STATE_DISCONNECTED; 493 } 494 } 495 handlePanDeviceStateChange(BluetoothDevice device, String iface, int state, int localRole, int remoteRole)496 void handlePanDeviceStateChange(BluetoothDevice device, String iface, int state, int localRole, 497 int remoteRole) { 498 if (DBG) { 499 Log.d(TAG, "handlePanDeviceStateChange: device: " + device + ", iface: " + iface 500 + ", state: " + state + ", localRole:" + localRole + ", remoteRole:" 501 + remoteRole); 502 } 503 int prevState; 504 505 BluetoothPanDevice panDevice = mPanDevices.get(device); 506 if (panDevice == null) { 507 Log.i(TAG, "state " + state + " Num of connected pan devices: " + mPanDevices.size()); 508 prevState = BluetoothProfile.STATE_DISCONNECTED; 509 panDevice = new BluetoothPanDevice(state, iface, localRole, remoteRole); 510 mPanDevices.put(device, panDevice); 511 } else { 512 prevState = panDevice.mState; 513 panDevice.mState = state; 514 panDevice.mLocalRole = localRole; 515 panDevice.mRemoteRole = remoteRole; 516 panDevice.mIface = iface; 517 } 518 519 // Avoid race condition that gets this class stuck in STATE_DISCONNECTING. While we 520 // are in STATE_CONNECTING, if a BluetoothPan#disconnect call comes in, the original 521 // connect call will put us in STATE_DISCONNECTED. Then, the disconnect completes and 522 // changes the state to STATE_DISCONNECTING. All future calls to BluetoothPan#connect 523 // will fail until the caller explicitly calls BluetoothPan#disconnect. 524 if (prevState == BluetoothProfile.STATE_DISCONNECTED 525 && state == BluetoothProfile.STATE_DISCONNECTING) { 526 Log.d(TAG, "Ignoring state change from " + prevState + " to " + state); 527 mPanDevices.remove(device); 528 return; 529 } 530 531 Log.d(TAG, "handlePanDeviceStateChange preState: " + prevState + " state: " + state); 532 if (prevState == state) { 533 return; 534 } 535 if (remoteRole == BluetoothPan.LOCAL_PANU_ROLE) { 536 if (state == BluetoothProfile.STATE_CONNECTED) { 537 if ((!mTetherOn) || (localRole == BluetoothPan.LOCAL_PANU_ROLE)) { 538 Log.d(TAG, "handlePanDeviceStateChange BT tethering is off/Local role" 539 + " is PANU drop the connection"); 540 mPanDevices.remove(device); 541 disconnectPanNative(Utils.getByteAddress(device)); 542 return; 543 } 544 Log.d(TAG, "handlePanDeviceStateChange LOCAL_NAP_ROLE:REMOTE_PANU_ROLE"); 545 if (mNapIfaceAddr == null) { 546 mNapIfaceAddr = startTethering(iface); 547 if (mNapIfaceAddr == null) { 548 Log.e(TAG, "Error seting up tether interface"); 549 mPanDevices.remove(device); 550 disconnectPanNative(Utils.getByteAddress(device)); 551 return; 552 } 553 } 554 } else if (state == BluetoothProfile.STATE_DISCONNECTED) { 555 mPanDevices.remove(device); 556 Log.i(TAG, "remote(PANU) is disconnected, Remaining connected PANU devices: " 557 + mPanDevices.size()); 558 if (mNapIfaceAddr != null && mPanDevices.size() == 0) { 559 stopTethering(iface); 560 mNapIfaceAddr = null; 561 } 562 } 563 } else if (mNetworkFactory != null) { 564 // PANU Role = reverse Tether 565 Log.d(TAG, "handlePanDeviceStateChange LOCAL_PANU_ROLE:REMOTE_NAP_ROLE state = " + state 566 + ", prevState = " + prevState); 567 if (state == BluetoothProfile.STATE_CONNECTED) { 568 mNetworkFactory.startReverseTether(iface); 569 } else if (state == BluetoothProfile.STATE_DISCONNECTED) { 570 mNetworkFactory.stopReverseTether(); 571 mPanDevices.remove(device); 572 } 573 } 574 575 if (state == BluetoothProfile.STATE_CONNECTED) { 576 MetricsLogger.logProfileConnectionEvent(BluetoothMetricsProto.ProfileId.PAN); 577 } 578 /* Notifying the connection state change of the profile before sending the intent for 579 connection state change, as it was causing a race condition, with the UI not being 580 updated with the correct connection state. */ 581 Log.d(TAG, "Pan Device state : device: " + device + " State:" + prevState + "->" + state); 582 Intent intent = new Intent(BluetoothPan.ACTION_CONNECTION_STATE_CHANGED); 583 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 584 intent.putExtra(BluetoothPan.EXTRA_PREVIOUS_STATE, prevState); 585 intent.putExtra(BluetoothPan.EXTRA_STATE, state); 586 intent.putExtra(BluetoothPan.EXTRA_LOCAL_ROLE, localRole); 587 sendBroadcast(intent, BLUETOOTH_PERM); 588 } 589 startTethering(String iface)590 private String startTethering(String iface) { 591 return configureBtIface(true, iface); 592 } 593 stopTethering(String iface)594 private String stopTethering(String iface) { 595 return configureBtIface(false, iface); 596 } 597 configureBtIface(boolean enable, String iface)598 private String configureBtIface(boolean enable, String iface) { 599 Log.i(TAG, "configureBtIface: " + iface + " enable: " + enable); 600 601 IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); 602 INetworkManagementService service = INetworkManagementService.Stub.asInterface(b); 603 ConnectivityManager cm = 604 (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); 605 String[] bluetoothRegexs = cm.getTetherableBluetoothRegexs(); 606 607 // bring toggle the interfaces 608 String[] currentIfaces = new String[0]; 609 try { 610 currentIfaces = service.listInterfaces(); 611 } catch (Exception e) { 612 Log.e(TAG, "Error listing Interfaces :" + e); 613 return null; 614 } 615 616 boolean found = false; 617 for (String currIface : currentIfaces) { 618 if (currIface.equals(iface)) { 619 found = true; 620 break; 621 } 622 } 623 624 if (!found) { 625 return null; 626 } 627 628 InterfaceConfiguration ifcg = null; 629 String address = null; 630 try { 631 ifcg = service.getInterfaceConfig(iface); 632 if (ifcg != null) { 633 InetAddress addr = null; 634 LinkAddress linkAddr = ifcg.getLinkAddress(); 635 if (linkAddr == null || (addr = linkAddr.getAddress()) == null || addr.equals( 636 NetworkUtils.numericToInetAddress("0.0.0.0")) || addr.equals( 637 NetworkUtils.numericToInetAddress("::0"))) { 638 address = BLUETOOTH_IFACE_ADDR_START; 639 addr = NetworkUtils.numericToInetAddress(address); 640 } 641 642 ifcg.setLinkAddress(new LinkAddress(addr, BLUETOOTH_PREFIX_LENGTH)); 643 if (enable) { 644 ifcg.setInterfaceUp(); 645 } else { 646 ifcg.setInterfaceDown(); 647 } 648 649 ifcg.clearFlag("running"); 650 service.setInterfaceConfig(iface, ifcg); 651 652 if (enable) { 653 int tetherStatus = cm.tether(iface); 654 if (tetherStatus != ConnectivityManager.TETHER_ERROR_NO_ERROR) { 655 Log.e(TAG, "Error tethering " + iface + " tetherStatus: " + tetherStatus); 656 return null; 657 } 658 } else { 659 int untetherStatus = cm.untether(iface); 660 Log.i(TAG, "Untethered: " + iface + " untetherStatus: " + untetherStatus); 661 } 662 } 663 } catch (Exception e) { 664 Log.e(TAG, "Error configuring interface " + iface + ", :" + e); 665 return null; 666 } 667 return address; 668 } 669 getConnectedPanDevices()670 private List<BluetoothDevice> getConnectedPanDevices() { 671 List<BluetoothDevice> devices = new ArrayList<BluetoothDevice>(); 672 673 for (BluetoothDevice device : mPanDevices.keySet()) { 674 if (getPanDeviceConnectionState(device) == BluetoothProfile.STATE_CONNECTED) { 675 devices.add(device); 676 } 677 } 678 return devices; 679 } 680 getPanDeviceConnectionState(BluetoothDevice device)681 private int getPanDeviceConnectionState(BluetoothDevice device) { 682 BluetoothPanDevice panDevice = mPanDevices.get(device); 683 if (panDevice == null) { 684 return BluetoothProfile.STATE_DISCONNECTED; 685 } 686 return panDevice.mState; 687 } 688 689 @Override dump(StringBuilder sb)690 public void dump(StringBuilder sb) { 691 super.dump(sb); 692 println(sb, "mMaxPanDevices: " + mMaxPanDevices); 693 println(sb, "mPanIfName: " + mPanIfName); 694 println(sb, "mTetherOn: " + mTetherOn); 695 println(sb, "mPanDevices:"); 696 for (BluetoothDevice device : mPanDevices.keySet()) { 697 println(sb, " " + device + " : " + mPanDevices.get(device)); 698 } 699 } 700 701 private class BluetoothPanDevice { 702 private int mState; 703 private String mIface; 704 private int mLocalRole; // Which local role is this PAN device bound to 705 private int mRemoteRole; // Which remote role is this PAN device bound to 706 BluetoothPanDevice(int state, String iface, int localRole, int remoteRole)707 BluetoothPanDevice(int state, String iface, int localRole, int remoteRole) { 708 mState = state; 709 mIface = iface; 710 mLocalRole = localRole; 711 mRemoteRole = remoteRole; 712 } 713 } 714 715 // Constants matching Hal header file bt_hh.h 716 // bthh_connection_state_t 717 private static final int CONN_STATE_CONNECTED = 0; 718 private static final int CONN_STATE_CONNECTING = 1; 719 private static final int CONN_STATE_DISCONNECTED = 2; 720 private static final int CONN_STATE_DISCONNECTING = 3; 721 classInitNative()722 private static native void classInitNative(); 723 initializeNative()724 private native void initializeNative(); 725 cleanupNative()726 private native void cleanupNative(); 727 connectPanNative(byte[] btAddress, int localRole, int remoteRole)728 private native boolean connectPanNative(byte[] btAddress, int localRole, int remoteRole); 729 disconnectPanNative(byte[] btAddress)730 private native boolean disconnectPanNative(byte[] btAddress); 731 enablePanNative(int localRole)732 private native boolean enablePanNative(int localRole); 733 getPanLocalRoleNative()734 private native int getPanLocalRoleNative(); 735 736 } 737