1 /* 2 * Copyright (c) 2008-2009, Motorola, Inc. 3 * 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * - Redistributions of source code must retain the above copyright notice, 10 * this list of conditions and the following disclaimer. 11 * 12 * - Redistributions in binary form must reproduce the above copyright notice, 13 * this list of conditions and the following disclaimer in the documentation 14 * and/or other materials provided with the distribution. 15 * 16 * - Neither the name of the Motorola, Inc. nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 package com.android.bluetooth.pbap; 34 35 import android.app.AlarmManager; 36 import android.app.Notification; 37 import android.app.NotificationChannel; 38 import android.app.NotificationManager; 39 import android.app.PendingIntent; 40 import android.app.Service; 41 import android.bluetooth.BluetoothAdapter; 42 import android.bluetooth.BluetoothDevice; 43 import android.bluetooth.BluetoothPbap; 44 import android.bluetooth.BluetoothProfile; 45 import android.bluetooth.BluetoothServerSocket; 46 import android.bluetooth.BluetoothSocket; 47 import android.bluetooth.BluetoothUuid; 48 import android.bluetooth.IBluetoothPbap; 49 import android.database.sqlite.SQLiteException; 50 import android.content.BroadcastReceiver; 51 import android.content.Context; 52 import android.content.ContentResolver; 53 import android.database.ContentObserver; 54 import android.content.Intent; 55 import android.content.IntentFilter; 56 import android.os.Handler; 57 import android.os.IBinder; 58 import android.os.Message; 59 import android.os.PowerManager; 60 import android.telephony.TelephonyManager; 61 import android.text.TextUtils; 62 import android.util.Log; 63 64 import com.android.bluetooth.BluetoothObexTransport; 65 import com.android.bluetooth.btservice.ProfileService; 66 import com.android.bluetooth.btservice.ProfileService.IProfileServiceBinder; 67 import com.android.bluetooth.IObexConnectionHandler; 68 import com.android.bluetooth.ObexServerSockets; 69 import com.android.bluetooth.R; 70 import com.android.bluetooth.sdp.SdpManager; 71 import com.android.bluetooth.Utils; 72 import com.android.bluetooth.util.DevicePolicyUtils; 73 74 import java.io.IOException; 75 import java.util.Calendar; 76 import java.util.concurrent.atomic.AtomicLong; 77 import java.util.HashMap; 78 79 import javax.obex.ServerSession; 80 81 public class BluetoothPbapService extends ProfileService implements IObexConnectionHandler { 82 private static final String TAG = "BluetoothPbapService"; 83 84 /** 85 * To enable PBAP DEBUG/VERBOSE logging - run below cmd in adb shell, and 86 * restart com.android.bluetooth process. only enable DEBUG log: 87 * "setprop log.tag.BluetoothPbapService DEBUG"; enable both VERBOSE and 88 * DEBUG log: "setprop log.tag.BluetoothPbapService VERBOSE" 89 */ 90 91 public static final boolean DEBUG = true; 92 93 public static final boolean VERBOSE = false; 94 95 /** 96 * Intent indicating incoming obex authentication request which is from 97 * PCE(Carkit) 98 */ 99 public static final String AUTH_CHALL_ACTION = "com.android.bluetooth.pbap.authchall"; 100 101 /** 102 * Intent indicating obex session key input complete by user which is sent 103 * from BluetoothPbapActivity 104 */ 105 public static final String AUTH_RESPONSE_ACTION = "com.android.bluetooth.pbap.authresponse"; 106 107 /** 108 * Intent indicating user canceled obex authentication session key input 109 * which is sent from BluetoothPbapActivity 110 */ 111 public static final String AUTH_CANCELLED_ACTION = "com.android.bluetooth.pbap.authcancelled"; 112 113 /** 114 * Intent indicating timeout for user confirmation, which is sent to 115 * BluetoothPbapActivity 116 */ 117 public static final String USER_CONFIRM_TIMEOUT_ACTION = 118 "com.android.bluetooth.pbap.userconfirmtimeout"; 119 120 /** 121 * Intent Extra name indicating session key which is sent from 122 * BluetoothPbapActivity 123 */ 124 public static final String EXTRA_SESSION_KEY = "com.android.bluetooth.pbap.sessionkey"; 125 126 public static final String THIS_PACKAGE_NAME = "com.android.bluetooth"; 127 128 public static final int MSG_SERVERSESSION_CLOSE = 5000; 129 130 public static final int MSG_SESSION_ESTABLISHED = 5001; 131 132 public static final int MSG_SESSION_DISCONNECTED = 5002; 133 134 public static final int MSG_OBEX_AUTH_CHALL = 5003; 135 136 public static final int MSG_ACQUIRE_WAKE_LOCK = 5004; 137 138 public static final int MSG_RELEASE_WAKE_LOCK = 5005; 139 140 private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH; 141 142 private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN; 143 144 private static final int START_LISTENER = 1; 145 146 private static final int USER_TIMEOUT = 2; 147 148 private static final int AUTH_TIMEOUT = 3; 149 150 private static final int SHUTDOWN = 4; 151 152 protected static final int LOAD_CONTACTS = 5; 153 154 private static final int CHECK_SECONDARY_VERSION_COUNTER = 6; 155 156 protected static final int ROLLOVER_COUNTERS = 7; 157 158 private static final int USER_CONFIRM_TIMEOUT_VALUE = 30000; 159 160 private static final int RELEASE_WAKE_LOCK_DELAY = 10000; 161 162 // Ensure not conflict with Opp notification ID 163 private static final int NOTIFICATION_ID_ACCESS = -1000001; 164 165 private static final int NOTIFICATION_ID_AUTH = -1000002; 166 167 private static final String PBAP_NOTIFICATION_CHANNEL = "pbap_notification_channel"; 168 169 private PowerManager.WakeLock mWakeLock = null; 170 171 private BluetoothPbapAuthenticator mAuth = null; 172 173 private BluetoothPbapObexServer mPbapServer; 174 175 private ServerSession mServerSession = null; 176 177 private BluetoothServerSocket mServerSocket = null; 178 179 private BluetoothSocket mConnSocket = null; 180 181 private BluetoothDevice mRemoteDevice = null; 182 183 private static String sLocalPhoneNum = null; 184 185 private static String sLocalPhoneName = null; 186 187 private static String sRemoteDeviceName = null; 188 189 private volatile boolean mInterrupted; 190 191 private int mState; 192 193 private boolean mIsWaitingAuthorization = false; 194 195 private ObexServerSockets mServerSockets = null; 196 197 private static final int SDP_PBAP_SERVER_VERSION = 0x0102; 198 199 private static final int SDP_PBAP_SUPPORTED_REPOSITORIES = 0x0003; 200 201 private static final int SDP_PBAP_SUPPORTED_FEATURES = 0x021F; 202 203 private AlarmManager mAlarmManager = null; 204 205 private int mSdpHandle = -1; 206 207 private boolean mRemoveTimeoutMsg = false; 208 209 private int mPermission = BluetoothDevice.ACCESS_UNKNOWN; 210 211 private boolean mSdpSearchInitiated = false; 212 213 private boolean isRegisteredObserver = false; 214 215 protected Context mContext; 216 217 // package and class name to which we send intent to check phone book access permission 218 private static final String ACCESS_AUTHORITY_PACKAGE = "com.android.settings"; 219 private static final String ACCESS_AUTHORITY_CLASS = 220 "com.android.settings.bluetooth.BluetoothPermissionRequest"; 221 222 private class BluetoothPbapContentObserver extends ContentObserver { BluetoothPbapContentObserver()223 public BluetoothPbapContentObserver() { 224 super(new Handler()); 225 } 226 227 @Override onChange(boolean selfChange)228 public void onChange(boolean selfChange) { 229 Log.d(TAG, " onChange on contact uri "); 230 if (BluetoothPbapUtils.contactsLoaded) { 231 if (!mSessionStatusHandler.hasMessages(CHECK_SECONDARY_VERSION_COUNTER)) { 232 mSessionStatusHandler.sendMessage( 233 mSessionStatusHandler.obtainMessage(CHECK_SECONDARY_VERSION_COUNTER)); 234 } 235 } 236 } 237 } 238 239 private BluetoothPbapContentObserver mContactChangeObserver; 240 BluetoothPbapService()241 public BluetoothPbapService() { 242 mState = BluetoothPbap.STATE_DISCONNECTED; 243 mContext = this; 244 } 245 246 // process the intent from receiver parseIntent(final Intent intent)247 private void parseIntent(final Intent intent) { 248 String action = intent.getAction(); 249 if (DEBUG) Log.d(TAG, "action: " + action); 250 if (action == null) return; // Nothing to do 251 int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR); 252 if (DEBUG) Log.d(TAG, "state: " + state); 253 if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) { 254 if (state == BluetoothAdapter.STATE_TURNING_OFF) { 255 // Send any pending timeout now, as this service will be destroyed. 256 if (mSessionStatusHandler.hasMessages(USER_TIMEOUT)) { 257 mSessionStatusHandler.removeMessages(USER_TIMEOUT); 258 mSessionStatusHandler.obtainMessage(USER_TIMEOUT).sendToTarget(); 259 } 260 // Release all resources 261 closeService(); 262 } else if (state == BluetoothAdapter.STATE_ON) { 263 // start RFCOMM listener 264 mSessionStatusHandler.sendMessage(mSessionStatusHandler.obtainMessage(START_LISTENER)); 265 } 266 return; 267 } 268 269 if (action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED) && mIsWaitingAuthorization) { 270 BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); 271 272 if (mRemoteDevice == null) return; 273 if (DEBUG) Log.d(TAG,"ACL disconnected for "+ device); 274 if (mRemoteDevice.equals(device)) { 275 mSessionStatusHandler.removeMessages(USER_TIMEOUT); 276 mSessionStatusHandler.obtainMessage(USER_TIMEOUT).sendToTarget(); 277 } 278 return; 279 } 280 281 if (action.equals(BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY)) { 282 int requestType = intent.getIntExtra(BluetoothDevice.EXTRA_ACCESS_REQUEST_TYPE, 283 BluetoothDevice.REQUEST_TYPE_PHONEBOOK_ACCESS); 284 285 if ((!mIsWaitingAuthorization) 286 || (requestType != BluetoothDevice.REQUEST_TYPE_PHONEBOOK_ACCESS)) { 287 // this reply is not for us 288 return; 289 } 290 291 mSessionStatusHandler.removeMessages(USER_TIMEOUT); 292 mIsWaitingAuthorization = false; 293 294 if (intent.getIntExtra(BluetoothDevice.EXTRA_CONNECTION_ACCESS_RESULT, 295 BluetoothDevice.CONNECTION_ACCESS_NO) 296 == BluetoothDevice.CONNECTION_ACCESS_YES) { 297 if (intent.getBooleanExtra(BluetoothDevice.EXTRA_ALWAYS_ALLOWED, false)) { 298 boolean result = mRemoteDevice.setPhonebookAccessPermission( 299 BluetoothDevice.ACCESS_ALLOWED); 300 if (VERBOSE) { 301 Log.v(TAG, "setPhonebookAccessPermission(ACCESS_ALLOWED)=" + result); 302 } 303 } 304 try { 305 if (mConnSocket != null) { 306 startObexServerSession(); 307 } else { 308 stopObexServerSession(); 309 } 310 } catch (IOException ex) { 311 Log.e(TAG, "Caught the error: " + ex.toString()); 312 } 313 } else { 314 if (intent.getBooleanExtra(BluetoothDevice.EXTRA_ALWAYS_ALLOWED, false)) { 315 boolean result = mRemoteDevice.setPhonebookAccessPermission( 316 BluetoothDevice.ACCESS_REJECTED); 317 if (VERBOSE) { 318 Log.v(TAG, "setPhonebookAccessPermission(ACCESS_REJECTED)=" + result); 319 } 320 } 321 stopObexServerSession(); 322 } 323 return; 324 } 325 326 if (action.equals(AUTH_RESPONSE_ACTION)) { 327 String sessionkey = intent.getStringExtra(EXTRA_SESSION_KEY); 328 notifyAuthKeyInput(sessionkey); 329 } else if (action.equals(AUTH_CANCELLED_ACTION)) { 330 notifyAuthCancelled(); 331 } else { 332 Log.w(TAG, "Unrecognized intent!"); 333 return; 334 } 335 336 mSessionStatusHandler.removeMessages(USER_TIMEOUT); 337 } 338 339 private BroadcastReceiver mPbapReceiver = new BroadcastReceiver() { 340 @Override 341 public void onReceive(Context context, Intent intent) { 342 parseIntent(intent); 343 } 344 }; 345 initSocket()346 private final boolean initSocket() { 347 if (VERBOSE) Log.v(TAG, "Pbap Service initSocket"); 348 349 boolean initSocketOK = false; 350 final int CREATE_RETRY_TIME = 10; 351 352 // It's possible that create will fail in some cases. retry for 10 times 353 for (int i = 0; i < CREATE_RETRY_TIME && !mInterrupted; i++) { 354 initSocketOK = true; 355 try { 356 // It is mandatory for PSE to support initiation of bonding and 357 // encryption. 358 mServerSocket = mAdapter.listenUsingEncryptedRfcommWithServiceRecord 359 ("OBEX Phonebook Access Server", BluetoothUuid.PBAP_PSE.getUuid()); 360 361 } catch (IOException e) { 362 Log.e(TAG, "Error create RfcommServerSocket " + e.toString()); 363 initSocketOK = false; 364 } 365 if (!initSocketOK) { 366 // Need to break out of this loop if BT is being turned off. 367 if (mAdapter == null) break; 368 int state = mAdapter.getState(); 369 if ((state != BluetoothAdapter.STATE_TURNING_ON) && 370 (state != BluetoothAdapter.STATE_ON)) { 371 Log.w(TAG, "initServerSocket failed as BT is (being) turned off"); 372 break; 373 } 374 try { 375 if (VERBOSE) Log.v(TAG, "wait 300 ms"); 376 Thread.sleep(300); 377 } catch (InterruptedException e) { 378 Log.e(TAG, "socketAcceptThread thread was interrupted (3)"); 379 break; 380 } 381 } else { 382 break; 383 } 384 } 385 386 if (mInterrupted) { 387 initSocketOK = false; 388 // close server socket to avoid resource leakage 389 closeServerSocket(); 390 } 391 392 if (initSocketOK) { 393 if (VERBOSE) Log.v(TAG, "Succeed to create listening socket "); 394 395 } else { 396 Log.e(TAG, "Error to create listening socket after " + CREATE_RETRY_TIME + " try"); 397 } 398 return initSocketOK; 399 } 400 closeServerSocket()401 private final synchronized void closeServerSocket() { 402 // exit SocketAcceptThread early 403 if (mServerSocket != null) { 404 try { 405 // this will cause mServerSocket.accept() return early with IOException 406 mServerSocket.close(); 407 mServerSocket = null; 408 } catch (IOException ex) { 409 Log.e(TAG, "Close Server Socket error: " + ex); 410 } 411 } 412 } 413 closeConnectionSocket()414 private final synchronized void closeConnectionSocket() { 415 if (mConnSocket != null) { 416 try { 417 mConnSocket.close(); 418 mConnSocket = null; 419 } catch (IOException e) { 420 Log.e(TAG, "Close Connection Socket error: " + e.toString()); 421 } 422 } 423 } 424 closeService()425 private final void closeService() { 426 if (VERBOSE) Log.v(TAG, "Pbap Service closeService in"); 427 428 BluetoothPbapUtils.savePbapParams(this, BluetoothPbapUtils.primaryVersionCounter, 429 BluetoothPbapUtils.secondaryVersionCounter, BluetoothPbapUtils.mDbIdentifier.get(), 430 BluetoothPbapUtils.contactsLastUpdated, BluetoothPbapUtils.totalFields, 431 BluetoothPbapUtils.totalSvcFields, BluetoothPbapUtils.totalContacts); 432 433 // exit initSocket early 434 mInterrupted = true; 435 if (mWakeLock != null) { 436 mWakeLock.release(); 437 mWakeLock = null; 438 } 439 440 if (mServerSession != null) { 441 mServerSession.close(); 442 mServerSession = null; 443 } 444 445 closeConnectionSocket(); 446 closeServerSocket(); 447 if (mSessionStatusHandler != null) mSessionStatusHandler.removeCallbacksAndMessages(null); 448 if (VERBOSE) Log.v(TAG, "Pbap Service closeService out"); 449 } 450 startObexServerSession()451 private final void startObexServerSession() throws IOException { 452 if (VERBOSE) Log.v(TAG, "Pbap Service startObexServerSession"); 453 454 // acquire the wakeLock before start Obex transaction thread 455 if (mWakeLock == null) { 456 PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE); 457 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, 458 "StartingObexPbapTransaction"); 459 mWakeLock.setReferenceCounted(false); 460 mWakeLock.acquire(); 461 } 462 TelephonyManager tm = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE); 463 if (tm != null) { 464 sLocalPhoneNum = tm.getLine1Number(); 465 sLocalPhoneName = tm.getLine1AlphaTag(); 466 if (TextUtils.isEmpty(sLocalPhoneName)) { 467 sLocalPhoneName = this.getString(R.string.localPhoneName); 468 } 469 } 470 471 mPbapServer = new BluetoothPbapObexServer(mSessionStatusHandler, this); 472 synchronized (this) { 473 mAuth = new BluetoothPbapAuthenticator(mSessionStatusHandler); 474 mAuth.setChallenged(false); 475 mAuth.setCancelled(false); 476 } 477 BluetoothObexTransport transport = new BluetoothObexTransport(mConnSocket); 478 mServerSession = new ServerSession(transport, mPbapServer, mAuth); 479 setState(BluetoothPbap.STATE_CONNECTED); 480 481 mSessionStatusHandler.removeMessages(MSG_RELEASE_WAKE_LOCK); 482 mSessionStatusHandler.sendMessageDelayed(mSessionStatusHandler 483 .obtainMessage(MSG_RELEASE_WAKE_LOCK), RELEASE_WAKE_LOCK_DELAY); 484 485 if (VERBOSE) { 486 Log.v(TAG, "startObexServerSession() success!"); 487 } 488 } 489 stopObexServerSession()490 private void stopObexServerSession() { 491 if (VERBOSE) Log.v(TAG, "Pbap Service stopObexServerSession"); 492 mSessionStatusHandler.removeMessages(MSG_ACQUIRE_WAKE_LOCK); 493 mSessionStatusHandler.removeMessages(MSG_RELEASE_WAKE_LOCK); 494 // Release the wake lock if obex transaction is over 495 if (mWakeLock != null) { 496 mWakeLock.release(); 497 mWakeLock = null; 498 } 499 500 if (mServerSession != null) { 501 mServerSession.close(); 502 mServerSession = null; 503 } 504 closeConnectionSocket(); 505 506 // Last obex transaction is finished, we start to listen for incoming 507 // connection again 508 if (mAdapter != null && mAdapter.isEnabled()) { 509 startSocketListeners(); 510 } 511 setState(BluetoothPbap.STATE_DISCONNECTED); 512 } 513 notifyAuthKeyInput(final String key)514 private void notifyAuthKeyInput(final String key) { 515 synchronized (mAuth) { 516 if (key != null) { 517 mAuth.setSessionKey(key); 518 } 519 mAuth.setChallenged(true); 520 mAuth.notify(); 521 } 522 } 523 notifyAuthCancelled()524 private void notifyAuthCancelled() { 525 synchronized (mAuth) { 526 mAuth.setCancelled(true); 527 mAuth.notify(); 528 } 529 } 530 531 /** 532 * A thread that runs in the background waiting for remote rfcomm 533 * connect.Once a remote socket connected, this thread shall be 534 * shutdown.When the remote disconnect,this thread shall run again waiting 535 * for next request. 536 */ 537 private class SocketAcceptThread extends Thread { 538 539 private boolean stopped = false; 540 541 @Override run()542 public void run() { 543 BluetoothServerSocket serverSocket; 544 if (mServerSocket == null) { 545 if (!initSocket()) { 546 return; 547 } 548 } 549 550 while (!stopped) { 551 try { 552 if (VERBOSE) Log.v(TAG, "Accepting socket connection..."); 553 serverSocket = mServerSocket; 554 if (serverSocket == null) { 555 Log.w(TAG, "mServerSocket is null"); 556 break; 557 } 558 mConnSocket = serverSocket.accept(); 559 if (VERBOSE) Log.v(TAG, "Accepted socket connection..."); 560 561 synchronized (BluetoothPbapService.this) { 562 if (mConnSocket == null) { 563 Log.w(TAG, "mConnSocket is null"); 564 break; 565 } 566 mRemoteDevice = mConnSocket.getRemoteDevice(); 567 } 568 if (mRemoteDevice == null) { 569 Log.i(TAG, "getRemoteDevice() = null"); 570 break; 571 } 572 sRemoteDeviceName = mRemoteDevice.getName(); 573 // In case getRemoteName failed and return null 574 if (TextUtils.isEmpty(sRemoteDeviceName)) { 575 sRemoteDeviceName = getString(R.string.defaultname); 576 } 577 int permission = mRemoteDevice.getPhonebookAccessPermission(); 578 if (VERBOSE) Log.v(TAG, "getPhonebookAccessPermission() = " + permission); 579 580 if (permission == BluetoothDevice.ACCESS_ALLOWED) { 581 try { 582 if (VERBOSE) { 583 Log.v(TAG, "incoming connection accepted from: " + sRemoteDeviceName 584 + " automatically as already allowed device"); 585 } 586 startObexServerSession(); 587 } catch (IOException ex) { 588 Log.e(TAG, "Caught exception starting obex server session" 589 + ex.toString()); 590 } 591 } else if (permission == BluetoothDevice.ACCESS_REJECTED) { 592 if (VERBOSE) { 593 Log.v(TAG, "incoming connection rejected from: " + sRemoteDeviceName 594 + " automatically as already rejected device"); 595 } 596 stopObexServerSession(); 597 } else { // permission == BluetoothDevice.ACCESS_UNKNOWN 598 // Send an Intent to Settings app to ask user preference. 599 Intent intent = 600 new Intent(BluetoothDevice.ACTION_CONNECTION_ACCESS_REQUEST); 601 intent.setPackage(getString(R.string.pairing_ui_package)); 602 intent.putExtra(BluetoothDevice.EXTRA_ACCESS_REQUEST_TYPE, 603 BluetoothDevice.REQUEST_TYPE_PHONEBOOK_ACCESS); 604 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mRemoteDevice); 605 intent.putExtra(BluetoothDevice.EXTRA_PACKAGE_NAME, getPackageName()); 606 intent.putExtra(BluetoothDevice.EXTRA_CLASS_NAME, getName()); 607 608 mIsWaitingAuthorization = true; 609 sendOrderedBroadcast(intent, BLUETOOTH_ADMIN_PERM); 610 611 if (VERBOSE) Log.v(TAG, "waiting for authorization for connection from: " 612 + sRemoteDeviceName); 613 614 // In case car kit time out and try to use HFP for 615 // phonebook 616 // access, while UI still there waiting for user to 617 // confirm 618 mSessionStatusHandler.sendMessageDelayed(mSessionStatusHandler 619 .obtainMessage(USER_TIMEOUT), USER_CONFIRM_TIMEOUT_VALUE); 620 // We will continue the process when we receive 621 // BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY from Settings app. 622 } 623 stopped = true; // job done ,close this thread; 624 } catch (IOException ex) { 625 stopped=true; 626 /* 627 if (stopped) { 628 break; 629 } 630 */ 631 if (VERBOSE) Log.v(TAG, "Accept exception: " + ex.toString()); 632 } 633 } 634 } 635 shutdown()636 void shutdown() { 637 stopped = true; 638 interrupt(); 639 } 640 } 641 642 protected final Handler mSessionStatusHandler = new Handler() { 643 @Override 644 public void handleMessage(Message msg) { 645 if (VERBOSE) Log.v(TAG, "Handler(): got msg=" + msg.what); 646 647 switch (msg.what) { 648 case START_LISTENER: 649 if (mAdapter.isEnabled()) { 650 startSocketListeners(); 651 } 652 break; 653 case USER_TIMEOUT: 654 Intent intent = new Intent(BluetoothDevice.ACTION_CONNECTION_ACCESS_CANCEL); 655 intent.setPackage(getString(R.string.pairing_ui_package)); 656 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mRemoteDevice); 657 intent.putExtra(BluetoothDevice.EXTRA_ACCESS_REQUEST_TYPE, 658 BluetoothDevice.REQUEST_TYPE_PHONEBOOK_ACCESS); 659 sendBroadcast(intent, BLUETOOTH_ADMIN_PERM); 660 mIsWaitingAuthorization = false; 661 stopObexServerSession(); 662 break; 663 case AUTH_TIMEOUT: 664 Intent i = new Intent(USER_CONFIRM_TIMEOUT_ACTION); 665 sendBroadcast(i); 666 removePbapNotification(NOTIFICATION_ID_AUTH); 667 notifyAuthCancelled(); 668 break; 669 case MSG_SERVERSESSION_CLOSE: 670 stopObexServerSession(); 671 break; 672 case MSG_SESSION_ESTABLISHED: 673 break; 674 case MSG_SESSION_DISCONNECTED: 675 // case MSG_SERVERSESSION_CLOSE will handle ,so just skip 676 break; 677 case MSG_OBEX_AUTH_CHALL: 678 createPbapNotification(AUTH_CHALL_ACTION); 679 mSessionStatusHandler.sendMessageDelayed(mSessionStatusHandler 680 .obtainMessage(AUTH_TIMEOUT), USER_CONFIRM_TIMEOUT_VALUE); 681 break; 682 case MSG_ACQUIRE_WAKE_LOCK: 683 if (mWakeLock == null) { 684 PowerManager pm = (PowerManager)getSystemService( 685 Context.POWER_SERVICE); 686 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, 687 "StartingObexPbapTransaction"); 688 mWakeLock.setReferenceCounted(false); 689 mWakeLock.acquire(); 690 Log.w(TAG, "Acquire Wake Lock"); 691 } 692 mSessionStatusHandler.removeMessages(MSG_RELEASE_WAKE_LOCK); 693 mSessionStatusHandler.sendMessageDelayed(mSessionStatusHandler 694 .obtainMessage(MSG_RELEASE_WAKE_LOCK), RELEASE_WAKE_LOCK_DELAY); 695 break; 696 case MSG_RELEASE_WAKE_LOCK: 697 if (mWakeLock != null) { 698 mWakeLock.release(); 699 mWakeLock = null; 700 Log.w(TAG, "Release Wake Lock"); 701 } 702 break; 703 case SHUTDOWN: 704 closeService(); 705 break; 706 case LOAD_CONTACTS: 707 BluetoothPbapUtils.loadAllContacts(mContext, this); 708 break; 709 case CHECK_SECONDARY_VERSION_COUNTER: 710 BluetoothPbapUtils.updateSecondaryVersionCounter(mContext, this); 711 break; 712 case ROLLOVER_COUNTERS: 713 BluetoothPbapUtils.rolloverCounters(); 714 break; 715 default: 716 break; 717 } 718 } 719 }; 720 setState(int state)721 private void setState(int state) { 722 setState(state, BluetoothPbap.RESULT_SUCCESS); 723 } 724 setState(int state, int result)725 private synchronized void setState(int state, int result) { 726 if (state != mState) { 727 if (DEBUG) Log.d(TAG, "Pbap state " + mState + " -> " + state + ", result = " 728 + result); 729 int prevState = mState; 730 mState = state; 731 Intent intent = new Intent(BluetoothPbap.PBAP_STATE_CHANGED_ACTION); 732 intent.putExtra(BluetoothPbap.PBAP_PREVIOUS_STATE, prevState); 733 intent.putExtra(BluetoothPbap.PBAP_STATE, mState); 734 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mRemoteDevice); 735 sendBroadcast(intent, BLUETOOTH_PERM); 736 } 737 } 738 getState()739 protected int getState() { 740 return mState; 741 } 742 getRemoteDevice()743 protected BluetoothDevice getRemoteDevice() { 744 return mRemoteDevice; 745 } 746 createPbapNotification(String action)747 private void createPbapNotification(String action) { 748 749 NotificationManager nm = (NotificationManager) 750 getSystemService(Context.NOTIFICATION_SERVICE); 751 NotificationChannel notificationChannel = new NotificationChannel(PBAP_NOTIFICATION_CHANNEL, 752 getString(R.string.pbap_notification_group), NotificationManager.IMPORTANCE_HIGH); 753 nm.createNotificationChannel(notificationChannel); 754 755 // Create an intent triggered by clicking on the status icon. 756 Intent clickIntent = new Intent(); 757 clickIntent.setClass(this, BluetoothPbapActivity.class); 758 clickIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 759 clickIntent.setAction(action); 760 761 // Create an intent triggered by clicking on the 762 // "Clear All Notifications" button 763 Intent deleteIntent = new Intent(); 764 deleteIntent.setClass(this, BluetoothPbapService.class); 765 deleteIntent.setAction(AUTH_CANCELLED_ACTION); 766 767 String name = getRemoteDeviceName(); 768 769 if (action.equals(AUTH_CHALL_ACTION)) { 770 Notification notification = 771 new Notification.Builder(this, PBAP_NOTIFICATION_CHANNEL) 772 .setWhen(System.currentTimeMillis()) 773 .setContentTitle(getString(R.string.auth_notif_title)) 774 .setContentText(getString(R.string.auth_notif_message, name)) 775 .setSmallIcon(android.R.drawable.stat_sys_data_bluetooth) 776 .setTicker(getString(R.string.auth_notif_ticker)) 777 .setColor(getResources().getColor( 778 com.android.internal.R.color.system_notification_accent_color, 779 this.getTheme())) 780 .setFlag(Notification.FLAG_AUTO_CANCEL, true) 781 .setFlag(Notification.FLAG_ONLY_ALERT_ONCE, true) 782 .setDefaults(Notification.DEFAULT_SOUND) 783 .setContentIntent(PendingIntent.getActivity(this, 0, clickIntent, 0)) 784 .setDeleteIntent(PendingIntent.getBroadcast(this, 0, deleteIntent, 0)) 785 .build(); 786 nm.notify(NOTIFICATION_ID_AUTH, notification); 787 } 788 } 789 removePbapNotification(int id)790 private void removePbapNotification(int id) { 791 NotificationManager nm = (NotificationManager) 792 getSystemService(Context.NOTIFICATION_SERVICE); 793 nm.cancel(id); 794 } 795 getLocalPhoneNum()796 public static String getLocalPhoneNum() { 797 return sLocalPhoneNum; 798 } 799 getLocalPhoneName()800 public static String getLocalPhoneName() { 801 return sLocalPhoneName; 802 } 803 getRemoteDeviceName()804 public static String getRemoteDeviceName() { 805 return sRemoteDeviceName; 806 } 807 808 @Override initBinder()809 protected IProfileServiceBinder initBinder() { 810 return new PbapBinder(this); 811 } 812 813 @Override start()814 protected boolean start() { 815 Log.v(TAG, "start()"); 816 IntentFilter filter = new IntentFilter(); 817 filter.addAction(BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY); 818 filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); 819 filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED); 820 filter.addAction(AUTH_RESPONSE_ACTION); 821 filter.addAction(AUTH_CANCELLED_ACTION); 822 mInterrupted = false; 823 BluetoothPbapConfig.init(this); 824 mSessionStatusHandler.sendMessage(mSessionStatusHandler.obtainMessage(START_LISTENER)); 825 if (mContactChangeObserver == null) { 826 registerReceiver(mPbapReceiver, filter); 827 try { 828 if (DEBUG) Log.d(TAG, "Registering observer"); 829 mContactChangeObserver = new BluetoothPbapContentObserver(); 830 getContentResolver().registerContentObserver( 831 DevicePolicyUtils.getEnterprisePhoneUri(this), false, 832 mContactChangeObserver); 833 } catch (SQLiteException e) { 834 Log.e(TAG, "SQLite exception: " + e); 835 } catch (IllegalStateException e) { 836 Log.e(TAG, "Illegal state exception, content observer is already registered"); 837 } 838 } 839 return true; 840 } 841 842 @Override stop()843 protected boolean stop() { 844 Log.v(TAG, "stop()"); 845 if (mContactChangeObserver == null) { 846 Log.i(TAG, "Avoid unregister when receiver it is not registered"); 847 return true; 848 } 849 try { 850 unregisterReceiver(mPbapReceiver); 851 getContentResolver().unregisterContentObserver(mContactChangeObserver); 852 mContactChangeObserver = null; 853 } catch (Exception e) { 854 Log.w(TAG, "Unable to unregister pbap receiver", e); 855 } 856 mSessionStatusHandler.obtainMessage(SHUTDOWN).sendToTarget(); 857 setState(BluetoothPbap.STATE_DISCONNECTED, BluetoothPbap.RESULT_CANCELED); 858 return true; 859 } 860 disconnect()861 protected void disconnect() { 862 synchronized (this) { 863 if (mState == BluetoothPbap.STATE_CONNECTED) { 864 if (mServerSession != null) { 865 mServerSession.close(); 866 mServerSession = null; 867 } 868 869 closeConnectionSocket(); 870 871 setState(BluetoothPbap.STATE_DISCONNECTED, BluetoothPbap.RESULT_CANCELED); 872 } 873 } 874 } 875 876 // Has to be a static class or a memory leak can occur. 877 private static class PbapBinder extends IBluetoothPbap.Stub implements IProfileServiceBinder { 878 private BluetoothPbapService mService; 879 getService(String perm)880 private BluetoothPbapService getService(String perm) { 881 if (!Utils.checkCaller()) { 882 Log.w(TAG, "not allowed for non-active user"); 883 return null; 884 } 885 if (mService != null && mService.isAvailable()) { 886 mService.enforceCallingOrSelfPermission(perm, "Need " + perm + " permission"); 887 return mService; 888 } 889 return null; 890 } 891 PbapBinder(BluetoothPbapService service)892 PbapBinder(BluetoothPbapService service) { 893 Log.v(TAG, "PbapBinder()"); 894 mService = service; 895 } 896 cleanup()897 public boolean cleanup() { 898 mService = null; 899 return true; 900 } 901 getState()902 public int getState() { 903 if (DEBUG) Log.d(TAG, "getState = " + mService.getState()); 904 BluetoothPbapService service = getService(BLUETOOTH_PERM); 905 if (service == null) return BluetoothPbap.STATE_DISCONNECTED; 906 907 return service.getState(); 908 } 909 getClient()910 public BluetoothDevice getClient() { 911 if (DEBUG) Log.d(TAG, "getClient = " + mService.getRemoteDevice()); 912 BluetoothPbapService service = getService(BLUETOOTH_PERM); 913 if (service == null) return null; 914 return service.getRemoteDevice(); 915 } 916 isConnected(BluetoothDevice device)917 public boolean isConnected(BluetoothDevice device) { 918 if (DEBUG) Log.d(TAG, "isConnected " + device); 919 BluetoothPbapService service = getService(BLUETOOTH_PERM); 920 if (service == null) return false; 921 return service.getState() == BluetoothPbap.STATE_CONNECTED 922 && service.getRemoteDevice().equals(device); 923 } 924 connect(BluetoothDevice device)925 public boolean connect(BluetoothDevice device) { 926 BluetoothPbapService service = getService(BLUETOOTH_ADMIN_PERM); 927 return false; 928 } 929 disconnect()930 public void disconnect() { 931 if (DEBUG) Log.d(TAG, "disconnect"); 932 BluetoothPbapService service = getService(BLUETOOTH_ADMIN_PERM); 933 if (service == null) return; 934 service.disconnect(); 935 } 936 } 937 startSocketListeners()938 synchronized private void startSocketListeners() { 939 if (DEBUG) Log.d(TAG, "startsocketListener"); 940 if (mServerSession != null) { 941 if (DEBUG) Log.d(TAG, "mServerSession exists - shutting it down..."); 942 mServerSession.close(); 943 mServerSession = null; 944 } 945 closeConnectionSocket(); 946 if (mServerSockets != null) { 947 mServerSockets.prepareForNewConnect(); 948 } else { 949 mServerSockets = ObexServerSockets.create(this); 950 if (mServerSockets == null) { 951 // TODO: Handle - was not handled before 952 Log.e(TAG, "Failed to start the listeners"); 953 return; 954 } 955 SdpManager sdpManager = SdpManager.getDefaultManager(); 956 if (sdpManager == null) { 957 Log.e(TAG, "Failed to start the listeners sdp null "); 958 return; 959 } 960 if (mAdapter != null && mSdpHandle >= 0) { 961 Log.d(TAG, "Removing SDP record for PBAP with SDP handle:" + mSdpHandle); 962 boolean status = sdpManager.removeSdpRecord(mSdpHandle); 963 Log.d(TAG, "RemoveSDPrecord returns " + status); 964 mSdpHandle = -1; 965 } 966 mSdpHandle = SdpManager.getDefaultManager().createPbapPseRecord( 967 "OBEX Phonebook Access Server", mServerSockets.getRfcommChannel(), 968 mServerSockets.getL2capPsm(), SDP_PBAP_SERVER_VERSION, 969 SDP_PBAP_SUPPORTED_REPOSITORIES, SDP_PBAP_SUPPORTED_FEATURES); 970 // fetch Pbap Params to check if significant change has happened to Database 971 BluetoothPbapUtils.fetchPbapParams(mContext); 972 973 if (DEBUG) Log.d(TAG, "PBAP server with handle:" + mSdpHandle); 974 } 975 } 976 getDbIdentifier()977 long getDbIdentifier() { 978 return BluetoothPbapUtils.mDbIdentifier.get(); 979 } 980 setUserTimeoutAlarm()981 private void setUserTimeoutAlarm() { 982 if (DEBUG) Log.d(TAG, "SetUserTimeOutAlarm()"); 983 if (mAlarmManager == null) { 984 mAlarmManager = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE); 985 } 986 mRemoveTimeoutMsg = true; 987 Intent timeoutIntent = new Intent(USER_CONFIRM_TIMEOUT_ACTION); 988 PendingIntent pIntent = PendingIntent.getBroadcast(this, 0, timeoutIntent, 0); 989 mAlarmManager.set(AlarmManager.RTC_WAKEUP, 990 System.currentTimeMillis() + USER_CONFIRM_TIMEOUT_VALUE, pIntent); 991 } 992 993 @Override onConnect(BluetoothDevice remoteDevice, BluetoothSocket socket)994 public boolean onConnect(BluetoothDevice remoteDevice, BluetoothSocket socket) { 995 mRemoteDevice = remoteDevice; 996 if (mRemoteDevice == null || socket == null) { 997 Log.i(TAG, "mRemoteDevice :" + mRemoteDevice + " socket :" + socket); 998 return false; 999 } 1000 mConnSocket = socket; 1001 sRemoteDeviceName = mRemoteDevice.getName(); 1002 // In case getRemoteName failed and return null 1003 if (TextUtils.isEmpty(sRemoteDeviceName)) { 1004 sRemoteDeviceName = getString(R.string.defaultname); 1005 } 1006 int permission = mRemoteDevice.getPhonebookAccessPermission(); 1007 if (DEBUG) Log.d(TAG, "getPhonebookAccessPermission() = " + permission); 1008 1009 if (permission == BluetoothDevice.ACCESS_ALLOWED) { 1010 try { 1011 startObexServerSession(); 1012 } catch (IOException ex) { 1013 Log.e(TAG, "Caught exception starting obex server session" + ex.toString()); 1014 } 1015 1016 if (!BluetoothPbapUtils.contactsLoaded) { 1017 mSessionStatusHandler.sendMessage( 1018 mSessionStatusHandler.obtainMessage(LOAD_CONTACTS)); 1019 } 1020 1021 } else if (permission == BluetoothDevice.ACCESS_REJECTED) { 1022 if (DEBUG) { 1023 Log.d(TAG, "incoming connection rejected from: " + sRemoteDeviceName 1024 + " automatically as already rejected device"); 1025 } 1026 return false; 1027 } else { // permission == BluetoothDevice.ACCESS_UNKNOWN 1028 // Send an Intent to Settings app to ask user preference. 1029 Intent intent = new Intent(BluetoothDevice.ACTION_CONNECTION_ACCESS_REQUEST); 1030 intent.setClassName(ACCESS_AUTHORITY_PACKAGE, ACCESS_AUTHORITY_CLASS); 1031 intent.putExtra(BluetoothDevice.EXTRA_ACCESS_REQUEST_TYPE, 1032 BluetoothDevice.REQUEST_TYPE_PHONEBOOK_ACCESS); 1033 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mRemoteDevice); 1034 intent.putExtra(BluetoothDevice.EXTRA_PACKAGE_NAME, getPackageName()); 1035 mIsWaitingAuthorization = true; 1036 sendOrderedBroadcast(intent, BLUETOOTH_ADMIN_PERM); 1037 if (VERBOSE) 1038 Log.v(TAG, "waiting for authorization for connection from: " + sRemoteDeviceName); 1039 /* In case car kit time out and try to use HFP for phonebook 1040 * access, while UI still there waiting for user to confirm */ 1041 mSessionStatusHandler.sendMessageDelayed( 1042 mSessionStatusHandler.obtainMessage(USER_TIMEOUT), USER_CONFIRM_TIMEOUT_VALUE); 1043 /* We will continue the process when we receive 1044 * BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY from Settings app. */ 1045 } 1046 return true; 1047 }; 1048 1049 /** 1050 * Called when an unrecoverable error occurred in an accept thread. 1051 * Close down the server socket, and restart. 1052 * TODO: Change to message, to call start in correct context. 1053 */ 1054 @Override onAcceptFailed()1055 public synchronized void onAcceptFailed() { 1056 // Force socket listener to restart 1057 mServerSockets = null; 1058 if (!mInterrupted && mAdapter != null && mAdapter.isEnabled()) { 1059 startSocketListeners(); 1060 } 1061 } 1062 } 1063