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