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