2013-04-12 6 views
11

Sto configurando un collegamento accessorio USB tra il mio telefono Android e un altro dispositivo. Basta inviare i byte avanti e indietro per ora per testare. All'inizio ho una comunicazione precisa, ma finisce sempre per morire con Java.io.IOException: write failed: EBADF (Bad file number)" dopo circa un secondo. A volte la lettura rimane in vita ma la scrittura muore; altri muoiono entrambi.Java.io.IOException, connessione USB "numero file errato"

non sto facendo niente super elegante, lettura e scrittura, proprio come la documentazione di Google:

connessione iniziale (all'interno di un ricevitore di broadcast, so che questo parte funziona almeno inizialmente):

if (action.equals(ACTION_USB_PERMISSION)) 
{ 
    ParcelFileDescriptor pfd = manager.openAccessory(accessory); 
    if (pfd != null) { 
     FileDescriptor fd = pfd.getFileDescriptor(); 
     mIn = new FileInputStream(fd); 
     mOut = new FileOutputStream(fd); 
    } 
} 

Reading:

Thread thread = new Thread(new Runnable() { 
    @Override 
    public void run() { 
     byte[] buf = new byte[BUF_SIZE]; 
     while (true) 
     { 
      try { 
       int recvd = mIn.read(buf); 
       if (recvd > 0) { 
        byte[] b = new byte[recvd]; 
        System.arraycopy(buf, 0, b, 0, recvd); 
        //Parse message 
       } 
      } 
      catch (IOException e) { 
       Log.e("read error", "failed to read from stream"); 
       e.printStackTrace(); 
      } 
     } 
    } 
}); 
thread.start(); 

scrittura:

synchronized(mWriteLock) { 
    if (mOut !=null && byteArray.length>0) { 
     try { 
      //mOut.flush(); 
      mOut.write(byteArray, 0, byteArray.length); 
     } 
     catch (IOException e) { 
      Log.e("error", "error writing"); 
      e.printStackTrace(); 
      return false; 
     } 
    } 
    else { 
     Log.e(TAG, "Can't send data, serial stream is null"); 
     return false; 
    } 
} 

Errore stacktrace:

java.io.IOException: write failed: EBADF (Bad file number) 
W/System.err(14028):  at libcore.io.IoBridge.write(IoBridge.java:452) 
W/System.err(14028):  at java.io.FileOutputStream.write(FileOutputStream.java:187) 
W/System.err(14028):  at com.my.android.transport.MyUSBService$5.send(MyUSBService.java:468) 
W/System.err(14028):  at com.my.android.transport.MyUSBService$3.onReceive(MyUSBService.java:164) 
W/System.err(14028):  at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:781) 
W/System.err(14028):  at android.os.Handler.handleCallback(Handler.java:608) 
W/System.err(14028):  at android.os.Handler.dispatchMessage(Handler.java:92) 
W/System.err(14028):  at android.os.Looper.loop(Looper.java:156) 
W/System.err(14028):  at android.app.ActivityThread.main(ActivityThread.java:5045) 
W/System.err(14028):  at java.lang.reflect.Method.invokeNative(Native Method) 
W/System.err(14028):  at java.lang.reflect.Method.invoke(Method.java:511) 
W/System.err(14028):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784) 
W/System.err(14028):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551) 
W/System.err(14028):  at dalvik.system.NativeStart.main(Native Method) 
W/System.err(14028): Caused by: libcore.io.ErrnoException: write failed: EBADF (Bad file number) 
W/System.err(14028):  at libcore.io.Posix.writeBytes(Native Method) 
W/System.err(14028):  at libcore.io.Posix.write(Posix.java:178) 
W/System.err(14028):  at libcore.io.BlockGuardOs.write(BlockGuardOs.java:191) 
W/System.err(14028):  at libcore.io.IoBridge.write(IoBridge.java:447) 
W/System.err(14028):  ... 13 more 

ho la registrazione in tutto il luogo e quindi so che non è qualcosa di troppo evidente, come ad esempio una nuova richiesta di autorizzazione in fase di ricezione (e quindi i flussi di file viene reinizializzata mid-lettura) . Anche i flussi non si stanno chiudendo, perché non ho mai potuto accadere da nessuna parte nel mio codice (per ora). Neanche io ricevo eventi distaccati o collegati (lo registro se succede). Nulla sembra troppo fuori dall'ordinario; muore e basta

Ho pensato che forse era un problema di concorrenza, quindi ho giocato con serrature e posti letto, niente ha funzionato che ho provato. Non penso che sia un problema di throughput o perché accade ancora quando dormo ogni lettura (su entrambe le estremità), e leggo un singolo pacchetto alla volta (bitrate super slow). C'è una possibilità che il buffer venga sovraccaricato dall'altra parte in qualche modo? Come farei a chiarire questo? Ho accesso al codice dell'altra parte, è anche un dispositivo Android, utilizzando la modalità Host. Nel caso in cui sia importante, posso postare anche quel codice: i trasferimenti di massa standard.

Il telefono ha solo il supporto scarno per la modalità accessorio Android? Ho provato due telefoni e entrambi falliscono allo stesso modo, quindi dubito che sia così.

Mi chiedo cosa causa questo errore in generale durante la scrittura o la lettura da USB su Android?

+0

Quale versione di Android stai utilizzando? Inoltre, con cosa stai cercando di comunicare? Credo che con Accessory Mode (stai usando la modalità Open Access di Android?) Hai bisogno di un dispositivo host compatibile come Arduino o FT311D. – TronicZomB

+0

Android 4.0.4. Posso ottenere la connessione iniziale bene, e non esiste un dispositivo "compatibile": se si inviano le richieste di controllo corrette, il telefono entra in modalità accessori se lo supporta. Una finestra di dialogo si apre sul mio telefono affermando che vede un accessorio - solo problemi con il mantenimento della connessione. –

+0

Oh ok, aspetta che veda un accessorio, il che significa che il tuo telefono è in modalità host, quindi non la modalità accessoria, giusto? Quale dispositivo fornisce alimentazione, telefono al dispositivo o dispositivo che fornisce al telefono? – TronicZomB

risposta

7

E 'finito per essere un problema di threading. Avevo bisogno di segregare più correttamente anche la scrittura, invece di limitarmi a leggere.

Ho finito per utilizzare this code come base.

+1

Ciao, ho lo stesso problema e ho visto sopra il collegamento ma non ha funzionato per me. per favore condividi qual è stato il problema del threading. – ashokk

1

OK, un paio di cose che ho notato che sembrava diverso da quello che faccio per Open Accessory Mode, che ho seguito la documentazione per l'accessorio USB per lo più, quindi dovrebbe essere molto simile, è che il mIn.read(buf); dovrebbe essere mIn.read(buf, 0, 64); per quanto come so.

Inoltre, è necessario dichiarare nelle dichiarazioni di classe thread myThread;. Quindi all'interno del tuo BroadcastReceiver dopo aver creato il nuovo FileInput/OutputStream, avere myThread = new thread(myHandler, myInputStream); seguito il mio myThread.start();.

Ora ho notato che comunichi direttamente con l'interfaccia utente dal tuo thread. Dovresti usare un gestore invece che il thread comunicherà e poi comunicherà nuovamente all'interfaccia utente, almeno da ciò che avevo letto.

Ecco un esempio di mio gestore e filo:

final Handler mHandler = new Handler() { 
    @Override 
    public void handleMessage(Message msg){ 

    } 
}; 

private class USB_Thread extends Thread { 
    Handler thisHandler; 
    FileInputStream thisInputStream; 

    USB_Thread(Handler handler, FileInputStream instream){ 
     thisHandler = handler; 
     thisInputStream = instream; 
    } 
    @Override 
    public void run(){ 
     while(true) { 
      try{ 
       if((thisInputStream != null) && (dataReceived == false)) { 
        Message msg = thisHandler.obtainMessage(); 
        int bytesRead = thisInputStream.read(USB_Data_In, 0, 63); 
        if (bytesRead > 0){ 
         dataReceived = true; 
         thisHandler.sendMessage(msg); 
        } 
       } 
      } 
      catch(IOException e){ 

      } 
     } 
    } 
} 

Inoltre, ci sono alcune demo aperto applicazione accessorio here.Potrebbero aiutarti a capire la modalità accessoria.

E inoltre sono noti problemi con un'applicazione che non riceve BroadcastReceiver per ACTION_USB_ACCESSORY/DEVICE_ATTACHED a livello di programmazione. Lo riceverà solo tramite il file manifest. Puoi trovare ulteriori informazioni su questo here e here.

In realtà non ho testato la variabile dataReceived nel gestore e solo recentemente ho modificato quella parte del mio codice. L'ho provato e non ha funzionato, quindi cercando di ricordare che cosa avevo letto, penso che non si trattasse di variabili che comunicano all'interno dei thread, ma di provare a usare qualcosa come .setText(). Ho aggiornato il mio codice per includere lo dataReceived=true nella discussione. Il gestore dovrebbe quindi essere utilizzato per aggiornare gli elementi nell'interfaccia utente, come ad esempio TextView s, ecc

discussione

FileDescriptor fd = mFileDescriptor.getFileDescriptor(); 
mInputStream = new FileInputStream(fd); 
mOutputStream = new FileOutputStream(fd); 
usbThread = new USB_Thread(mHandler, mInputStream); 
usbThread.start(); 
+0

Grazie per i suggerimenti, ma non sto comunicando direttamente con l'interfaccia utente; da dove l'hai preso? Il sovraccarico di 'mRead' era un buon consiglio, dovrei sempre specificare un massimo, ma non è cambiato molto. Sto pensando che questo potrebbe essere un problema lato hardware .... così difficile da dire. –

+0

Sì, l'interfaccia utente era una lettura errata. Potrebbe essere anche un possibile problema hardware.Ho testato il codice Open Accessory su tre tablet diversi, uno fuori marchio che non ha funzionato affatto, il Nexus 7 che ha funzionato bene, tranne quando acceso da uno stato off e poi un Galaxy Tab 2 7 "che funziona come il Nexus ma non ha il problema di avvio.Ma dove stai iniziando il tuo thread di lettura? – TronicZomB

+0

Ho provato in più posti, proprio ora in 'onCreate'. –

7

Ho avuto lo stesso problema nel mio codice e ho scoperto che ciò accade perché l'oggetto FileDescriptor era GCed.

Ho risolto questo problema aggiungendo il campo ParcelFileDescriptor in Attività (o Servizio).

Ho controllato il tuo primo snippet di codice e il codice su cui hai basato, e quest'ultimo ha il campo ParcelFileDescriptor in Thread.

Penso che se si modifica il codice come di seguito, funziona bene.

ParcelFileDescriptor mPfd; 
... 

if (action.equals(ACTION_USB_PERMISSION)) 
{ 
    mPfd = manager.openAccessory(accessory); 
    if (mPfd != null) { 
     FileDescriptor fd = mPfd.getFileDescriptor(); 
     mIn = new FileInputStream(fd); 
     mOut = new FileOutputStream(fd); 
    } 
} 
+1

Grazie per aver contribuito a questo. Non l'ho fatto da anni, ma spero che le persone lo trovino utile. –

+0

Questa risposta merita sicuramente più upvotes, il fatto che ParcelFileDescriptor sia GC non è affatto ovvio, ho avuto un metodo che restituisce un nuovo FileOutputStream (mPfd.getFileDescriptor()) e ho visto errori del genere dopo un paio di trasferimenti. Ho passato molte ore su questo, grazie amico! –