PanService.java revision 74ae04c73312403e89db0f8e9bd9601d403b4783
1/* 2 * Copyright (C) 2012 Google Inc. 3 */ 4 5package com.android.bluetooth.pan; 6 7import android.app.Service; 8import android.bluetooth.BluetoothDevice; 9import android.bluetooth.BluetoothPan; 10import android.bluetooth.BluetoothProfile; 11import android.bluetooth.BluetoothTetheringDataTracker; 12import android.bluetooth.IBluetooth; 13import android.bluetooth.IBluetoothPan; 14import android.content.Context; 15import android.content.Intent; 16import android.content.pm.PackageManager; 17import android.content.res.Resources.NotFoundException; 18import android.net.ConnectivityManager; 19import android.net.InterfaceConfiguration; 20import android.net.LinkAddress; 21import android.net.NetworkUtils; 22import android.os.IBinder; 23import android.os.INetworkManagementService; 24import android.os.Handler; 25import android.os.Message; 26import android.os.RemoteException; 27import android.os.ServiceManager; 28import android.provider.Settings; 29import android.util.Log; 30 31import java.net.InetAddress; 32import java.util.ArrayList; 33import java.util.Collections; 34import java.util.HashMap; 35import java.util.List; 36import java.util.Map; 37import com.android.bluetooth.Utils; 38import com.android.bluetooth.btservice.ProfileService; 39 40/** 41 * Provides Bluetooth Pan Device profile, as a service in 42 * the Bluetooth application. 43 * @hide 44 */ 45public class PanService extends ProfileService { 46 private static final String TAG = "PanService"; 47 private static final boolean DBG = true; 48 49 private static final String BLUETOOTH_IFACE_ADDR_START= "192.168.44.1"; 50 private static final int BLUETOOTH_MAX_PAN_CONNECTIONS = 5; 51 private static final int BLUETOOTH_PREFIX_LENGTH = 24; 52 53 private HashMap<BluetoothDevice, BluetoothPanDevice> mPanDevices; 54 private ArrayList<String> mBluetoothIfaceAddresses; 55 private int mMaxPanDevices; 56 private String mPanIfName; 57 private boolean mNativeAvailable; 58 59 private static final int MESSAGE_CONNECT = 1; 60 private static final int MESSAGE_DISCONNECT = 2; 61 private static final int MESSAGE_CONNECT_STATE_CHANGED = 11; 62 private boolean mTetherOn = false; 63 64 65 static { 66 classInitNative(); 67 } 68 69 protected String getName() { 70 return TAG; 71 } 72 73 public IProfileServiceBinder initBinder() { 74 return new BluetoothPanBinder(this); 75 } 76 77 protected boolean start() { 78 mPanDevices = new HashMap<BluetoothDevice, BluetoothPanDevice>(); 79 mBluetoothIfaceAddresses = new ArrayList<String>(); 80 try { 81 mMaxPanDevices = getResources().getInteger( 82 com.android.internal.R.integer.config_max_pan_devices); 83 } catch (NotFoundException e) { 84 mMaxPanDevices = BLUETOOTH_MAX_PAN_CONNECTIONS; 85 } 86 initializeNative(); 87 mNativeAvailable=true; 88 return true; 89 } 90 91 protected boolean stop() { 92 if (DBG) log("stop"); 93 mHandler.removeCallbacksAndMessages(null); 94 return true; 95 } 96 97 protected boolean cleanup() { 98 if (mNativeAvailable) { 99 cleanupNative(); 100 mNativeAvailable=false; 101 } 102 if(mPanDevices != null) { 103 mPanDevices.clear(); 104 mPanDevices = null; 105 } 106 if(mBluetoothIfaceAddresses != null) { 107 mBluetoothIfaceAddresses.clear(); 108 mBluetoothIfaceAddresses = null; 109 } 110 if(mPanIfName != null) 111 mPanIfName = null; 112 return true; 113 } 114 115 private final Handler mHandler = new Handler() { 116 @Override 117 public void handleMessage(Message msg) { 118 switch (msg.what) { 119 case MESSAGE_CONNECT: 120 { 121 BluetoothDevice device = (BluetoothDevice) msg.obj; 122 if (!connectPanNative(Utils.getByteAddress(device), BluetoothPan.LOCAL_PANU_ROLE, BluetoothPan.REMOTE_NAP_ROLE)) { 123 handlePanDeviceStateChange(device, null, BluetoothProfile.STATE_CONNECTING, 124 BluetoothPan.LOCAL_PANU_ROLE, BluetoothPan.REMOTE_NAP_ROLE); 125 handlePanDeviceStateChange(device, null, BluetoothProfile.STATE_DISCONNECTED, 126 BluetoothPan.LOCAL_PANU_ROLE, BluetoothPan.REMOTE_NAP_ROLE); 127 break; 128 } 129 } 130 break; 131 case MESSAGE_DISCONNECT: 132 { 133 BluetoothDevice device = (BluetoothDevice) msg.obj; 134 if (!disconnectPanNative(Utils.getByteAddress(device)) ) { 135 handlePanDeviceStateChange(device, mPanIfName, BluetoothProfile.STATE_DISCONNECTING, 136 BluetoothPan.LOCAL_PANU_ROLE, BluetoothPan.REMOTE_NAP_ROLE); 137 handlePanDeviceStateChange(device, mPanIfName, BluetoothProfile.STATE_DISCONNECTED, 138 BluetoothPan.LOCAL_PANU_ROLE, BluetoothPan.REMOTE_NAP_ROLE); 139 break; 140 } 141 } 142 break; 143 case MESSAGE_CONNECT_STATE_CHANGED: 144 { 145 ConnectState cs = (ConnectState)msg.obj; 146 BluetoothDevice device = getDevice(cs.addr); 147 // TBD get iface from the msg 148 if (DBG) log("MESSAGE_CONNECT_STATE_CHANGED: " + device + " state: " + cs.state); 149 handlePanDeviceStateChange(device, mPanIfName /* iface */, convertHalState(cs.state), 150 cs.local_role, cs.remote_role); 151 } 152 break; 153 } 154 } 155 }; 156 157 /** 158 * Handlers for incoming service calls 159 */ 160 private static class BluetoothPanBinder extends IBluetoothPan.Stub implements IProfileServiceBinder { 161 private PanService mService; 162 public BluetoothPanBinder(PanService svc) { 163 mService = svc; 164 } 165 public boolean cleanup() { 166 mService = null; 167 return true; 168 } 169 private PanService getService() { 170 if (mService != null && mService.isAvailable()) { 171 return mService; 172 } 173 return null; 174 } 175 public boolean connect(BluetoothDevice device) { 176 PanService service = getService(); 177 if (service == null) return false; 178 return service.connect(device); 179 } 180 public boolean disconnect(BluetoothDevice device) { 181 PanService service = getService(); 182 if (service == null) return false; 183 return service.disconnect(device); 184 } 185 public int getConnectionState(BluetoothDevice device) { 186 PanService service = getService(); 187 if (service == null) return BluetoothPan.STATE_DISCONNECTED; 188 return service.getConnectionState(device); 189 } 190 private boolean isPanNapOn() { 191 PanService service = getService(); 192 if (service == null) return false; 193 return service.isPanNapOn(); 194 } 195 private boolean isPanUOn() { 196 if(DBG) Log.d(TAG, "isTetheringOn call getPanLocalRoleNative"); 197 PanService service = getService(); 198 return service.isPanUOn(); 199 } 200 public boolean isTetheringOn() { 201 // TODO(BT) have a variable marking the on/off state 202 PanService service = getService(); 203 if (service == null) return false; 204 return service.isTetheringOn(); 205 } 206 public void setBluetoothTethering(boolean value) { 207 PanService service = getService(); 208 if (service == null) return; 209 if(DBG) Log.d(TAG, "setBluetoothTethering: " + value +", mTetherOn: " + service.mTetherOn); 210 service.setBluetoothTethering(value); 211 } 212 213 public List<BluetoothDevice> getConnectedDevices() { 214 PanService service = getService(); 215 if (service == null) return new ArrayList<BluetoothDevice>(0); 216 return service.getConnectedDevices(); 217 } 218 219 public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { 220 PanService service = getService(); 221 if (service == null) return new ArrayList<BluetoothDevice>(0); 222 return service.getDevicesMatchingConnectionStates(states); 223 } 224 }; 225 226 boolean connect(BluetoothDevice device) { 227 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 228 if (getConnectionState(device) != BluetoothProfile.STATE_DISCONNECTED) { 229 Log.e(TAG, "Pan Device not disconnected: " + device); 230 return false; 231 } 232 Message msg = mHandler.obtainMessage(MESSAGE_CONNECT,device); 233 mHandler.sendMessage(msg); 234 return true; 235 } 236 237 boolean disconnect(BluetoothDevice device) { 238 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 239 Message msg = mHandler.obtainMessage(MESSAGE_DISCONNECT,device); 240 mHandler.sendMessage(msg); 241 return true; 242 } 243 244 int getConnectionState(BluetoothDevice device) { 245 BluetoothPanDevice panDevice = mPanDevices.get(device); 246 if (panDevice == null) { 247 return BluetoothPan.STATE_DISCONNECTED; 248 } 249 return panDevice.mState; 250 } 251 252 boolean isPanNapOn() { 253 if(DBG) Log.d(TAG, "isTetheringOn call getPanLocalRoleNative"); 254 return (getPanLocalRoleNative() & BluetoothPan.LOCAL_NAP_ROLE) != 0; 255 } 256 boolean isPanUOn() { 257 if(DBG) Log.d(TAG, "isTetheringOn call getPanLocalRoleNative"); 258 return (getPanLocalRoleNative() & BluetoothPan.LOCAL_PANU_ROLE) != 0; 259 } 260 boolean isTetheringOn() { 261 // TODO(BT) have a variable marking the on/off state 262 return mTetherOn; 263 } 264 265 void setBluetoothTethering(boolean value) { 266 if(DBG) Log.d(TAG, "setBluetoothTethering: " + value +", mTetherOn: " + mTetherOn); 267 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); 268 if(mTetherOn != value) { 269 //drop any existing panu or pan-nap connection when changing the tethering state 270 mTetherOn = value; 271 List<BluetoothDevice> DevList = getConnectedDevices(); 272 for(BluetoothDevice dev : DevList) 273 disconnect(dev); 274 } 275 } 276 277 List<BluetoothDevice> getConnectedDevices() { 278 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 279 List<BluetoothDevice> devices = getDevicesMatchingConnectionStates( 280 new int[] {BluetoothProfile.STATE_CONNECTED}); 281 return devices; 282 } 283 284 List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { 285 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 286 List<BluetoothDevice> panDevices = new ArrayList<BluetoothDevice>(); 287 288 for (BluetoothDevice device: mPanDevices.keySet()) { 289 int panDeviceState = getConnectionState(device); 290 for (int state : states) { 291 if (state == panDeviceState) { 292 panDevices.add(device); 293 break; 294 } 295 } 296 } 297 return panDevices; 298 } 299 300 static protected class ConnectState { 301 public ConnectState(byte[] address, int state, int error, int local_role, int remote_role) { 302 this.addr = address; 303 this.state = state; 304 this.error = error; 305 this.local_role = local_role; 306 this.remote_role = remote_role; 307 } 308 byte[] addr; 309 int state; 310 int error; 311 int local_role; 312 int remote_role; 313 }; 314 private void onConnectStateChanged(byte[] address, int state, int error, int local_role, int remote_role) { 315 if (DBG) log("onConnectStateChanged: " + state + ", local role:" + local_role + ", remote_role: " + remote_role); 316 Message msg = mHandler.obtainMessage(MESSAGE_CONNECT_STATE_CHANGED); 317 msg.obj = new ConnectState(address, state, error, local_role, remote_role); 318 mHandler.sendMessage(msg); 319 } 320 private void onControlStateChanged(int local_role, int state, int error, String ifname) { 321 if (DBG) 322 log("onControlStateChanged: " + state + ", error: " + error + ", ifname: " + ifname); 323 if(error == 0) 324 mPanIfName = ifname; 325 } 326 327 private static int convertHalState(int halState) { 328 switch (halState) { 329 case CONN_STATE_CONNECTED: 330 return BluetoothProfile.STATE_CONNECTED; 331 case CONN_STATE_CONNECTING: 332 return BluetoothProfile.STATE_CONNECTING; 333 case CONN_STATE_DISCONNECTED: 334 return BluetoothProfile.STATE_DISCONNECTED; 335 case CONN_STATE_DISCONNECTING: 336 return BluetoothProfile.STATE_DISCONNECTING; 337 default: 338 Log.e(TAG, "bad pan connection state: " + halState); 339 return BluetoothProfile.STATE_DISCONNECTED; 340 } 341 } 342 343 void handlePanDeviceStateChange(BluetoothDevice device, 344 String iface, int state, int local_role, int remote_role) { 345 if(DBG) Log.d(TAG, "handlePanDeviceStateChange: device: " + device + ", iface: " + iface + 346 ", state: " + state + ", local_role:" + local_role + ", remote_role:" + remote_role); 347 int prevState; 348 String ifaceAddr = null; 349 BluetoothPanDevice panDevice = mPanDevices.get(device); 350 if (panDevice == null) { 351 prevState = BluetoothProfile.STATE_DISCONNECTED; 352 } else { 353 prevState = panDevice.mState; 354 ifaceAddr = panDevice.mIfaceAddr; 355 } 356 Log.d(TAG, "handlePanDeviceStateChange preState: " + prevState + " state: " + state); 357 if (prevState == state) return; 358 if (remote_role == BluetoothPan.LOCAL_PANU_ROLE) { 359 Log.d(TAG, "handlePanDeviceStateChange LOCAL_NAP_ROLE:REMOTE_PANU_ROLE"); 360 if (state == BluetoothProfile.STATE_CONNECTED) { 361 if(!mTetherOn) { 362 Log.d(TAG, "handlePanDeviceStateChange bluetooth tethering is off, drop the connection"); 363 disconnectPanNative(Utils.getByteAddress(device)); 364 return; 365 } 366 ifaceAddr = enableTethering(iface); 367 if (ifaceAddr == null) Log.e(TAG, "Error seting up tether interface"); 368 369 } else if (state == BluetoothProfile.STATE_DISCONNECTED) { 370 if (ifaceAddr != null) { 371 mBluetoothIfaceAddresses.remove(ifaceAddr); 372 ifaceAddr = null; 373 } 374 } 375 } else { 376 // PANU Role = reverse Tether 377 Log.d(TAG, "handlePanDeviceStateChange LOCAL_PANU_ROLE:REMOTE_NAP_ROLE"); 378 if (state == BluetoothProfile.STATE_CONNECTED) { 379 if(DBG) Log.d(TAG, "handlePanDeviceStateChange: panu STATE_CONNECTED, startReverseTether"); 380 IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); 381 INetworkManagementService service = INetworkManagementService.Stub.asInterface(b); 382 Log.d(TAG, "call INetworkManagementService.startReverseTethering()"); 383 try { 384 service.startReverseTethering(iface); 385 } catch (Exception e) { 386 Log.e(TAG, "Cannot start reverse tethering: " + e); 387 return; 388 } 389 } else if (state == BluetoothProfile.STATE_DISCONNECTED && 390 (prevState == BluetoothProfile.STATE_CONNECTED || 391 prevState == BluetoothProfile.STATE_DISCONNECTING)) { 392 if(DBG) Log.d(TAG, "handlePanDeviceStateChange: stopReverseTether, panDevice.mIface: " 393 + panDevice.mIface); 394 IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); 395 INetworkManagementService service = INetworkManagementService.Stub.asInterface(b); 396 try { 397 service.stopReverseTethering(); 398 } catch(Exception e) { 399 Log.e(TAG, "Cannot stop reverse tethering: " + e); 400 return; 401 } 402 } 403 } 404 405 if (panDevice == null) { 406 panDevice = new BluetoothPanDevice(state, ifaceAddr, iface, local_role); 407 mPanDevices.put(device, panDevice); 408 } else { 409 panDevice.mState = state; 410 panDevice.mIfaceAddr = ifaceAddr; 411 panDevice.mLocalRole = local_role; 412 panDevice.mIface = iface; 413 } 414 415 Intent intent = new Intent(BluetoothPan.ACTION_CONNECTION_STATE_CHANGED); 416 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 417 intent.putExtra(BluetoothPan.EXTRA_PREVIOUS_STATE, prevState); 418 intent.putExtra(BluetoothPan.EXTRA_STATE, state); 419 intent.putExtra(BluetoothPan.EXTRA_LOCAL_ROLE, local_role); 420 sendBroadcast(intent, BLUETOOTH_PERM); 421 422 if (DBG) Log.d(TAG, "Pan Device state : device: " + device + " State:" + 423 prevState + "->" + state); 424 notifyProfileConnectionStateChanged(device, BluetoothProfile.PAN, state, prevState); 425 } 426 427 // configured when we start tethering 428 private String enableTethering(String iface) { 429 if (DBG) Log.d(TAG, "updateTetherState:" + iface); 430 431 IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); 432 INetworkManagementService service = INetworkManagementService.Stub.asInterface(b); 433 ConnectivityManager cm = 434 (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); 435 String[] bluetoothRegexs = cm.getTetherableBluetoothRegexs(); 436 437 // bring toggle the interfaces 438 String[] currentIfaces = new String[0]; 439 try { 440 currentIfaces = service.listInterfaces(); 441 } catch (Exception e) { 442 Log.e(TAG, "Error listing Interfaces :" + e); 443 return null; 444 } 445 446 boolean found = false; 447 for (String currIface: currentIfaces) { 448 if (currIface.equals(iface)) { 449 found = true; 450 break; 451 } 452 } 453 454 if (!found) return null; 455 456 String address = createNewTetheringAddressLocked(); 457 if (address == null) return null; 458 459 InterfaceConfiguration ifcg = null; 460 try { 461 ifcg = service.getInterfaceConfig(iface); 462 if (ifcg != null) { 463 InetAddress addr = null; 464 if (ifcg.addr == null || (addr = ifcg.addr.getAddress()) == null || 465 addr.equals(NetworkUtils.numericToInetAddress("0.0.0.0")) || 466 addr.equals(NetworkUtils.numericToInetAddress("::0"))) { 467 addr = NetworkUtils.numericToInetAddress(address); 468 } 469 ifcg.interfaceFlags = ifcg.interfaceFlags.replace("down", "up"); 470 ifcg.addr = new LinkAddress(addr, BLUETOOTH_PREFIX_LENGTH); 471 ifcg.interfaceFlags = ifcg.interfaceFlags.replace("running", ""); 472 ifcg.interfaceFlags = ifcg.interfaceFlags.replace(" "," "); 473 service.setInterfaceConfig(iface, ifcg); 474 if (cm.tether(iface) != ConnectivityManager.TETHER_ERROR_NO_ERROR) { 475 Log.e(TAG, "Error tethering "+iface); 476 } 477 } 478 } catch (Exception e) { 479 Log.e(TAG, "Error configuring interface " + iface + ", :" + e); 480 return null; 481 } 482 return address; 483 } 484 485 private String createNewTetheringAddressLocked() { 486 if (getConnectedPanDevices().size() == mMaxPanDevices) { 487 if (DBG) Log.d(TAG, "Max PAN device connections reached"); 488 return null; 489 } 490 String address = BLUETOOTH_IFACE_ADDR_START; 491 while (true) { 492 if (mBluetoothIfaceAddresses.contains(address)) { 493 String[] addr = address.split("\\."); 494 Integer newIp = Integer.parseInt(addr[2]) + 1; 495 address = address.replace(addr[2], newIp.toString()); 496 } else { 497 break; 498 } 499 } 500 mBluetoothIfaceAddresses.add(address); 501 return address; 502 } 503 504 private List<BluetoothDevice> getConnectedPanDevices() { 505 List<BluetoothDevice> devices = new ArrayList<BluetoothDevice>(); 506 507 for (BluetoothDevice device: mPanDevices.keySet()) { 508 if (getPanDeviceConnectionState(device) == BluetoothProfile.STATE_CONNECTED) { 509 devices.add(device); 510 } 511 } 512 return devices; 513 } 514 515 private int getPanDeviceConnectionState(BluetoothDevice device) { 516 BluetoothPanDevice panDevice = mPanDevices.get(device); 517 if (panDevice == null) { 518 return BluetoothProfile.STATE_DISCONNECTED; 519 } 520 return panDevice.mState; 521 } 522 523 private class BluetoothPanDevice { 524 private int mState; 525 private String mIfaceAddr; 526 private String mIface; 527 private int mLocalRole; // Which local role is this PAN device bound to 528 529 BluetoothPanDevice(int state, String ifaceAddr, String iface, int localRole) { 530 mState = state; 531 mIfaceAddr = ifaceAddr; 532 mIface = iface; 533 mLocalRole = localRole; 534 } 535 } 536 537 // Constants matching Hal header file bt_hh.h 538 // bthh_connection_state_t 539 private final static int CONN_STATE_CONNECTED = 0; 540 private final static int CONN_STATE_CONNECTING = 1; 541 private final static int CONN_STATE_DISCONNECTED = 2; 542 private final static int CONN_STATE_DISCONNECTING = 3; 543 544 private native static void classInitNative(); 545 private native void initializeNative(); 546 private native void cleanupNative(); 547 private native boolean connectPanNative(byte[] btAddress, int local_role, int remote_role); 548 private native boolean disconnectPanNative(byte[] btAddress); 549 private native boolean enablePanNative(int local_role); 550 private native int getPanLocalRoleNative(); 551 552} 553