9

残念ながら、Android の Bluetooth に問題があります。私のテスト環境では、Android 4.4.2 を搭載した Nexus 4 を使用しています。

PC に Java アプリケーションがあり、クライアントとして SPP 接続を行うために bluecove を使用しています。プログラムは特別なサービス名を探しており、Android フォンに接続します。その後、72 バイトを Android フォンに送信し、応答を待ちます。その答えを得ると、プログラムは 3 秒間スリープし、その後再び開始します。

Androidフォンには、起動時に開始されるバックグラウンドBluetoothリスナーを備えたアプリケーションがあります。このアプリケーションは、BluetoothChat サンプル デモに基づいています。Bluetooth データを受信するときは、受信データを確認して応答を返します。

すべて正常に動作しています。しかし、489 回の Bluetooth 接続の後、PC-java-app の実行中に Android アプリが次のエラー スニペットで失敗します。

getBluetoothService() called with no BluetoothManagerCallback
Shutting down VM
threadid=1: thread exiting with uncaught exception (group=0x41b34ba8)
FATAL EXCEPTION: main
Process: de.tum.lme.diamantum:remote_blue, PID: 21567
java.lang.NullPointerException: FileDescriptor must not be null
    at android.os.ParcelFileDescriptor.<init>(ParcelFileDescriptor.java:174)
    at android.os.ParcelFileDescriptor$1.createFromParcel(ParcelFileDescriptor.java:905)
    at android.os.ParcelFileDescriptor$1.createFromParcel(ParcelFileDescriptor.java:897)
    at android.bluetooth.IBluetooth$Stub$Proxy.createSocketChannel(IBluetooth.java:1355)
    at android.bluetooth.BluetoothSocket.bindListen(BluetoothSocket.java:349)
    at android.bluetooth.BluetoothAdapter.createNewRfcommSocketAndRecord(BluetoothAdapter.java:1055)
    at android.bluetooth.BluetoothAdapter.listenUsingRfcommWithServiceRecord(BluetoothAdapter.java:976)
    at com.test.btconn.BluetoothHandling$AcceptThread.<init>(BluetoothHandling.java:449)
    at com.test.btconn.BluetoothHandling.start(BluetoothHandling.java:216)
    at com.test.btconn.BluetoothListenerService.setupBtSockets(BluetoothListenerService.java:330)
    at com.test.btconn.BluetoothListenerService.manageBtState(BluetoothListenerService.java:249)
    at com.test.btconn.BluetoothListenerService.setBtStateDisconnected(BluetoothListenerService.java:383)
    at com.test.btconn.BluetoothListenerService.access$5(BluetoothListenerService.java:378)
    at com.test.btconn.BluetoothListenerService$2.handleMessage(BluetoothListenerService.java:421)

そのため、アプリは ParcelFileDescriptor に問題があり、突然 null になります。しかし、なぜ?

上記のすべては、PC-java-app で一時停止時間を変更したり、送信にさまざまなデータ サイズを使用したり、さまざまなスマートフォンを使用したりするときにも発生します。リフレクション「listenUsingRfcommWithServiceRecord」を使用すると、505回の送信後に同じことが起こります。また、ウェイクロックを使用しても何も変わりません。

ちなみに、BluetoothChat サンプルを使用した場合も同様の動作が得られました。

それで、誰かヒントはありますか?

アップデート:

BluetoothServerSocket は接続ごとに閉じられ、Bluetooth 状態が 3 の場合は BluetoothSocket が閉じられます。

4

4 に答える 4

4

私が尋ねた質問に対する私の修正:

private synchronized void clearFileDescriptor(){
        try{
            Field field = BluetoothSocket.class.getDeclaredField("mPfd");
            field.setAccessible(true);
            ParcelFileDescriptor mPfd = (ParcelFileDescriptor)field.get(socket);
            if(null == mPfd){
                return;
            }
            mPfd.close();
        }catch(Exception e){
            Log.w(SensorTicker.TAG, "ParcelFileDescriptor could not be cleanly closed.");
        }
    }

したがって、上記はファイル記述子を閉じるために作成したメソッドであり、このコードを使用した場合は以下のとおりです。常に、ソケットを閉じる必要があります。

private synchronized void cleanClose() {
        if (socket != null) {
            try {
                clearFileDescriptor();
                //clearLocalSocket();
                socket.close();         
            }
            catch (IOException e) {
                Log.w(SensorTicker.TAG, "Socket could not be cleanly closed.");
            }
        }
    }

私が書いた clearLocalSocket() メソッドも試しましたが、私の問題には使用されませんでした。だから私はFileDescriptorを閉じようとしました。あなたと同じ問題に直面している他の人に役立つことを願っています。

于 2014-11-27T06:01:46.613 に答える
0

アプリで bluetooth をサーバーとして使用している場合、これと同じ問題に遭遇しましたが、私の問題は、リフレクションを行うときにファイル記述子 mPfd で null になることです。この方法を使用してファイルを閉じることができました。これが役立つことを願っています。

ParceFileDescriptor を使用して、BluetoothSocket の LoaclSocket から ID/インデックスを介してファイルを取得します。int mfd = 0; フィールド socketField = null; LocalSocket mSocket = null;

    try
    {
        socketField = btSocket.getClass().getDeclaredField("mSocket");
        socketField.setAccessible(true);

        mSocket = (LocalSocket)socketField.get(btSocket);
    }
    catch(Exception e)
    {
        Log ( "Exception getting mSocket in cleanCloseFix(): " + e.toString());
    }

    if(mSocket != null)
    {
        FileDescriptor fileDescriptor =
                mSocket.getFileDescriptor();

        String in = fileDescriptor.toString();

        //regular expression to get filedescriptor index id
        Pattern p = Pattern.compile("\\[(.*?)\\]");
        Matcher m = p.matcher(in);

        while(m.find()) {
            Log ( "File Descriptor " + m.group(1));
            mfd = Integer.parseInt(m.group(1));
            break;
        }

        //Shutdown the socket properly
        mSocket.shutdownInput();
        mSocket.shutdownOutput();
        mSocket.close();

        mSocket = null;

        try { socketField.set(btSocket, mSocket); }
        catch(Exception e)
        {
            Log ("Exception setting mSocket = null in cleanCloseFix(): " + e.toString());
        }

        //Close the file descriptor when we have it from the Local Socket
        try {
            ParcelFileDescriptor parcelFileDescriptor = ParcelFileDescriptor.adoptFd(mfd);
            if (parcelFileDescriptor != null) {
                parcelFileDescriptor.close();
                Log ( "File descriptor close succeed : FD = " + mfd);
            }
        } catch (Exception ex) {
            Log ( "File descriptor close exception " + ex.getMessage());
        }
    }
于 2016-01-14T20:27:17.720 に答える