Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-40172

Android Bluetooth Socket Connection fails in some cases.

    XMLWordPrintable

    Details

    • Type: Bug
    • Status: Closed
    • Priority: P2: Important
    • Resolution: Done
    • Affects Version/s: 5.3.1
    • Fix Version/s: 5.3.2
    • Labels:
      None
    • Environment:
      android
    • Platform/s:
      Android

      Description

      Hello. Sorry for my english.

      I was trying to connect a bluetooth device (not an android) using RFcomm socket. But It was failing with following log output.

      D/Qt      (25579): ../sprcc/src/Bluetooth/BluetoothClientWorker.cpp:37 (void BluetoothClientWorker::connectToHost(const QBluetoothAddress&, const QBluetoothUuid&)): [BluetoothClientWorker] Connecting using  "{00001101-0000-1000-8000-00805f9b34fb}"
      D/Qt      (25579): ../sprcc/src/Bluetooth/BluetoothClientWorker.cpp:130 (void BluetoothClientWorker::stateChanged(QBluetoothSocket::SocketState)): [BluetoothClientWorker] State: "Connecting"
      W/BluetoothAdapter(25579): getBluetoothService() called with no BluetoothManagerCallback
      D/BTIF_SOCK(  946): service_uuid: 00001101-0000-1000-8000-00805f9b34fb
      D/BluetoothSocket(25579): connect(), SocketState: INIT, mPfd: {ParcelFileDescriptor: FileDescriptor[68]}
      W/bt-btif (  946): info:x10
      D/        (  946): remote version info [00:12:ff:c7:00:c9]: 4, a, 12e9
      D/BluetoothManagerService(  451): Message: 20
      D/BluetoothManagerService(  451): Added callback: android.bluetooth.IBluetoothManagerCallback$Stub$Proxy@428d5548:true
      W/bt-sdp  (  946): process_service_search_attr_rsp
      E/bt-btif (  946): DISCOVERY_COMP_EVT slot id:129, failed to find channle,                                       status:1, scn:0
      W/bt-btif (  946): invalid rfc slot id: 129
      W/System.err(25579): java.io.IOException: read failed, socket might closed or timeout, read ret: -1
      W/System.err(25579): 	at android.bluetooth.BluetoothSocket.readAll(BluetoothSocket.java:505)
      W/System.err(25579): 	at android.bluetooth.BluetoothSocket.readInt(BluetoothSocket.java:516)
      W/System.err(25579): 	at android.bluetooth.BluetoothSocket.connect(BluetoothSocket.java:320)
      W/System.err(25579): 	at dalvik.system.NativeStart.run(Native Method)
      D/Qt      (25579): ../sprcc/src/Bluetooth/BluetoothClientWorker.cpp:93 (void BluetoothClientWorker::socketError(QBluetoothSocket::SocketError)): [BluetoothClientWorker] Error: "Service not found error."
      D/Qt      (25579): ../sprcc/src/Bluetooth/BluetoothClientWorker.cpp:130 (void BluetoothClientWorker::stateChanged(QBluetoothSocket::SocketState)): [BluetoothClientWorker] State: "Unconnected"
      D/Finsky  (13387): [1] 5.onFinished: Installation state replication succeeded.
      D/btif_config_util(  946): btif_config_save_file(L153): in file name:/data/misc/bluedroid/bt_config.new
      E/bt-btm  (  946): btm_sec_disconnected - Clearing Pending flag
      
      

      Then I find out this was a chronic problem of Android and I found this patch. In fact this patch is everywhere.

      https://github.com/pires/android-obd-reader/commit/2ae0d214abf4c02e6d3b1ef07a165c82c6ef13a7

      I did applied into qtconnectivity

      qbluetoothsocket_android.cpp
      void QBluetoothSocketPrivate::connectToServiceConc(const QBluetoothAddress &address,
                                                         const QBluetoothUuid &uuid, QIODevice::OpenMode openMode)
      {
          Q_Q(QBluetoothSocket);
          Q_UNUSED(openMode);
      
          if (!adapter.isValid()) {
              qCWarning(QT_BT_ANDROID) << "Device does not support Bluetooth";
              errorString = QBluetoothSocket::tr("Device does not support Bluetooth");
              q->setSocketError(QBluetoothSocket::NetworkError);
              q->setSocketState(QBluetoothSocket::UnconnectedState);
              return;
          }
      
          const int state = adapter.callMethod<jint>("getState");
          if (state != 12 ) { //BluetoothAdapter.STATE_ON
              qCWarning(QT_BT_ANDROID) << "Bt device offline";
              errorString = QBluetoothSocket::tr("Device is powered off");
              q->setSocketError(QBluetoothSocket::NetworkError);
              q->setSocketState(QBluetoothSocket::UnconnectedState);
              return;
          }
      
          QAndroidJniEnvironment env;
          QAndroidJniObject inputString = QAndroidJniObject::fromString(address.toString());
          remoteDevice = adapter.callObjectMethod("getRemoteDevice",
                                                  "(Ljava/lang/String;)Landroid/bluetooth/BluetoothDevice;",
                                                  inputString.object<jstring>());
          if (env->ExceptionCheck()) {
              env->ExceptionDescribe();
              env->ExceptionClear();
      
              errorString = QBluetoothSocket::tr("Cannot access address %1", "%1 = Bt address e.g. 11:22:33:44:55:66").arg(address.toString());
              q->setSocketError(QBluetoothSocket::HostNotFoundError);
              q->setSocketState(QBluetoothSocket::UnconnectedState);
              return;
          }
      
          //cut leading { and trailing } {xxx-xxx}
          QString tempUuid = uuid.toString();
          tempUuid.chop(1); //remove trailing '}'
          tempUuid.remove(0, 1); //remove first '{'
      
          inputString = QAndroidJniObject::fromString(tempUuid);
          QAndroidJniObject uuidObject = QAndroidJniObject::callStaticObjectMethod("java/util/UUID", "fromString",
                                                                             "(Ljava/lang/String;)Ljava/util/UUID;",
                                                                             inputString.object<jstring>());
      
          socketObject = remoteDevice.callObjectMethod("createRfcommSocketToServiceRecord",
                                                       "(Ljava/util/UUID;)Landroid/bluetooth/BluetoothSocket;",
                                                       uuidObject.object<jobject>());
      
          if (env->ExceptionCheck()) {
              env->ExceptionDescribe();
              env->ExceptionClear();
      
              socketObject = remoteDevice = QAndroidJniObject();
              errorString = QBluetoothSocket::tr("Cannot connect to %1 on %2",
                                                 "%1 = uuid, %2 = Bt address").arg(uuid.toString()).arg(address.toString());
              q->setSocketError(QBluetoothSocket::ServiceNotFoundError);
              q->setSocketState(QBluetoothSocket::UnconnectedState);
              return;
          }
      
          socketObject.callMethod<void>("connect");
          if (env->ExceptionCheck() || socketObject.callMethod<jboolean>("isConnected") == JNI_FALSE) {
              if (env->ExceptionCheck()) {
                  env->ExceptionDescribe();
                  env->ExceptionClear();
              }
      
              qCWarning(QT_BT_ANDROID) << "Falling back to workaround.";
              jclass remoteDeviceClazz = env->GetObjectClass(remoteDevice.object());
              if (!remoteDeviceClazz)
              {
                  qCWarning(QT_BT_ANDROID) << "Could not found GetObjectClass of BluetoothDevice.";
      
                  socketObject = remoteDevice = QAndroidJniObject();
                  q->setSocketError(QBluetoothSocket::ServiceNotFoundError);
                  q->setSocketState(QBluetoothSocket::UnconnectedState);
                  return;
              }
      
              jmethodID getClassMethod = env->GetMethodID(remoteDeviceClazz, "getClass", "()Ljava/lang/Class;");
              if (!getClassMethod)
              {
                  qCWarning(QT_BT_ANDROID) << "getClass method could not found.";
      
                  socketObject = remoteDevice = QAndroidJniObject();
                  q->setSocketError(QBluetoothSocket::ServiceNotFoundError);
                  q->setSocketState(QBluetoothSocket::UnconnectedState);
                  return;
              }
      
              QAndroidJniObject remoteDeviceClass = QAndroidJniObject(env->CallObjectMethod(remoteDevice.object(), getClassMethod));
              if (!remoteDeviceClass.isValid())
              {
                  qCWarning(QT_BT_ANDROID) << "Could not invoke getClass from BluetoothDevice.";
      
                  socketObject = remoteDevice = QAndroidJniObject();
                  q->setSocketError(QBluetoothSocket::ServiceNotFoundError);
                  q->setSocketState(QBluetoothSocket::UnconnectedState);
                  return;
              }
      
              jclass classClass = env->FindClass("java/lang/Class");
              jclass integerClass = env->FindClass("java/lang/Integer");
              jfieldID integerType = env->GetStaticFieldID(integerClass, "TYPE", "Ljava/lang/Class;");
              jobject integerObject = env->GetStaticObjectField(integerClass, integerType);
              if (!integerObject)
              {
                  qCWarning(QT_BT_ANDROID) << "Could not get Integer.TYPE";
      
                  socketObject = remoteDevice = QAndroidJniObject();
                  q->setSocketError(QBluetoothSocket::ServiceNotFoundError);
                  q->setSocketState(QBluetoothSocket::UnconnectedState);
                  return;
              }
      
              jobjectArray paramTypes = env->NewObjectArray(1, classClass, integerObject);
              if (!paramTypes)
              {
                  qCWarning(QT_BT_ANDROID) << "Could not create new Class[]{Integer.TYPE}";
                  if (env->ExceptionCheck())
                  {
                      env->ExceptionDescribe();
                      env->ExceptionClear();
                  }
      
                  socketObject = remoteDevice = QAndroidJniObject();
                  q->setSocketError(QBluetoothSocket::ServiceNotFoundError);
                  q->setSocketState(QBluetoothSocket::UnconnectedState);
                  return;
              }
      
              QAndroidJniObject method = remoteDeviceClass.callObjectMethod(
                  "getMethod",
                  "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;",
                  QAndroidJniObject::fromString("createInsecureRfcommSocket").object<jstring>(),
                  paramTypes);
              if (!method.isValid() || env->ExceptionCheck())
              {
                  qCWarning(QT_BT_ANDROID) << "Could not invoke getMethod";
                  if (env->ExceptionCheck())
                  {
                      env->ExceptionDescribe();
                      env->ExceptionClear();
                  }
      
                  socketObject = remoteDevice = QAndroidJniObject();
                  q->setSocketError(QBluetoothSocket::ServiceNotFoundError);
                  q->setSocketState(QBluetoothSocket::UnconnectedState);
                  return;
              }
      
              jclass methodClass = env->GetObjectClass(method.object());
              jmethodID invokeMethodId = env->GetMethodID(methodClass, "invoke", "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;");
              if (!invokeMethodId)
              {
                  qCWarning(QT_BT_ANDROID) << "Could not invoke method.";
      
                  socketObject = remoteDevice = QAndroidJniObject();
                  q->setSocketError(QBluetoothSocket::ServiceNotFoundError);
                  q->setSocketState(QBluetoothSocket::UnconnectedState);
                  return;
              }
      
              jmethodID valueOfMethodId = env->GetStaticMethodID(integerClass, "valueOf", "(I)Ljava/lang/Integer;");
              jclass objectClass = env->FindClass("java/lang/Object");
              jobjectArray invokeParams = env->NewObjectArray(1, objectClass, env->CallStaticObjectMethod(integerClass, valueOfMethodId, 1));
      
              jobject invokeResult = env->CallObjectMethod(method.object(), invokeMethodId, remoteDevice.object(), invokeParams);
              if (!invokeResult)
              {
                  qCWarning(QT_BT_ANDROID) << "Invoke Resulted with error.";
                  if (env->ExceptionCheck())
                  {
                      env->ExceptionDescribe();
                      env->ExceptionClear();
                  }
      
                  socketObject = remoteDevice = QAndroidJniObject();
                  q->setSocketError(QBluetoothSocket::ServiceNotFoundError);
                  q->setSocketState(QBluetoothSocket::UnconnectedState);
                  return;
              }
              else
              {
                  qCWarning(QT_BT_ANDROID) << "Invoke Result successfull.";
              }
      
              socketObject = QAndroidJniObject(invokeResult);
              socketObject.callMethod<void>("connect");
              if (env->ExceptionCheck() || socketObject.callMethod<jboolean>("isConnected") == JNI_FALSE)
              {
                  if (env->ExceptionCheck())
                  {
                      env->ExceptionDescribe();
                      env->ExceptionClear();
                  }
      
                  socketObject = remoteDevice = QAndroidJniObject();
                  errorString = QBluetoothSocket::tr("Connection to service failed");
      
                  qCWarning(QT_BT_ANDROID) << errorString;
      
                  q->setSocketError(QBluetoothSocket::ServiceNotFoundError);
                  q->setSocketState(QBluetoothSocket::UnconnectedState);
                  return;
              }
          }
      
          if (inputThread) {
              inputThread->deleteLater();
              inputThread = 0;
          }
      
          inputStream = socketObject.callObjectMethod("getInputStream", "()Ljava/io/InputStream;");
          outputStream = socketObject.callObjectMethod("getOutputStream", "()Ljava/io/OutputStream;");
      
          if (env->ExceptionCheck() || !inputStream.isValid() || !outputStream.isValid()) {
              env->ExceptionDescribe();
              env->ExceptionClear();
      
              //close socket again
              socketObject.callMethod<void>("close");
              if (env->ExceptionCheck()) {
                  env->ExceptionDescribe();
                  env->ExceptionClear();
              }
      
              socketObject = inputStream = outputStream = remoteDevice = QAndroidJniObject();
      
      
              errorString = QBluetoothSocket::tr("Obtaining streams for service failed");
              q->setSocketError(QBluetoothSocket::NetworkError);
              q->setSocketState(QBluetoothSocket::UnconnectedState);
              return;
          }
      
          inputThread = new InputStreamThread(this);
          QObject::connect(inputThread, SIGNAL(dataAvailable()),
                           q, SIGNAL(readyRead()), Qt::QueuedConnection);
          QObject::connect(inputThread, SIGNAL(error(int)),
                           this, SLOT(inputThreadError(int)), Qt::QueuedConnection);
      
          if (!inputThread->run()) {
              //close socket again
              socketObject.callMethod<void>("close");
              if (env->ExceptionCheck()) {
                  env->ExceptionDescribe();
                  env->ExceptionClear();
              }
      
              socketObject = inputStream = outputStream = remoteDevice = QAndroidJniObject();
      
              delete inputThread;
              inputThread = 0;
      
              errorString = QBluetoothSocket::tr("Input stream thread cannot be started");
              q->setSocketError(QBluetoothSocket::NetworkError);
              q->setSocketState(QBluetoothSocket::UnconnectedState);
              return;
          }
      
          q->setSocketState(QBluetoothSocket::ConnectedState);
          emit q->connected();
      }
      
      

      And yes... It worked with following output.

      D/Qt      (26912): ../sprcc/src/Bluetooth/BluetoothClientWorker.cpp:37 (void BluetoothClientWorker::connectToHost(const QBluetoothAddress&, const QBluetoothUuid&)): [BluetoothClientWorker] Connecting using  "{00001101-0000-1000-8000-00805f9b34fb}"
      D/Qt      (26912): ../sprcc/src/Bluetooth/BluetoothClientWorker.cpp:130 (void BluetoothClientWorker::stateChanged(QBluetoothSocket::SocketState)): [BluetoothClientWorker] State: "Connecting"
      W/BluetoothAdapter(26912): getBluetoothService() called with no BluetoothManagerCallback
      D/BTIF_SOCK(  946): service_uuid: 00001101-0000-1000-8000-00805f9b34fb
      D/BluetoothSocket(26912): connect(), SocketState: INIT, mPfd: {ParcelFileDescriptor: FileDescriptor[68]}
      W/bt-sdp  (  946): SDP - Rcvd conn cnf with error: 0x4  CID 0x40
      E/bt-btif (  946): DISCOVERY_COMP_EVT slot id:130, failed to find channle,                                       status:1, scn:0
      W/System.err(26912): java.io.IOException: read failed, socket might closed or timeout, read ret: -1
      W/bt-btif (  946): invalid rfc slot id: 130
      W/System.err(26912): 	at android.bluetooth.BluetoothSocket.readAll(BluetoothSocket.java:505)
      W/System.err(26912): 	at android.bluetooth.BluetoothSocket.readInt(BluetoothSocket.java:516)
      W/System.err(26912): 	at android.bluetooth.BluetoothSocket.connect(BluetoothSocket.java:320)
      W/System.err(26912): 	at dalvik.system.NativeStart.run(Native Method)
      W/Qt      (26912): /Developer/Native/qtconnectivity/src/bluetooth/qbluetoothsocket_android.cpp:166 (void QBluetoothSocketPrivate::connectToServiceConc(const QBluetoothAddress&, const QBluetoothUuid&, QIODevice::OpenMode)): qt.bluetooth.android: Falling back to workaround.
      W/Qt      (26912): /Developer/Native/qtconnectivity/src/bluetooth/qbluetoothsocket_android.cpp:283 (void QBluetoothSocketPrivate::connectToServiceConc(const QBluetoothAddress&, const QBluetoothUuid&, QIODevice::OpenMode)): qt.bluetooth.android: Invoke Result successfull.
      W/BluetoothAdapter(26912): getBluetoothService() called with no BluetoothManagerCallback
      D/BluetoothSocket(26912): connect(), SocketState: INIT, mPfd: {ParcelFileDescriptor: FileDescriptor[69]}
      W/bt-btif (  946): info:x10
      D/        (  946): remote version info [00:12:ff:c7:00:c9]: 4, a, 12e9
      I/ActivityManager(  451): Start proc com.skype.raider for broadcast com.skype.raider/com.skype.android.audio.BluetoothReceiver: pid=27019 uid=10098 gids={50098, 3003, 3002, 1028, 1015}
      D/dalvikvm(27019): Trying to load lib /data/app-lib/com.skype.raider-1/libSkypeAndroid.so 0x41c68e00
      W/linker  (27019): libSkypeAndroid.so has text relocations. This is wasting memory and is a security risk. Please fix.
      D/dalvikvm(27019): Added shared lib /data/app-lib/com.skype.raider-1/libSkypeAndroid.so 0x41c68e00
      W/bt-btif (  946): new conn_srvc id:26, app_id:1
      W/bt-btif (  946): bta_dm_pm_ssr conn_srvc id:26, app_id:1
      W/bt-btif (  946): bta_dm_pm_ssr:2, lat:1200
      D/Qt      (26912): ../sprcc/src/Bluetooth/BluetoothClientWorker.cpp:130 (void BluetoothClientWorker::stateChanged(QBluetoothSocket::SocketState)): [BluetoothClientWorker] State: "Connected"
      D/dalvikvm(27019): GC_CONCURRENT freed 317K, 11% free 3154K/3536K, paused 3ms+2ms, total 22ms
      D/dalvikvm(27019): GC_CONCURRENT freed 404K, 13% free 3172K/3640K, paused 2ms+2ms, total 12ms
      D/dalvikvm(27019): GC_CONCURRENT freed 368K, 13% free 3190K/3640K, paused 1ms+1ms, total 8ms
      D/dalvikvm(27019): GC_CONCURRENT freed 354K, 12% free 3221K/3640K, paused 1ms+1ms, total 8ms
      D/dalvikvm(27019): GC_CONCURRENT freed 437K, 14% free 3236K/3736K, paused 2ms+1ms, total 9ms
      D/dalvikvm(27019): GC_CONCURRENT freed 431K, 14% free 3272K/3768K, paused 1ms+2ms, total 14ms
      D/dalvikvm(27019): GC_CONCURRENT freed 405K, 13% free 3356K/3824K, paused 1ms+15ms, total 30ms
      D/dalvikvm(27019): GC_CONCURRENT freed 420K, 13% free 3365K/3848K, paused 2ms+11ms, total 23ms
      D/dalvikvm(27019): GC_CONCURRENT freed 339K, 11% free 3445K/3860K, paused 1ms+2ms, total 24ms
      D/dalvikvm(27019): GC_CONCURRENT freed 372K, 10% free 3520K/3896K, paused 2ms+1ms, total 15ms
      D//Ln.java:218(27019): main Configuring Logging, minimum log level is INFO
      D/dalvikvm(27019): GC_CONCURRENT freed 448K, 13% free 3458K/3972K, paused 2ms+1ms, total 10ms
      D/dalvikvm(27019): GC_FOR_ALLOC freed 49K, 12% free 3531K/4012K, paused 7ms, total 7ms
      D/dalvikvm(27019): GC_FOR_ALLOC freed 81K, 12% free 3641K/4092K, paused 8ms, total 8ms
      D/BluetoothManagerService(  451): Message: 20
      D/BluetoothManagerService(  451): Added callback: android.bluetooth.IBluetoothManagerCallback$Stub$Proxy@42484b68:true
      D/btif_config_util(  946): btif_config_save_file(L153): in file name:/data/misc/bluedroid/bt_config.new
      
      
      

      Is there any way to implement this patch? Or is it too ugly?

        Attachments

          Issue Links

          No reviews matched the request. Check your Options in the drop-down menu of this sections header.

            Activity

              People

              Assignee:
              ablasche Alex Blasche
              Reporter:
              firatagdas Firat Agdas
              Votes:
              1 Vote for this issue
              Watchers:
              3 Start watching this issue

                Dates

                Created:
                Updated:
                Resolved:

                  Gerrit Reviews

                  There are no open Gerrit changes