Java 蓝牙:服务发现失败

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18378340/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 01:01:01  来源:igfitidea点击:

Bluetooth : Service discovery failed

javaandroidbluetoothandroid-bluetooth

提问by ben75

I try to establish a Bluetooth connection between my Android App (on a Samsung phone running 4.1.2: the client) and my Laptop (Win7, 64bits: the server). It has always failed with a Service discovery failed.

我尝试在我的 Android 应用程序(在运行 4.1.2 的三星手机上:客户端)和我的笔记本电脑(Win7,64 位:服务器)之间建立蓝牙连接。它总是因服务发现失败而失败

I read various topics about this (hereand there) but it didn't solve my problem.

我阅读了关于这个的各种主题(这里那里),但它没有解决我的问题。

I have two questions:

我有两个问题:

  • what means the well known UUID "00001101-0000-1000-8000-00805F9B34FB". Why/when should it be used ?
  • any suggestion to investigate/solve my problem would be appreciated.
  • 众所周知的 UUID "00001101-0000-1000-8000-00805F9B34FB"是什么意思。为什么/什么时候应该使用它?
  • 任何调查/解决我的问题的建议将不胜感激。

Remarks:

评论:

  • I tried to establish a secured and unsecured connection (same failure with both)
  • I'm able to pair my laptop and my device from Settings>Bluetooth
  • As suggested in comments : I tried with a randomly generated UUID (but the same on both side) instead of the well known one, but I still have exactly the same behavior.
  • 我试图建立安全和不安全的连接(两者都失败)
  • 我可以从“设置”>“蓝牙”配对我的笔记本电脑和我的设备
  • 正如评论中所建议的:我尝试使用随机生成的 UUID(但两侧相同)而不是众所周知的UUID ,但我仍然具有完全相同的行为。

I have those permissions

我有这些权限

<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>

EDIT

编辑

Instead of harcoding the UUID on client side, I tried the following (but still get the same error):

我没有在客户端对 UUID 进行硬编码,而是尝试了以下操作(但仍然出现相同的错误):

UUID uuid = bluetoothDevice.getUuids()[bluetoothDevice.getUuids().length-1].getUuid();

The UUID of the echo-server is always the last one in the array.

echo-server 的 UUID 始终是数组中的最后一个。

END EDIT

结束编辑

Here are the relevant logs on the client:

以下是客户端的相关日志:

08-22 12:30:28.627: ERROR/BluetoothService.cpp(12008): stopDiscoveryNative: D-Bus error in StopDiscovery: org.bluez.Error.Failed (Invalid discovery session)
08-22 12:30:28.647: INFO/BluetoothSocket.cpp(18030): Setting Master socket option
08-22 12:30:28.647: VERBOSE/BluetoothSocket.cpp(18030): ...fd 43 created (RFCOMM, lm = 7)
08-22 12:30:28.687: DEBUG/BluetoothPolicyService(12008): getAllowBluetoothDataTransfer - showMsg: true
08-22 12:30:28.687: DEBUG/BluetoothPolicyService(12008): MDM: isProfileEnabled = true
08-22 12:30:28.697: DEBUG/BluetoothUtils(18030): isSocketAllowedBySecurityPolicy start : device null
08-22 12:30:28.727: ERROR/BluetoothEventLoop.cpp(12008): onCreateDeviceResult: D-Bus error: org.bluez.Error.AlreadyExists (Already Exists)
08-22 12:30:28.727: VERBOSE/BluetoothService.cpp(12008): discoverServicesNative
08-22 12:30:28.727: VERBOSE/BluetoothService.cpp(12008): ... Object Path = /org/bluez/12635/hci0/dev_00_09_DD_50_88_54
08-22 12:30:28.727: VERBOSE/BluetoothService.cpp(12008): ... Pattern = , strlen = 0
08-22 12:30:29.138: VERBOSE/BluetoothEventLoop.cpp(12008): event_filter: Received signal org.bluez.Device:PropertyChanged from /org/bluez/12635/hci0/dev_00_09_DD_50_88_54
08-22 12:30:29.138: DEBUG/BluetoothEventLoop(12008): Device property changed
08-22 12:30:32.141: DEBUG/BluetoothA2DPStateReceiver(15827): BluetoothA2DPStateReceiver constructor call()
08-22 12:30:32.141: DEBUG/BluetoothA2DPStateReceiver(15827): onReceive(): action = android.bluetooth.device.action.ACL_CONNECTED
08-22 12:30:32.141: DEBUG/BluetoothA2DPStateReceiver(15827): ACTION_ACL_CONNECTED
08-22 12:30:32.141: DEBUG/BluetoothA2DPSinkInfo(15827): checkBlackListCarkit() : isBlackListCarkit false
08-22 12:30:32.161: DEBUG/BluetoothNotiBroadcastReceiver(15910): onReceive
08-22 12:30:40.749: ERROR/Bluetooth(18030): Cannot connect
    java.io.IOException: Service discovery failed
    at android.bluetooth.BluetoothSocket$SdpHelper.doSdp(BluetoothSocket.java:475)
    at android.bluetooth.BluetoothSocket.connect(BluetoothSocket.java:241)
    at com.company.BlueToothTestActivity.open(BlueToothTestActivity.java:48)
    at com.company.BlueToothTestActivity.run(BlueToothTestActivity.java:29)
08-22 12:30:40.749: WARN/Bluetooth(18030): Unable to open connection !


Here is the code to reproduce the error (it's simplified version, it compiles and reproduce the error - at least on my hardware -)

这是重现错误的代码(它是简化版本,它编译并重现错误 - 至少在我的硬件上 -)

Client

客户

import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;

import java.io.IOException;
import java.util.UUID;

public class BlueToothTestActivity extends Activity {

private String macAddress = "00:09:DD:50:88:54";  //hardcoded laptop macAddress
private BluetoothAdapter mBluetoothAdapter;
private BluetoothDevice bluetoothDevice;
private BluetoothSocket socket;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);   
    Thread bluetoothClientThread = new Thread(){
        @Override
        public void run() {
            if(open()){
                Log.i("Bluetooth","Connection is open !");
            }else{
                Log.w("Bluetooth","Unable to open connection !");
            }
        }
    };
    bluetoothClientThread.start();
    initUI();
}

public boolean open() {
    mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    bluetoothDevice = mBluetoothAdapter.getRemoteDevice(macAddress);
    String BT_UUID = "00001101-0000-1000-8000-00805F9B34FB";
    try {
        mBluetoothAdapter.cancelDiscovery();
        //socket = bluetoothDevice.createInsecureRfcommSocketToServiceRecord(UUID.fromString(BT_UUID));
        socket = bluetoothDevice.createRfcommSocketToServiceRecord(UUID.fromString(BT_UUID));
        socket.connect(); //Block 12 sec here, then throw the exception.
        return true;
    } catch (IOException e) {
        try {
            socket.close();
        } catch (IOException closeException) { }
        Log.e("Bluetooth", "Cannot connect", e);
        return false;
    }
}

private void initUI(){
    LinearLayout linearLayout = new LinearLayout(this);
    Button finish = new Button(this);
    finish.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            if(socket!=null){
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            BlueToothTestActivity.this.finish();
        }
    });
    finish.setText("Exit");
    linearLayout.addView(finish);
    setContentView(linearLayout);
}
}

The server is a simple echo server(based on Bluecove library, I took the code from here : http://www.miniware.net/mobile/articles/viewarticle.php?id=22)

服务器是一个简单的回显服务器(基于 Bluecove 库,我从这里获取代码:http: //www.miniware.net/mobile/articles/viewarticle.php?id=22

Server

服务器

import java.io.*;
import javax.bluetooth.*;
import javax.microedition.io.*;

// sample code from : http://www.miniware.net/mobile/articles/viewarticle.php?id=22   (Nikos Fotiou)
public class EchoServer {
    public final UUID uuid = new UUID("0000110100001000800000805F9B34FB",false);
    public final String name = "EchoServer";                       //the name of the service
    public final String url  =  "btspp://localhost:" + uuid + ";name=" + name  + ";authenticate=false;encrypt=false;";
    LocalDevice local = null;
    StreamConnectionNotifier server = null;
    StreamConnection conn = null;

    public EchoServer() {
    try {
        System.out.println("Setting device to be discoverable...");
        local = LocalDevice.getLocalDevice();
        local.setDiscoverable(DiscoveryAgent.GIAC);
        System.out.println("Start service:"+url);
        server = (StreamConnectionNotifier)Connector.open(url);
        System.out.println("Waiting for incoming connection...");
        conn = server.acceptAndOpen();  // stop and wait here
        System.out.println("Client Connected..."); //never reach this line
        DataInputStream din   = new DataInputStream(conn.openInputStream());
        while(true){
            String cmd = "";
            char c;
            while (((c = din.readChar()) > 0) && (c!='\n') ){
                cmd = cmd + c;
            }
            System.out.println("Received " + cmd);
        }
    } catch (Exception  e) {
        System.err.println("Exception Occured: " + e.toString());
        e.printStackTrace();
    }
}

public static void main (String args[]){
    EchoServer echoserver = new EchoServer();
}

}

Server pom.xml

服务器 pom.xml

<dependencies>
    <dependency>
        <groupId>net.sf.bluecove</groupId>
        <artifactId>bluecove</artifactId>
        <version>2.1.1-SNAPSHOT</version>
    </dependency>
</dependencies>

<repositories>
    <repository>
        <id>pyx4me-web-snapshot</id>
        <url>http://www.pyx4me.com/maven2-snapshot</url>
        <snapshots>
            <enabled>true</enabled>
        </snapshots>
        <releases>
            <enabled>false</enabled>
        </releases>
    </repository>
</repositories>

采纳答案by allprog

The UUID you try to use is the Serial Port Profile UUID. It could be declared in code like

您尝试使用的 UUID 是串行端口配置文件 UUID。它可以在代码中声明,如

private static final UUID BLUETOOTH_SPP_UUID =
                UUID.fromString("00001101-0000-1000-8000-00805f9b34fb");

I tried your code with a Windows 8 laptop and a Nexus S. First I had to pair the devices from the Nexus. Then I started the server and used the Bluetooth SPP app to test the connection. It worked flawlessly. Then I started your code and it worked as well and it worked too.

我在 Windows 8 笔记本电脑和 Nexus S 上尝试了您的代码。首先,我必须将 Nexus 上的设备配对。然后我启动服务器并使用蓝牙SPP应用程序测试连接。它完美无缺。然后我启动了你的代码,它运行良好,也运行良好。

I could reproduce the "Service discovery failed" exception when the server side was not started. Also, after I scanned all 30 channels with the createRfcommSocketmethod, the bluetooth stack on the phone got corrupted and I had to restart the device.

当服务器端未启动时,我可以重现“服务发现失败”异常。此外,在我使用该createRfcommSocket方法扫描所有 30 个频道后,手机上的蓝牙堆栈已损坏,我不得不重新启动设备。

In conclusion, to make sure you are able to communicate:

总之,为了确保您能够进行交流:

  1. on the laptop make sure that the bluetooth is in discoverable state
  2. (optional) turn off UAC and use an admin account to make sure you don't encounter any security bugs (I didn't have to do this but on the second start the firewall had to be opened for eclipse to enable debugging)
  3. restart the phone
  4. pair from the phone
  5. use the SPP UUID, not a custom one
  6. ensure you use the right mac address by adding System.out.println(local.getBluetoothAddress());somewhere before the acceptAndOpen()invocation.
  7. test the connection with a third party app from the play store. I used this onein command line mode. Only the connection needs to be tested.
  8. update the MAC address and run the app
  9. it should work.
  1. 在笔记本电脑上确保蓝牙处于可发现状态
  2. (可选)关闭 UAC 并使用管理员帐户以确保您不会遇到任何安全错误(我不必这样做,但在第二次启动时必须为 Eclipse 打开防火墙以启用调试)
  3. 重启手机
  4. 从手机配对
  5. 使用 SPP UUID,而不是自定义的
  6. 通过System.out.println(local.getBluetoothAddress());acceptAndOpen()调用前添加某处来确保您使用正确的 mac 地址。
  7. 测试与 Play 商店中第三方应用的连接。我在命令行模式下使用了这个。只需要测试连接。
  8. 更新 MAC 地址并运行应用程序
  9. 它应该工作。

Here is the output I got from the run:

这是我从运行中得到的输出:

Start service:btspp://localhost:0000110100001000800000805f9b34fb;name=EchoServer;authenticate=false;encrypt=false;
MAC 402CF454215C
Waiting for incoming connection...
Client Connected...
Exception Occured: java.io.EOFException
BlueCove stack shutdown completed
java.io.EOFException
    at java.io.DataInputStream.readChar(Unknown Source)
    at examples.bluetooth_spp_server.EchoServer.<init>(EchoServer.java:30)
    at examples.bluetooth_spp_server.EchoServer.main(EchoServer.java:42)

For the sake of completeness, here is the error that is returned under various conditions

为了完整起见,这里是各种条件下返回的错误

  • Windows bluetooth turned off: javax.bluetooth.BluetoothStateException: Bluetooth not detected
  • Android bluetooth turned off: java.io.IOException: Unable to start Service Discovery
  • Windows server not running: java.io.IOException: Service discovery failed
  • Not paired: TimeoutException
  • Windows 蓝牙关闭: javax.bluetooth.BluetoothStateException: Bluetooth not detected
  • 安卓蓝牙关闭: java.io.IOException: Unable to start Service Discovery
  • Windows 服务器未运行: java.io.IOException: Service discovery failed
  • 未配对: TimeoutException

Theoretically pairing should happen automatically when a secure connection is initiated but in reality the pairing dialog may not appear in all cases on the phone or in Windows. This is a factor of uncertainty that needs to be considered if failures happen.

理论上配对应该在启动安全连接时自动发生,但实际上配对对话框可能不会在所有情况下都出现在手机或 Windows 中。如果发生故障,这是一个需要考虑的不确定因素。

回答by ligi

a) The UUID is a Serial-Port UUID - mostly needed for using devices that do not speak the SDP protocol - e.g. small embedded RFCOMM devices.

a) UUID 是串行端口 UUID - 主要用于使用不使用 SDP 协议的设备 - 例如小型嵌入式 RFCOMM 设备。

b) Check if the bluetooth is switched on on your phone.

b) 检查手机蓝牙是否开启。