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