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