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