1 package com.android.bluetooth.sap;
2 
3 import static android.Manifest.permission.BLUETOOTH_CONNECT;
4 
5 import android.annotation.RequiresPermission;
6 import android.annotation.TargetApi;
7 import android.app.AlarmManager;
8 import android.app.PendingIntent;
9 import android.bluetooth.BluetoothAdapter;
10 import android.bluetooth.BluetoothDevice;
11 import android.bluetooth.BluetoothProfile;
12 import android.bluetooth.BluetoothSap;
13 import android.bluetooth.BluetoothServerSocket;
14 import android.bluetooth.BluetoothSocket;
15 import android.bluetooth.BluetoothUuid;
16 import android.bluetooth.IBluetoothSap;
17 import android.content.Attributable;
18 import android.content.AttributionSource;
19 import android.content.BroadcastReceiver;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.content.IntentFilter;
23 import android.os.Build;
24 import android.os.Handler;
25 import android.os.Message;
26 import android.os.ParcelUuid;
27 import android.os.PowerManager;
28 import android.text.TextUtils;
29 import android.util.Log;
30 
31 import com.android.bluetooth.BluetoothMetricsProto;
32 import com.android.bluetooth.R;
33 import com.android.bluetooth.Utils;
34 import com.android.bluetooth.btservice.AdapterService;
35 import com.android.bluetooth.btservice.MetricsLogger;
36 import com.android.bluetooth.btservice.ProfileService;
37 import com.android.bluetooth.sdp.SdpManager;
38 import com.android.internal.annotations.VisibleForTesting;
39 
40 import java.io.IOException;
41 import java.util.ArrayList;
42 import java.util.List;
43 import java.util.Set;
44 
45 @TargetApi(Build.VERSION_CODES.ECLAIR)
46 public class SapService extends ProfileService {
47 
48     private static final String SDP_SAP_SERVICE_NAME = "SIM Access";
49     private static final int SDP_SAP_VERSION = 0x0102;
50     private static final String TAG = "SapService";
51     public static final boolean DEBUG = false;
52     public static final boolean VERBOSE = false;
53 
54     /* Message ID's */
55     private static final int START_LISTENER = 1;
56     private static final int USER_TIMEOUT = 2;
57     private static final int SHUTDOWN = 3;
58 
59     public static final int MSG_SERVERSESSION_CLOSE = 5000;
60     public static final int MSG_SESSION_ESTABLISHED = 5001;
61     public static final int MSG_SESSION_DISCONNECTED = 5002;
62 
63     public static final int MSG_ACQUIRE_WAKE_LOCK = 5005;
64     public static final int MSG_RELEASE_WAKE_LOCK = 5006;
65 
66     public static final int MSG_CHANGE_STATE = 5007;
67 
68     /* Each time a transaction between the SIM and the BT Client is detected a wakelock is taken.
69      * After an idle period of RELEASE_WAKE_LOCK_DELAY ms the wakelock is released.
70      *
71      * NOTE: While connected the the Nokia 616 car-kit it was noticed that the carkit do
72      *       TRANSFER_APDU_REQ with 20-30 seconds interval, and it sends no requests less than 1 sec
73      *       apart. Additionally the responses from the RIL seems to come within 100 ms, hence a
74      *       one second timeout should be enough.
75      */
76     private static final int RELEASE_WAKE_LOCK_DELAY = 1000;
77 
78     /* Intent indicating timeout for user confirmation. */
79     public static final String USER_CONFIRM_TIMEOUT_ACTION =
80             "com.android.bluetooth.sap.USER_CONFIRM_TIMEOUT";
81     private static final int USER_CONFIRM_TIMEOUT_VALUE = 25000;
82 
83     private PowerManager.WakeLock mWakeLock = null;
84     private AdapterService mAdapterService;
85     private SocketAcceptThread mAcceptThread = null;
86     private BluetoothServerSocket mServerSocket = null;
87     private int mSdpHandle = -1;
88     private BluetoothSocket mConnSocket = null;
89     private BluetoothDevice mRemoteDevice = null;
90     private static String sRemoteDeviceName = null;
91     private volatile boolean mInterrupted;
92     private int mState;
93     private SapServer mSapServer = null;
94     private AlarmManager mAlarmManager = null;
95     private boolean mRemoveTimeoutMsg = false;
96 
97     private boolean mIsWaitingAuthorization = false;
98     private boolean mIsRegistered = false;
99 
100     private static SapService sSapService;
101 
102     private static final ParcelUuid[] SAP_UUIDS = {
103             BluetoothUuid.SAP,
104     };
105 
106 
SapService()107     public SapService() {
108         mState = BluetoothSap.STATE_DISCONNECTED;
109     }
110 
111     /***
112      * Call this when ever an activity is detected to renew the wakelock
113      *
114      * @param messageHandler reference to the handler to notify
115      *  - typically mSessionStatusHandler, but it cannot be accessed in a static manner.
116      */
notifyUpdateWakeLock(Handler messageHandler)117     public static void notifyUpdateWakeLock(Handler messageHandler) {
118         if (messageHandler != null) {
119             Message msg = Message.obtain(messageHandler);
120             msg.what = MSG_ACQUIRE_WAKE_LOCK;
121             msg.sendToTarget();
122         }
123     }
124 
removeSdpRecord()125     private void removeSdpRecord() {
126         if (mAdapterService != null && mSdpHandle >= 0 && SdpManager.getDefaultManager() != null) {
127             if (VERBOSE) {
128                 Log.d(TAG, "Removing SDP record handle: " + mSdpHandle);
129             }
130             boolean status = SdpManager.getDefaultManager().removeSdpRecord(mSdpHandle);
131             mSdpHandle = -1;
132         }
133     }
134 
startRfcommSocketListener()135     private void startRfcommSocketListener() {
136         if (VERBOSE) {
137             Log.v(TAG, "Sap Service startRfcommSocketListener");
138         }
139 
140         if (mAcceptThread == null) {
141             mAcceptThread = new SocketAcceptThread();
142             mAcceptThread.setName("SapAcceptThread");
143             mAcceptThread.start();
144         }
145     }
146 
147     private static final int CREATE_RETRY_TIME = 10;
148 
initSocket()149     private boolean initSocket() {
150         if (VERBOSE) {
151             Log.v(TAG, "Sap Service initSocket");
152         }
153 
154         boolean initSocketOK = false;
155 
156         // It's possible that create will fail in some cases. retry for 10 times
157         for (int i = 0; i < CREATE_RETRY_TIME && !mInterrupted; i++) {
158             initSocketOK = true;
159             try {
160                 // It is mandatory for MSE to support initiation of bonding and encryption.
161                 // TODO: Consider reusing the mServerSocket - it is indented to be reused
162                 //       for multiple connections.
163                 mServerSocket = BluetoothAdapter.getDefaultAdapter().listenUsingRfcommOn(
164                         BluetoothAdapter.SOCKET_CHANNEL_AUTO_STATIC_NO_SDP, true, true);
165                 removeSdpRecord();
166                 mSdpHandle = SdpManager.getDefaultManager()
167                         .createSapsRecord(SDP_SAP_SERVICE_NAME, mServerSocket.getChannel(),
168                                 SDP_SAP_VERSION);
169             } catch (IOException e) {
170                 Log.e(TAG, "Error create RfcommServerSocket ", e);
171                 initSocketOK = false;
172             }
173 
174             if (!initSocketOK) {
175                 // Need to break out of this loop if BT is being turned off.
176                 if (mAdapterService == null) {
177                     break;
178                 }
179                 int state = mAdapterService.getState();
180                 if ((state != BluetoothAdapter.STATE_TURNING_ON) && (state
181                         != BluetoothAdapter.STATE_ON)) {
182                     Log.w(TAG, "initServerSocket failed as BT is (being) turned off");
183                     break;
184                 }
185                 try {
186                     if (VERBOSE) {
187                         Log.v(TAG, "wait 300 ms");
188                     }
189                     Thread.sleep(300);
190                 } catch (InterruptedException e) {
191                     Log.e(TAG, "socketAcceptThread thread was interrupted (3)", e);
192                 }
193             } else {
194                 break;
195             }
196         }
197 
198         if (initSocketOK) {
199             if (VERBOSE) {
200                 Log.v(TAG, "Succeed to create listening socket ");
201             }
202 
203         } else {
204             Log.e(TAG, "Error to create listening socket after " + CREATE_RETRY_TIME + " try");
205         }
206         return initSocketOK;
207     }
208 
closeServerSocket()209     private synchronized void closeServerSocket() {
210         // exit SocketAcceptThread early
211         if (mServerSocket != null) {
212             try {
213                 // this will cause mServerSocket.accept() return early with IOException
214                 mServerSocket.close();
215                 mServerSocket = null;
216             } catch (IOException ex) {
217                 Log.e(TAG, "Close Server Socket error: ", ex);
218             }
219         }
220     }
221 
closeConnectionSocket()222     private synchronized void closeConnectionSocket() {
223         if (mConnSocket != null) {
224             try {
225                 mConnSocket.close();
226                 mConnSocket = null;
227             } catch (IOException e) {
228                 Log.e(TAG, "Close Connection Socket error: ", e);
229             }
230         }
231     }
232 
closeService()233     private void closeService() {
234         if (VERBOSE) {
235             Log.v(TAG, "SAP Service closeService in");
236         }
237 
238         // exit initSocket early
239         mInterrupted = true;
240         closeServerSocket();
241 
242         if (mAcceptThread != null) {
243             try {
244                 mAcceptThread.shutdown();
245                 mAcceptThread.join();
246                 mAcceptThread = null;
247             } catch (InterruptedException ex) {
248                 Log.w(TAG, "mAcceptThread close error", ex);
249             }
250         }
251 
252         if (mWakeLock != null) {
253             mSessionStatusHandler.removeMessages(MSG_ACQUIRE_WAKE_LOCK);
254             mSessionStatusHandler.removeMessages(MSG_RELEASE_WAKE_LOCK);
255             mWakeLock.release();
256             mWakeLock = null;
257         }
258 
259         closeConnectionSocket();
260 
261         if (VERBOSE) {
262             Log.v(TAG, "SAP Service closeService out");
263         }
264     }
265 
startSapServerSession()266     private void startSapServerSession() throws IOException {
267         if (VERBOSE) {
268             Log.v(TAG, "Sap Service startSapServerSession");
269         }
270 
271         // acquire the wakeLock before start SAP transaction thread
272         if (mWakeLock == null) {
273             PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
274             mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "StartingSapTransaction");
275             mWakeLock.setReferenceCounted(false);
276             mWakeLock.acquire();
277         }
278 
279         /* Start the SAP I/O thread and associate with message handler */
280         mSapServer = new SapServer(mSessionStatusHandler, this, mConnSocket.getInputStream(),
281                 mConnSocket.getOutputStream());
282         mSapServer.start();
283         /* Warning: at this point we most likely have already handled the initial connect
284          *          request from the SAP client, hence we need to be prepared to handle the
285          *          response. (the SapHandler should have been started before this point)*/
286 
287         mSessionStatusHandler.removeMessages(MSG_RELEASE_WAKE_LOCK);
288         mSessionStatusHandler.sendMessageDelayed(
289                 mSessionStatusHandler.obtainMessage(MSG_RELEASE_WAKE_LOCK),
290                 RELEASE_WAKE_LOCK_DELAY);
291 
292         if (VERBOSE) {
293             Log.v(TAG, "startSapServerSession() success!");
294         }
295     }
296 
stopSapServerSession()297     private void stopSapServerSession() {
298 
299         /* When we reach this point, the SapServer is closed down, and the client is
300          * supposed to close the RFCOMM connection. */
301         if (VERBOSE) {
302             Log.v(TAG, "SAP Service stopSapServerSession");
303         }
304 
305         mAcceptThread = null;
306         closeConnectionSocket();
307         closeServerSocket();
308 
309         setState(BluetoothSap.STATE_DISCONNECTED);
310 
311         if (mWakeLock != null) {
312             mWakeLock.release();
313             mWakeLock = null;
314         }
315 
316         // Last SAP transaction is finished, we start to listen for incoming
317         // rfcomm connection again
318         if (mAdapterService.isEnabled()) {
319             startRfcommSocketListener();
320         }
321     }
322 
323     /**
324      * A thread that runs in the background waiting for remote rfcomm
325      * connect.Once a remote socket connected, this thread shall be
326      * shutdown.When the remote disconnect,this thread shall run again waiting
327      * for next request.
328      */
329     private class SocketAcceptThread extends Thread {
330 
331         private boolean mStopped = false;
332 
333         @Override
run()334         public void run() {
335             BluetoothServerSocket serverSocket;
336             if (mServerSocket == null) {
337                 if (!initSocket()) {
338                     return;
339                 }
340             }
341 
342             while (!mStopped) {
343                 try {
344                     if (VERBOSE) {
345                         Log.v(TAG, "Accepting socket connection...");
346                     }
347                     serverSocket = mServerSocket;
348                     if (serverSocket == null) {
349                         Log.w(TAG, "mServerSocket is null");
350                         break;
351                     }
352                     mConnSocket = mServerSocket.accept();
353                     if (VERBOSE) {
354                         Log.v(TAG, "Accepted socket connection...");
355                     }
356                     synchronized (SapService.this) {
357                         if (mConnSocket == null) {
358                             Log.w(TAG, "mConnSocket is null");
359                             break;
360                         }
361                         mRemoteDevice = mConnSocket.getRemoteDevice();
362                     }
363                     if (mRemoteDevice == null) {
364                         Log.i(TAG, "getRemoteDevice() = null");
365                         break;
366                     }
367 
368                     sRemoteDeviceName = Utils.getName(mRemoteDevice);
369                     // In case getRemoteName failed and return null
370                     if (TextUtils.isEmpty(sRemoteDeviceName)) {
371                         sRemoteDeviceName = getString(R.string.defaultname);
372                     }
373                     int permission = mRemoteDevice.getSimAccessPermission();
374 
375                     if (VERBOSE) {
376                         Log.v(TAG, "getSimAccessPermission() = " + permission);
377                     }
378 
379                     if (permission == BluetoothDevice.ACCESS_ALLOWED) {
380                         try {
381                             if (VERBOSE) {
382                                 Log.v(TAG, "incoming connection accepted from: " + sRemoteDeviceName
383                                         + " automatically as trusted device");
384                             }
385                             startSapServerSession();
386                         } catch (IOException ex) {
387                             Log.e(TAG, "catch exception starting obex server session", ex);
388                         }
389                     } else if (permission != BluetoothDevice.ACCESS_REJECTED) {
390                         Intent intent =
391                                 new Intent(BluetoothDevice.ACTION_CONNECTION_ACCESS_REQUEST);
392                         intent.setPackage(getString(R.string.pairing_ui_package));
393                         intent.putExtra(BluetoothDevice.EXTRA_ACCESS_REQUEST_TYPE,
394                                 BluetoothDevice.REQUEST_TYPE_SIM_ACCESS);
395                         intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mRemoteDevice);
396                         intent.putExtra(BluetoothDevice.EXTRA_PACKAGE_NAME, getPackageName());
397 
398                         mIsWaitingAuthorization = true;
399                         setUserTimeoutAlarm();
400                         sendBroadcast(intent, BLUETOOTH_CONNECT,
401                                 Utils.getTempAllowlistBroadcastOptions());
402 
403                         if (VERBOSE) {
404                             Log.v(TAG, "waiting for authorization for connection from: "
405                                     + sRemoteDeviceName);
406                         }
407 
408                     } else {
409                         // Close RFCOMM socket for current connection and start listening
410                         // again for new connections.
411                         Log.w(TAG, "Can't connect with " + sRemoteDeviceName
412                                 + " as access is rejected");
413                         if (mSessionStatusHandler != null) {
414                             mSessionStatusHandler.sendEmptyMessage(MSG_SERVERSESSION_CLOSE);
415                         }
416                     }
417                     mStopped = true; // job done ,close this thread;
418                 } catch (IOException ex) {
419                     mStopped = true;
420                     if (VERBOSE) {
421                         Log.v(TAG, "Accept exception: ", ex);
422                     }
423                 }
424             }
425         }
426 
shutdown()427         void shutdown() {
428             mStopped = true;
429             interrupt();
430         }
431     }
432 
433     private final Handler mSessionStatusHandler = new Handler() {
434         @Override
435         public void handleMessage(Message msg) {
436             if (VERBOSE) {
437                 Log.v(TAG, "Handler(): got msg=" + msg.what);
438             }
439 
440             switch (msg.what) {
441                 case START_LISTENER:
442                     if (mAdapterService.isEnabled()) {
443                         startRfcommSocketListener();
444                     }
445                     break;
446                 case USER_TIMEOUT:
447                     if (mIsWaitingAuthorization) {
448                         sendCancelUserConfirmationIntent(mRemoteDevice);
449                         cancelUserTimeoutAlarm();
450                         mIsWaitingAuthorization = false;
451                         stopSapServerSession(); // And restart RfcommListener if needed
452                     }
453                     break;
454                 case MSG_SERVERSESSION_CLOSE:
455                     stopSapServerSession();
456                     break;
457                 case MSG_SESSION_ESTABLISHED:
458                     break;
459                 case MSG_SESSION_DISCONNECTED:
460                     // handled elsewhere
461                     break;
462                 case MSG_ACQUIRE_WAKE_LOCK:
463                     if (VERBOSE) {
464                         Log.i(TAG, "Acquire Wake Lock request message");
465                     }
466                     if (mWakeLock == null) {
467                         PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
468                         mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
469                                 "StartingObexMapTransaction");
470                         mWakeLock.setReferenceCounted(false);
471                     }
472                     if (!mWakeLock.isHeld()) {
473                         mWakeLock.acquire();
474                         if (DEBUG) {
475                             Log.i(TAG, "  Acquired Wake Lock by message");
476                         }
477                     }
478                     mSessionStatusHandler.removeMessages(MSG_RELEASE_WAKE_LOCK);
479                     mSessionStatusHandler.sendMessageDelayed(
480                             mSessionStatusHandler.obtainMessage(MSG_RELEASE_WAKE_LOCK),
481                             RELEASE_WAKE_LOCK_DELAY);
482                     break;
483                 case MSG_RELEASE_WAKE_LOCK:
484                     if (VERBOSE) {
485                         Log.i(TAG, "Release Wake Lock request message");
486                     }
487                     if (mWakeLock != null) {
488                         mWakeLock.release();
489                         if (DEBUG) {
490                             Log.i(TAG, "  Released Wake Lock by message");
491                         }
492                     }
493                     break;
494                 case MSG_CHANGE_STATE:
495                     if (DEBUG) {
496                         Log.d(TAG, "change state message: newState = " + msg.arg1);
497                     }
498                     setState(msg.arg1);
499                     break;
500                 case SHUTDOWN:
501                     /* Ensure to call close from this handler to avoid starting new stuff
502                        because of pending messages */
503                     closeService();
504                     break;
505                 default:
506                     break;
507             }
508         }
509     };
510 
setState(int state)511     private void setState(int state) {
512         setState(state, BluetoothSap.RESULT_SUCCESS);
513     }
514 
setState(int state, int result)515     private synchronized void setState(int state, int result) {
516         if (state != mState) {
517             if (DEBUG) {
518                 Log.d(TAG, "Sap state " + mState + " -> " + state + ", result = " + result);
519             }
520             if (state == BluetoothProfile.STATE_CONNECTED) {
521                 MetricsLogger.logProfileConnectionEvent(BluetoothMetricsProto.ProfileId.SAP);
522             }
523             int prevState = mState;
524             mState = state;
525             Intent intent = new Intent(BluetoothSap.ACTION_CONNECTION_STATE_CHANGED);
526             intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, prevState);
527             intent.putExtra(BluetoothProfile.EXTRA_STATE, mState);
528             intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mRemoteDevice);
529             sendBroadcast(intent, BLUETOOTH_CONNECT, Utils.getTempAllowlistBroadcastOptions());
530         }
531     }
532 
getState()533     public int getState() {
534         return mState;
535     }
536 
getRemoteDevice()537     public BluetoothDevice getRemoteDevice() {
538         return mRemoteDevice;
539     }
540 
getRemoteDeviceName()541     public static String getRemoteDeviceName() {
542         return sRemoteDeviceName;
543     }
544 
disconnect(BluetoothDevice device)545     public boolean disconnect(BluetoothDevice device) {
546         boolean result = false;
547         synchronized (SapService.this) {
548             if (mRemoteDevice != null && mRemoteDevice.equals(device)) {
549                 switch (mState) {
550                     case BluetoothSap.STATE_CONNECTED:
551                         closeConnectionSocket();
552                         setState(BluetoothSap.STATE_DISCONNECTED, BluetoothSap.RESULT_CANCELED);
553                         result = true;
554                         break;
555                     default:
556                         break;
557                 }
558             }
559         }
560         return result;
561     }
562 
getConnectedDevices()563     public List<BluetoothDevice> getConnectedDevices() {
564         List<BluetoothDevice> devices = new ArrayList<BluetoothDevice>();
565         synchronized (this) {
566             if (mState == BluetoothSap.STATE_CONNECTED && mRemoteDevice != null) {
567                 devices.add(mRemoteDevice);
568             }
569         }
570         return devices;
571     }
572 
getDevicesMatchingConnectionStates(int[] states)573     public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
574         List<BluetoothDevice> deviceList = new ArrayList<BluetoothDevice>();
575         BluetoothDevice[] bondedDevices = mAdapterService.getBondedDevices();
576         int connectionState;
577         synchronized (this) {
578             for (BluetoothDevice device : bondedDevices) {
579                 ParcelUuid[] featureUuids = device.getUuids();
580                 if (!BluetoothUuid.containsAnyUuid(featureUuids, SAP_UUIDS)) {
581                     continue;
582                 }
583                 connectionState = getConnectionState(device);
584                 for (int i = 0; i < states.length; i++) {
585                     if (connectionState == states[i]) {
586                         deviceList.add(device);
587                     }
588                 }
589             }
590         }
591         return deviceList;
592     }
593 
getConnectionState(BluetoothDevice device)594     public int getConnectionState(BluetoothDevice device) {
595         synchronized (this) {
596             if (getState() == BluetoothSap.STATE_CONNECTED && getRemoteDevice().equals(device)) {
597                 return BluetoothProfile.STATE_CONNECTED;
598             } else {
599                 return BluetoothProfile.STATE_DISCONNECTED;
600             }
601         }
602     }
603 
604     /**
605      * Set connection policy of the profile and disconnects it if connectionPolicy is
606      * {@link BluetoothProfile#CONNECTION_POLICY_FORBIDDEN}
607      *
608      * <p> The device should already be paired.
609      * Connection policy can be one of:
610      * {@link BluetoothProfile#CONNECTION_POLICY_ALLOWED},
611      * {@link BluetoothProfile#CONNECTION_POLICY_FORBIDDEN},
612      * {@link BluetoothProfile#CONNECTION_POLICY_UNKNOWN}
613      *
614      * @param device Paired bluetooth device
615      * @param connectionPolicy is the connection policy to set to for this profile
616      * @return true if connectionPolicy is set, false on error
617      */
618     @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
setConnectionPolicy(BluetoothDevice device, int connectionPolicy)619     public boolean setConnectionPolicy(BluetoothDevice device, int connectionPolicy) {
620         if (DEBUG) {
621             Log.d(TAG, "Saved connectionPolicy " + device + " = " + connectionPolicy);
622         }
623         enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED,
624                 "Need BLUETOOTH_PRIVILEGED permission");
625         AdapterService.getAdapterService().getDatabase()
626                 .setProfileConnectionPolicy(device, BluetoothProfile.SAP, connectionPolicy);
627         if (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN) {
628             disconnect(device);
629         }
630         return true;
631     }
632 
633     /**
634      * Get the connection policy of the profile.
635      *
636      * <p> The connection policy can be any of:
637      * {@link BluetoothProfile#CONNECTION_POLICY_ALLOWED},
638      * {@link BluetoothProfile#CONNECTION_POLICY_FORBIDDEN},
639      * {@link BluetoothProfile#CONNECTION_POLICY_UNKNOWN}
640      *
641      * @param device Bluetooth device
642      * @return connection policy of the device
643      * @hide
644      */
645     @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
getConnectionPolicy(BluetoothDevice device)646     public int getConnectionPolicy(BluetoothDevice device) {
647         enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED,
648                 "Need BLUETOOTH_PRIVILEGED permission");
649         return AdapterService.getAdapterService().getDatabase()
650                 .getProfileConnectionPolicy(device, BluetoothProfile.SAP);
651     }
652 
653     @Override
initBinder()654     protected IProfileServiceBinder initBinder() {
655         return new SapBinder(this);
656     }
657 
658     @Override
start()659     protected boolean start() {
660         Log.v(TAG, "start()");
661         IntentFilter filter = new IntentFilter();
662         filter.addAction(BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY);
663         filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
664         filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
665         filter.addAction(USER_CONFIRM_TIMEOUT_ACTION);
666 
667         try {
668             registerReceiver(mSapReceiver, filter);
669             mIsRegistered = true;
670         } catch (Exception e) {
671             Log.w(TAG, "Unable to register sap receiver", e);
672         }
673         mInterrupted = false;
674         mAdapterService = AdapterService.getAdapterService();
675         // start RFCOMM listener
676         mSessionStatusHandler.sendMessage(mSessionStatusHandler.obtainMessage(START_LISTENER));
677         setSapService(this);
678         return true;
679     }
680 
681     @Override
stop()682     protected boolean stop() {
683         Log.v(TAG, "stop()");
684         if (!mIsRegistered) {
685             Log.i(TAG, "Avoid unregister when receiver it is not registered");
686             return true;
687         }
688         setSapService(null);
689         try {
690             mIsRegistered = false;
691             unregisterReceiver(mSapReceiver);
692         } catch (Exception e) {
693             Log.w(TAG, "Unable to unregister sap receiver", e);
694         }
695         setState(BluetoothSap.STATE_DISCONNECTED, BluetoothSap.RESULT_CANCELED);
696         sendShutdownMessage();
697         return true;
698     }
699 
700     @Override
cleanup()701     public void cleanup() {
702         setState(BluetoothSap.STATE_DISCONNECTED, BluetoothSap.RESULT_CANCELED);
703         closeService();
704         if (mSessionStatusHandler != null) {
705             mSessionStatusHandler.removeCallbacksAndMessages(null);
706         }
707     }
708 
709     /**
710      * Get the current instance of {@link SapService}
711      *
712      * @return current instance of {@link SapService}
713      */
714     @VisibleForTesting
getSapService()715     public static synchronized SapService getSapService() {
716         if (sSapService == null) {
717             Log.w(TAG, "getSapService(): service is null");
718             return null;
719         }
720         if (!sSapService.isAvailable()) {
721             Log.w(TAG, "getSapService(): service is not available");
722             return null;
723         }
724         return sSapService;
725     }
726 
setSapService(SapService instance)727     private static synchronized void setSapService(SapService instance) {
728         if (DEBUG) {
729             Log.d(TAG, "setSapService(): set to: " + instance);
730         }
731         sSapService = instance;
732     }
733 
setUserTimeoutAlarm()734     private void setUserTimeoutAlarm() {
735         if (DEBUG) {
736             Log.d(TAG, "setUserTimeOutAlarm()");
737         }
738         cancelUserTimeoutAlarm();
739         mRemoveTimeoutMsg = true;
740         Intent timeoutIntent = new Intent(USER_CONFIRM_TIMEOUT_ACTION);
741         PendingIntent pIntent = PendingIntent.getBroadcast(this, 0, timeoutIntent,
742                 PendingIntent.FLAG_IMMUTABLE);
743         mAlarmManager.set(AlarmManager.RTC_WAKEUP,
744                 System.currentTimeMillis() + USER_CONFIRM_TIMEOUT_VALUE, pIntent);
745     }
746 
cancelUserTimeoutAlarm()747     private void cancelUserTimeoutAlarm() {
748         if (DEBUG) {
749             Log.d(TAG, "cancelUserTimeOutAlarm()");
750         }
751         if (mAlarmManager == null) {
752             mAlarmManager = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
753         }
754         if (mRemoveTimeoutMsg) {
755             Intent timeoutIntent = new Intent(USER_CONFIRM_TIMEOUT_ACTION);
756             PendingIntent sender = PendingIntent.getBroadcast(this, 0, timeoutIntent,
757                     PendingIntent.FLAG_IMMUTABLE);
758             mAlarmManager.cancel(sender);
759             mRemoveTimeoutMsg = false;
760         }
761     }
762 
sendCancelUserConfirmationIntent(BluetoothDevice device)763     private void sendCancelUserConfirmationIntent(BluetoothDevice device) {
764         Intent intent = new Intent(BluetoothDevice.ACTION_CONNECTION_ACCESS_CANCEL);
765         intent.setPackage(getString(R.string.pairing_ui_package));
766         intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
767         intent.putExtra(BluetoothDevice.EXTRA_ACCESS_REQUEST_TYPE,
768                 BluetoothDevice.REQUEST_TYPE_SIM_ACCESS);
769         sendBroadcast(intent, BLUETOOTH_CONNECT);
770     }
771 
sendShutdownMessage()772     private void sendShutdownMessage() {
773         /* Any pending messages are no longer valid.
774         To speed up things, simply delete them. */
775         if (mRemoveTimeoutMsg) {
776             Intent timeoutIntent = new Intent(USER_CONFIRM_TIMEOUT_ACTION);
777             sendBroadcast(timeoutIntent);
778             mIsWaitingAuthorization = false;
779             cancelUserTimeoutAlarm();
780         }
781         removeSdpRecord();
782         mSessionStatusHandler.removeCallbacksAndMessages(null);
783         // Request release of all resources
784         mSessionStatusHandler.obtainMessage(SHUTDOWN).sendToTarget();
785     }
786 
sendConnectTimeoutMessage()787     private void sendConnectTimeoutMessage() {
788         if (DEBUG) {
789             Log.d(TAG, "sendConnectTimeoutMessage()");
790         }
791         if (mSessionStatusHandler != null) {
792             Message msg = mSessionStatusHandler.obtainMessage(USER_TIMEOUT);
793             msg.sendToTarget();
794         } // Can only be null during shutdown
795     }
796 
797     private SapBroadcastReceiver mSapReceiver = new SapBroadcastReceiver();
798 
799     private class SapBroadcastReceiver extends BroadcastReceiver {
800         @Override
onReceive(Context context, Intent intent)801         public void onReceive(Context context, Intent intent) {
802 
803             if (VERBOSE) {
804                 Log.v(TAG, "onReceive");
805             }
806             String action = intent.getAction();
807             if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
808                 int state =
809                         intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
810                 if (state == BluetoothAdapter.STATE_TURNING_OFF) {
811                     if (DEBUG) {
812                         Log.d(TAG, "STATE_TURNING_OFF");
813                     }
814                     sendShutdownMessage();
815                 } else if (state == BluetoothAdapter.STATE_ON) {
816                     if (DEBUG) {
817                         Log.d(TAG, "STATE_ON");
818                     }
819                     // start RFCOMM listener
820                     mSessionStatusHandler.sendMessage(
821                             mSessionStatusHandler.obtainMessage(START_LISTENER));
822                 }
823                 return;
824             }
825 
826             if (action.equals(BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY)) {
827                 Log.v(TAG, " - Received BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY");
828 
829                 int requestType = intent.getIntExtra(BluetoothDevice.EXTRA_ACCESS_REQUEST_TYPE, -1);
830                 if (requestType != BluetoothDevice.REQUEST_TYPE_SIM_ACCESS) {
831                     return;
832                 }
833 
834                 mIsWaitingAuthorization = false;
835 
836                 if (intent.getIntExtra(BluetoothDevice.EXTRA_CONNECTION_ACCESS_RESULT,
837                         BluetoothDevice.CONNECTION_ACCESS_NO)
838                         == BluetoothDevice.CONNECTION_ACCESS_YES) {
839                     // bluetooth connection accepted by user
840                     if (intent.getBooleanExtra(BluetoothDevice.EXTRA_ALWAYS_ALLOWED, false)) {
841                         boolean result = mRemoteDevice.setSimAccessPermission(
842                                 BluetoothDevice.ACCESS_ALLOWED);
843                         if (VERBOSE) {
844                             Log.v(TAG, "setSimAccessPermission(ACCESS_ALLOWED) result=" + result);
845                         }
846                     }
847                     boolean result = setConnectionPolicy(mRemoteDevice,
848                             BluetoothProfile.CONNECTION_POLICY_ALLOWED);
849                     Log.d(TAG, "setConnectionPolicy ALLOWED, result = " + result);
850 
851                     try {
852                         if (mConnSocket != null) {
853                             // start obex server and rfcomm connection
854                             startSapServerSession();
855                         } else {
856                             stopSapServerSession();
857                         }
858                     } catch (IOException ex) {
859                         Log.e(TAG, "Caught the error: ", ex);
860                     }
861                 } else {
862                     if (intent.getBooleanExtra(BluetoothDevice.EXTRA_ALWAYS_ALLOWED, false)) {
863                         boolean result = mRemoteDevice.setSimAccessPermission(
864                                 BluetoothDevice.ACCESS_REJECTED);
865                         if (VERBOSE) {
866                             Log.v(TAG, "setSimAccessPermission(ACCESS_REJECTED) result=" + result);
867                         }
868                     }
869                     boolean result = setConnectionPolicy(mRemoteDevice,
870                             BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
871                     Log.d(TAG, "setConnectionPolicy FORBIDDEN, result = " + result);
872                     // Ensure proper cleanup, and prepare for new connect.
873                     mSessionStatusHandler.sendEmptyMessage(MSG_SERVERSESSION_CLOSE);
874                 }
875                 return;
876             }
877 
878             if (action.equals(USER_CONFIRM_TIMEOUT_ACTION)) {
879                 if (DEBUG) {
880                     Log.d(TAG, "USER_CONFIRM_TIMEOUT_ACTION Received.");
881                 }
882                 // send us self a message about the timeout.
883                 sendConnectTimeoutMessage();
884                 return;
885             }
886 
887             if (action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED) && mIsWaitingAuthorization) {
888                 BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
889 
890                 if (mRemoteDevice == null || device == null) {
891                     Log.i(TAG, "Unexpected error!");
892                     return;
893                 }
894 
895                 if (DEBUG) {
896                     Log.d(TAG, "ACL disconnected for " + device);
897                 }
898 
899                 if (mRemoteDevice.equals(device)) {
900                     if (mRemoveTimeoutMsg) {
901                         // Send any pending timeout now, as ACL got disconnected.
902                         mSessionStatusHandler.removeMessages(USER_TIMEOUT);
903                         mSessionStatusHandler.obtainMessage(USER_TIMEOUT).sendToTarget();
904                     }
905                     setState(BluetoothSap.STATE_DISCONNECTED);
906                     // Ensure proper cleanup, and prepare for new connect.
907                     mSessionStatusHandler.sendEmptyMessage(MSG_SERVERSESSION_CLOSE);
908                 }
909             }
910         }
911     }
912 
913     ;
914 
915     //Binder object: Must be static class or memory leak may occur
916 
917     /**
918      * This class implements the IBluetoothSap interface - or actually it validates the
919      * preconditions for calling the actual functionality in the SapService, and calls it.
920      */
921     private static class SapBinder extends IBluetoothSap.Stub implements IProfileServiceBinder {
922         private SapService mService;
923 
924         @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
getService(AttributionSource source)925         private SapService getService(AttributionSource source) {
926             if (!Utils.checkCallerIsSystemOrActiveUser(TAG)
927                     || !Utils.checkServiceAvailable(mService, TAG)
928                     || !Utils.checkConnectPermissionForDataDelivery(mService, source, TAG)) {
929                 return null;
930             }
931             return mService;
932         }
933 
SapBinder(SapService service)934         SapBinder(SapService service) {
935             Log.v(TAG, "SapBinder()");
936             mService = service;
937         }
938 
939         @Override
cleanup()940         public void cleanup() {
941             mService = null;
942         }
943 
944         @Override
getState(AttributionSource source)945         public int getState(AttributionSource source) {
946             Log.v(TAG, "getState()");
947             SapService service = getService(source);
948             if (service == null) {
949                 return BluetoothSap.STATE_DISCONNECTED;
950             }
951             return service.getState();
952         }
953 
954         @Override
getClient(AttributionSource source)955         public BluetoothDevice getClient(AttributionSource source) {
956             Log.v(TAG, "getClient()");
957             SapService service = getService(source);
958             if (service == null) {
959                 return null;
960             }
961             Log.v(TAG, "getClient() - returning " + service.getRemoteDevice());
962             return service.getRemoteDevice();
963         }
964 
965         @Override
isConnected(BluetoothDevice device, AttributionSource source)966         public boolean isConnected(BluetoothDevice device, AttributionSource source) {
967             Log.v(TAG, "isConnected()");
968             Attributable.setAttributionSource(device, source);
969             SapService service = getService(source);
970             if (service == null) {
971                 return false;
972             }
973             return (service.getState() == BluetoothSap.STATE_CONNECTED && service.getRemoteDevice()
974                     .equals(device));
975         }
976 
977         @Override
connect(BluetoothDevice device, AttributionSource source)978         public boolean connect(BluetoothDevice device, AttributionSource source) {
979             Log.v(TAG, "connect()");
980             Attributable.setAttributionSource(device, source);
981             SapService service = getService(source);
982             if (service == null) {
983                 return false;
984             }
985             return false;
986         }
987 
988         @Override
disconnect(BluetoothDevice device, AttributionSource source)989         public boolean disconnect(BluetoothDevice device, AttributionSource source) {
990             Log.v(TAG, "disconnect()");
991             Attributable.setAttributionSource(device, source);
992             SapService service = getService(source);
993             if (service == null) {
994                 return false;
995             }
996             return service.disconnect(device);
997         }
998 
999         @Override
getConnectedDevices(AttributionSource source)1000         public List<BluetoothDevice> getConnectedDevices(AttributionSource source) {
1001             Log.v(TAG, "getConnectedDevices()");
1002             SapService service = getService(source);
1003             if (service == null) {
1004                 return new ArrayList<BluetoothDevice>(0);
1005             }
1006             return service.getConnectedDevices();
1007         }
1008 
1009         @Override
getDevicesMatchingConnectionStates(int[] states, AttributionSource source)1010         public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states,
1011                 AttributionSource source) {
1012             Log.v(TAG, "getDevicesMatchingConnectionStates()");
1013             SapService service = getService(source);
1014             if (service == null) {
1015                 return new ArrayList<BluetoothDevice>(0);
1016             }
1017             return service.getDevicesMatchingConnectionStates(states);
1018         }
1019 
1020         @Override
getConnectionState(BluetoothDevice device, AttributionSource source)1021         public int getConnectionState(BluetoothDevice device, AttributionSource source) {
1022             Log.v(TAG, "getConnectionState()");
1023             Attributable.setAttributionSource(device, source);
1024             SapService service = getService(source);
1025             if (service == null) {
1026                 return BluetoothProfile.STATE_DISCONNECTED;
1027             }
1028             return service.getConnectionState(device);
1029         }
1030 
1031         @Override
setConnectionPolicy(BluetoothDevice device, int connectionPolicy, AttributionSource source)1032         public boolean setConnectionPolicy(BluetoothDevice device, int connectionPolicy,
1033                 AttributionSource source) {
1034             Attributable.setAttributionSource(device, source);
1035             SapService service = getService(source);
1036             if (service == null) {
1037                 return false;
1038             }
1039             return service.setConnectionPolicy(device, connectionPolicy);
1040         }
1041 
1042         @Override
getConnectionPolicy(BluetoothDevice device, AttributionSource source)1043         public int getConnectionPolicy(BluetoothDevice device, AttributionSource source) {
1044             Attributable.setAttributionSource(device, source);
1045             SapService service = getService(source);
1046             if (service == null) {
1047                 return BluetoothProfile.CONNECTION_POLICY_UNKNOWN;
1048             }
1049             return service.getConnectionPolicy(device);
1050         }
1051     }
1052 }
1053