Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e6564029 authored by Ashwini Munigala's avatar Ashwini Munigala Committed by Andre Eisenbach
Browse files

MAP: Add MNS SDP Search during setNotificationRegistration.

Precondition:
Verified with remote MCE device that starts MNS server
only before issuing setNotification Registration to MSE.

Use Case:
1. Discover and Pair with MSE from MCE.
2. Connect to MSE on Mas insance 0.
3. Enable Notification Registration for MAS Instance 0

Failure:
MNS connection happens over RFCOMM
and MAS Instance is connected over L2CAP.

Root Cause:
Current design performs MNS SDP search only at the time
of successful MAS Instance Connect. MNS connect implementation
tries connection over insecure RFCOMM channel based on UUID
when MNS Server record is not available.

Fix:
Add implementation to check and perform MNS SDP search
if this info is not available when MCE requests
setNotificationRegistration. This fix is required to
handle MCE implementation that start MNS Sever and
expose SDP only before sending setNotificationRegistration.

Change-Id: If1e8d33dcac078f04d13b8bacf8e1d1513c119e1
parent 5bc62299
Loading
Loading
Loading
Loading
+50 −10
Original line number Diff line number Diff line
@@ -327,6 +327,26 @@ public class BluetoothMapContentObserver {
        }
    }

    public int getObserverRemoteFeatureMask() {
        if (V) Log.v(TAG, "getObserverRemoteFeatureMask : " + mMapEventReportVersion
            + " mMapSupportedFeatures: " + mMapSupportedFeatures);
        return mMapSupportedFeatures;
    }

    public void setObserverRemoteFeatureMask(int remoteSupportedFeatures) {
        mMapSupportedFeatures = remoteSupportedFeatures;
        if ((BluetoothMapUtils.MAP_FEATURE_EXTENDED_EVENT_REPORT_11_BIT
                & mMapSupportedFeatures) != 0) {
            mMapEventReportVersion = BluetoothMapUtils.MAP_EVENT_REPORT_V11;
        }
        // Make sure support for all formats result in latest version returned
        if ((BluetoothMapUtils.MAP_FEATURE_EVENT_REPORT_V12_BIT
                & mMapSupportedFeatures) != 0) {
            mMapEventReportVersion = BluetoothMapUtils.MAP_EVENT_REPORT_V12;
        }
        if (V) Log.d(TAG, "setObserverRemoteFeatureMask : " + mMapEventReportVersion
            + " mMapSupportedFeatures : " + mMapSupportedFeatures);
    }

    private Map<Long, Msg> getMsgListSms() {
        return mMsgListSms;
@@ -865,28 +885,48 @@ public class BluetoothMapContentObserver {
    public int setNotificationRegistration(int notificationStatus) throws RemoteException {
        // Forward the request to the MNS thread as a message - including the MAS instance ID.
        if(D) Log.d(TAG,"setNotificationRegistration() enter");
        if (mMnsClient == null) {
            return ResponseCodes.OBEX_HTTP_UNAVAILABLE;
        }
        Handler mns = mMnsClient.getMessageHandler();
        if (mns != null) {
            Message msg = mns.obtainMessage();
            if (mMnsClient.isValidMnsRecord()) {
                msg.what = BluetoothMnsObexClient.MSG_MNS_NOTIFICATION_REGISTRATION;
            } else {
                //Trigger SDP Search and notificaiton registration , if SDP record not found.
                msg.what = BluetoothMnsObexClient.MSG_MNS_SDP_SEARCH_REGISTRATION;
                if (mMnsClient.mMnsLstRegRqst != null &&
                        (mMnsClient.mMnsLstRegRqst.isSearchInProgress())) {
                    /*  1. Disallow next Notification ON Request :
                     *     - Respond "Service Unavailable" as SDP Search and last notification
                     *       registration ON request is already InProgress.
                     *     - Next notification ON Request will be allowed ONLY after search
                     *       and connect for last saved request [Replied with OK ] is processed.
                     */
                    if (notificationStatus == BluetoothMapAppParams.NOTIFICATION_STATUS_YES) {
                        return ResponseCodes.OBEX_HTTP_UNAVAILABLE;
                    } else {
                        /*  2. Allow next Notification OFF Request:
                         *    - Keep the SDP search still in progress.
                         *    - Disconnect and Deregister the contentObserver.
                         */
                        msg.what = BluetoothMnsObexClient.MSG_MNS_NOTIFICATION_REGISTRATION;
                    }
                }
            }
            msg.arg1 = mMasId;
            msg.arg2 = notificationStatus;
            mns.sendMessageDelayed(msg, 10); // Send message without forcing a context switch
            /* Some devices - e.g. PTS needs to get the unregister confirm before we actually
             * disconnect the MNS. */
            if(D) Log.d(TAG,"setNotificationRegistration() MSG_MNS_NOTIFICATION_REGISTRATION " +
                    "send to MNS");
            if(D) Log.d(TAG,"setNotificationRegistration() send : " + msg.what + " to MNS ");
            return ResponseCodes.OBEX_HTTP_OK;
        } else {
            // This should not happen except at shutdown.
            if(D) Log.d(TAG,"setNotificationRegistration() Unable to send registration request");
            return ResponseCodes.OBEX_HTTP_UNAVAILABLE;
        }
        if(notificationStatus == BluetoothMapAppParams.NOTIFICATION_STATUS_YES) {
            registerObserver();
        } else {
            unregisterObserver();
        }
        return ResponseCodes.OBEX_HTTP_OK;
    }

    boolean eventMaskContainsContacts(long mask) {
+7 −2
Original line number Diff line number Diff line
@@ -434,8 +434,13 @@ public class BluetoothMapMasInstance implements IObexConnectionHandler {
        }
    }

    public void setRemoteFeatureMask(int supported_features) {
        mRemoteFeatureMask  = supported_features;
    public void setRemoteFeatureMask(int supportedFeatures) {
       if(V) Log.v(TAG, "setRemoteFeatureMask : Curr: "+ mRemoteFeatureMask);
       mRemoteFeatureMask  = supportedFeatures;
       if (mObserver != null) {
           mObserver.setObserverRemoteFeatureMask(mRemoteFeatureMask);
           if(V) Log.v(TAG, "setRemoteFeatureMask : set: " + mRemoteFeatureMask);
       }
    }

    public int getRemoteFeatureMask(){
+40 −9
Original line number Diff line number Diff line
@@ -90,6 +90,10 @@ public class BluetoothMapService extends ProfileService {

    public static final int MSG_RELEASE_WAKE_LOCK = 5006;

    public static final int MSG_MNS_SDP_SEARCH = 5007;

    public static final int MSG_OBSERVER_REGISTRATION = 5008;

    private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;

    private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
@@ -389,6 +393,30 @@ public class BluetoothMapService extends ProfileService {
                        if (DEBUG) Log.d(TAG, "  Released Wake Lock by message");
                    }
                    break;
                case MSG_MNS_SDP_SEARCH:
                    if (mRemoteDevice != null) {
                        if (DEBUG) Log.d(TAG,"MNS SDP Initiate Search ..");
                        mRemoteDevice.sdpSearch(BluetoothMnsObexClient.BLUETOOTH_UUID_OBEX_MNS);
                    } else {
                        Log.w(TAG, "remoteDevice info not available");
                    }
                    break;
                case MSG_OBSERVER_REGISTRATION:
                    if (DEBUG) Log.d(TAG,"ContentObserver Registration MASID: " + msg.arg1
                        + " Enable: " + msg.arg2);
                    BluetoothMapMasInstance masInst = mMasInstances.get(msg.arg1);
                    if (masInst != null) {
                        try {
                            if (msg.arg2 == BluetoothMapAppParams.NOTIFICATION_STATUS_YES) {
                                masInst.mObserver.registerObserver();
                            } else {
                                masInst.mObserver.unregisterObserver();
                            }
                        } catch (RemoteException e) {
                            Log.e(TAG,"ContentObserverRegistarion Failed: "+ e);
                        }
                    }
                    break;
                default:
                    break;
            }
@@ -966,31 +994,34 @@ public class BluetoothMapService extends ProfileService {
                    sendConnectCancelMessage();
                }
            } else if (action.equals(BluetoothDevice.ACTION_SDP_RECORD)) {
//                Log.v(TAG, "Received ACTION_SDP_RECORD.");
                if (DEBUG) Log.d(TAG, "Received ACTION_SDP_RECORD.");
                ParcelUuid uuid = intent.getParcelableExtra(BluetoothDevice.EXTRA_UUID);
                if (VERBOSE) {
                    Log.v(TAG, "Received UUID: " + uuid.toString());
                    Log.v(TAG, "expected UUID: " +
                          BluetoothMnsObexClient.BLUETOOTH_UUID_OBEX_MNS.toString());
                }
                if(uuid.equals(BluetoothMnsObexClient.BLUETOOTH_UUID_OBEX_MNS)
                        && mSdpSearchInitiated)
                {
                if (uuid.equals(BluetoothMnsObexClient.BLUETOOTH_UUID_OBEX_MNS)) {
                    mMnsRecord = intent.getParcelableExtra(BluetoothDevice.EXTRA_SDP_RECORD);
                    int status = intent.getIntExtra(BluetoothDevice.EXTRA_SDP_SEARCH_STATUS, -1);
                    if (VERBOSE) {
                        Log.v(TAG, " -> MNS Record:" + mMnsRecord);
                        Log.v(TAG, " -> status: " + status);
                    }
                    mSdpSearchInitiated = false; // done searching
                    if (mBluetoothMnsObexClient != null && !mSdpSearchInitiated) {
                        mBluetoothMnsObexClient.setMnsRecord(mMnsRecord);
                    }
                    if (status != -1 && mMnsRecord != null) {
                        for (int i = 0, c = mMasInstances.size(); i < c; i++) {
                                mMasInstances.valueAt(i).setRemoteFeatureMask(
                                        mMnsRecord.getSupportedFeatures());
                        }
                    }
                    if (mSdpSearchInitiated) {
                        mSdpSearchInitiated = false; // done searching
                        sendConnectMessage(-1); // -1 indicates all MAS instances
                    }
                }
            } else if (action.equals(ACTION_SHOW_MAPS_SETTINGS)) {
                if (VERBOSE) Log.v(TAG, "Received ACTION_SHOW_MAPS_SETTINGS.");

+116 −10
Original line number Diff line number Diff line
@@ -60,12 +60,16 @@ public class BluetoothMnsObexClient {

    private HeaderSet mHsConnect = null;
    private Handler mCallback = null;
    private final SdpMnsRecord mMnsRecord;
    private SdpMnsRecord mMnsRecord;
    // Used by the MAS to forward notification registrations
    public static final int MSG_MNS_NOTIFICATION_REGISTRATION = 1;
    public static final int MSG_MNS_SEND_EVENT = 2;
    public static final int MSG_MNS_SDP_SEARCH_REGISTRATION = 3;


    //Copy SdpManager.SDP_INTENT_DELAY - The timeout to wait for reply from native.
    private final int MNS_SDP_SEARCH_DELAY = 6000;
    public MnsSdpSearchInfo mMnsLstRegRqst = null;
    private static final int MNS_NOTIFICATION_DELAY = 10;
    public static final ParcelUuid BLUETOOTH_UUID_OBEX_MNS =
            ParcelUuid.fromString("00001133-0000-1000-8000-00805F9B34FB");

@@ -90,6 +94,26 @@ public class BluetoothMnsObexClient {
        return mHandler;
    }

    class MnsSdpSearchInfo {
        private boolean isSearchInProgress;
        int lastMasId;
        int lastNotificationStatus;

        MnsSdpSearchInfo (boolean isSearchON, int masId, int notification) {
            isSearchInProgress = isSearchON;
            lastMasId = masId;
            lastNotificationStatus = notification;
        }

        public boolean isSearchInProgress() {
            return isSearchInProgress;
        }

        public void setIsSearchInProgress(boolean isSearchON) {
            isSearchInProgress = isSearchON;
        }
    }

    private final class MnsObexClientHandler extends Handler {
        private MnsObexClientHandler(Looper looper) {
            super(looper);
@@ -99,11 +123,29 @@ public class BluetoothMnsObexClient {
        public void handleMessage(Message msg) {
            switch (msg.what) {
            case MSG_MNS_NOTIFICATION_REGISTRATION:
                if (V) Log.v(TAG, "Reg  masId:  " + msg.arg1 + " notfStatus: " + msg.arg2);
                if (isValidMnsRecord()) {
                    handleRegistration(msg.arg1 /*masId*/, msg.arg2 /*status*/);
                } else {
                    //Should not happen
                    if (D) Log.d(TAG, "MNS SDP info not available yet - Cannot Connect.");
                }
                break;
            case MSG_MNS_SEND_EVENT:
                sendEventHandler((byte[])msg.obj/*byte[]*/, msg.arg1 /*masId*/);
                break;
            case MSG_MNS_SDP_SEARCH_REGISTRATION:
                //Initiate SDP Search
                notifyMnsSdpSearch();
                //Save the mns search info
                mMnsLstRegRqst = new MnsSdpSearchInfo(true, msg.arg1, msg.arg2);
                //Handle notification registration.
                Message msgReg =
                        mHandler.obtainMessage(MSG_MNS_NOTIFICATION_REGISTRATION,
                                msg.arg1, msg.arg2);
                if (V) Log.v(TAG, "SearchReg  masId:  " + msg.arg1 + " notfStatus: " + msg.arg2);
                mHandler.sendMessageDelayed(msgReg, MNS_SDP_SEARCH_DELAY);
                break;
            default:
                break;
            }
@@ -180,9 +222,13 @@ public class BluetoothMnsObexClient {
     */
    public synchronized void handleRegistration(int masId, int notificationStatus){
        if(D) Log.d(TAG, "handleRegistration( " + masId + ", " + notificationStatus + ")");

        boolean sendObserverRegistration = true;
        if (notificationStatus == BluetoothMapAppParams.NOTIFICATION_STATUS_NO) {
            mRegisteredMasIds.delete(masId);
            if (mMnsLstRegRqst != null &&  mMnsLstRegRqst.lastMasId == masId) {
                //Clear last saved MNSSdpSearchInfo , if Disconnect requested for same MasId.
                mMnsLstRegRqst = null;
            }
        } else if (notificationStatus == BluetoothMapAppParams.NOTIFICATION_STATUS_YES) {
            /* Connect if we do not have a connection, and start the content observers providing
             * this thread as Handler.
@@ -191,13 +237,65 @@ public class BluetoothMnsObexClient {
                if(D) Log.d(TAG, "handleRegistration: connect");
                connect();
            }
            sendObserverRegistration = isConnected();
            mRegisteredMasIds.put(masId, true); // We don't use the value for anything

            // Clear last saved MNSSdpSearchInfo after connect is processed.
            mMnsLstRegRqst = null;
        }

        if (mRegisteredMasIds.size() == 0) {
            // No more registrations - disconnect
            if(D) Log.d(TAG, "handleRegistration: disconnect");
            disconnect();
        }

        //Register ContentObserver After connect/disconnect MNS channel.
        if (V) Log.v(TAG, "Send  registerObserver: " + sendObserverRegistration);
        if (mCallback != null && sendObserverRegistration) {
            Message msg = Message.obtain(mCallback);
            msg.what = BluetoothMapService.MSG_OBSERVER_REGISTRATION;
            msg.arg1 = masId;
            msg.arg2 = notificationStatus;
            msg.sendToTarget();
        }
    }

    public boolean isValidMnsRecord() {
        return (mMnsRecord != null);
    }

    public void setMnsRecord(SdpMnsRecord mnsRecord) {
        if (V) Log.v(TAG, "setMNSRecord");
        if (isValidMnsRecord()) {
           Log.w(TAG,"MNS Record already available. Still update.");
        }
        mMnsRecord = mnsRecord;
        if (mMnsLstRegRqst != null) {
            //SDP Search completed.
            mMnsLstRegRqst.setIsSearchInProgress(false);
            if (mHandler.hasMessages(MSG_MNS_NOTIFICATION_REGISTRATION)) {
                mHandler.removeMessages(MSG_MNS_NOTIFICATION_REGISTRATION);
                //Search Result obtained within MNS_SDP_SEARCH_DELAY timeout
                if (!isValidMnsRecord()) {
                    // SDP info still not available for last trial.
                    // Clear saved info.
                    mMnsLstRegRqst = null;
                } else {
                    if (V) Log.v(TAG, "Handle registration for last saved request");
                    Message msgReg =
                            mHandler.obtainMessage(MSG_MNS_NOTIFICATION_REGISTRATION);
                    msgReg.arg1 = mMnsLstRegRqst.lastMasId;
                    msgReg.arg2 = mMnsLstRegRqst.lastNotificationStatus;
                    if (V) Log.v(TAG, "SearchReg  masId:  " + msgReg.arg1
                        + " notfStatus: " + msgReg.arg2);
                    //Handle notification registration.
                    mHandler.sendMessageDelayed(msgReg, MNS_NOTIFICATION_DELAY);
                }
            }
        } else {
           if (V) Log.v(TAG, "No last saved MNSSDPInfo to handle");
        }
    }

    public void connect() {
@@ -207,11 +305,11 @@ public class BluetoothMnsObexClient {
        BluetoothSocket btSocket = null;
        try {
            // TODO: Do SDP record search again?
            if(mMnsRecord != null && mMnsRecord.getL2capPsm() > 0) {
            if (isValidMnsRecord() && mMnsRecord.getL2capPsm() > 0) {
                // Do L2CAP connect
                btSocket = mRemoteDevice.createL2capSocket(mMnsRecord.getL2capPsm());

            } else if (mMnsRecord != null && mMnsRecord.getRfcommChannelNumber() > 0) {
            } else if (isValidMnsRecord() && mMnsRecord.getRfcommChannelNumber() > 0) {
                // Do Rfcomm connect
                btSocket = mRemoteDevice.createRfcommSocket(mMnsRecord.getRfcommChannelNumber());
            } else {
@@ -280,6 +378,14 @@ public class BluetoothMnsObexClient {
        notifyUpdateWakeLock();
    }

    private void notifyMnsSdpSearch() {
        if (mCallback != null) {
            Message msg = Message.obtain(mCallback);
            msg.what = BluetoothMapService.MSG_MNS_SDP_SEARCH;
            msg.sendToTarget();
        }
    }

    private int sendEventHandler(byte[] eventBytes, int masInstanceId) {

        boolean error = false;