2015-09-24 17 views
5

vengo sopra errore indicato su alcuni dispositivi (molto raramente, 2 volte fino ad ora solo):SQLiteDiskIOException: disco I/O error (codice 3850)

android.database.sqlite.SQLiteDiskIOException: disk I/O error (code 3850) 
    at android.database.sqlite.SQLiteConnection.nativeExecuteForString(Native Method) 
    at android.database.sqlite.SQLiteConnection.executeForString(SQLiteConnection.java:679) 
    at android.database.sqlite.SQLiteConnection.setJournalMode(SQLiteConnection.java:361) 
    at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:236) 
    at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:200) 
    at android.database.sqlite.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:463) 
    at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:185) 
    at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:177) 
    at android.database.sqlite.SQLiteDatabase.openInner(SQLiteDatabase.java:806) 
    at android.database.sqlite.SQLiteDatabase.open(SQLiteDatabase.java:791) 
    at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:694) 
    at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:669) 
    at ***.a(***.java:115) 

La linea 115 nel mio codice è il seguente:

// here the exception occurs 
SQLiteDatabase db = SQLiteDatabase.openDatabase(pathApp, null, SQLiteDatabase.OPEN_READONLY); 
// ... 
db.close(); 

Story

Quello che faccio è la seguente:

  • applicazione ha i privilegi di root
  • copia il database da un'altra applicazione in essa la propria directory
  • si tenta di aprire il database e leggere alcuni dati
  • si chiude il file di nuovo

Questo è tutto . Questo sta lavorando su migliaia di dispositivi. La mia app di sicuro accede solo il database in su posto, io sono del tutto sicuro di questo

Domanda

Qualcuno sa che cosa potrebbe causare questo problema?

fatti

Forse interessanti

  • i 2 dispositivi sono un OnePlus2
  • un ragazzo mi ha detto che il problema si è verificato dopo l'aggiornamento a ossigeno 2,1
+0

Ricevo improvvisamente segnalazioni da parte dell'utente di questo errore (dal 25 settembre, prima che non apparisse mai). Tutte le istanze sono su un dispositivo ONE e con Android 5.1.1. Forse quel dispositivo ha ricevuto un recente aggiornamento del sistema che ha causato questo? – mike47

+0

i due dispositivi che conosco che sono stati effettuati hanno ottenuto un aggiornamento del sistema ... a Oxygen 2.1 ... Ma non ne so più nulla ... E non ho trovato ancora nulla ... – prom85

+0

Finalmente trovato un soluzione :-). Aggiungi i binari sqlite alla tua app, scopri quale funziona sul dispositivo e DUMP il database sulla console e analizza l'output ... Funziona anche su OnePlus2 – prom85

risposta

0

Ecco la soluzione di lavoro (già testato in produzione per 2 mesi ora o giù di lì) e questo funziona sul OnePlus2 e su Android 6 così:

Poi, nel tuo app, provate a leggere un database esterno come segue:

  • Scopri quali binario sta lavorando. Ho provato alcuni metodi (via chiamando /proc/cpuinfo per esempio), ma non sono riuscito a trovare una soluzione affidabile, quindi lo faccio attraverso tentativi ed errori, come segue:
    • prima cosa copiare il binario dalla mia cartella di beni per le mie applicazioni cartella files
    • poi cerco di eseguire il dump del database desiderato tramite <path_to_SQLite3_bnary> <path_to_database> \.dump '<tablename>'\n e leggere il risultato
    • controlla il risultato, se contiene error: so che il binario non funziona, se inizia con INSERT INTO so che funziona
    • I ripeti questo con i miei binari fino a quando ho trovato un file binario funzionante
  • Quindi ho appena letto il risultato. Il risultato conterrà un errore o sarà un contenuto simile a csv. O gestisco l'errore o converto ogni riga in csv valido via row.replace("INSERT INTO \"" + tablename + "\" VALUES(", "").replace(");", ""), in modo da ottenere il contenuto in un formato csv. Io uso opencsv di CSVReader per analizzare i dati, allora ...

Questo è tutto, questo funziona (fino al sapere) su tutti i dispositivi senza problemi

Codice - copiato da mie fonti, adotta un po ' per soddisfare le vostre esigenze

public static List<String> readCSVData(String pathDatabase, String tableName) throws InterruptedException, TimeoutException, RootDeniedException, IOException 
{ 
    List<String> res = null; 
    List<String> csvData = null; 

    final String[] architectures = new String[]{ 
      "armv7", 
      "armv7-pie", 
      "armv6", 
      "armv6-nofpu" 
    }; 

    for (int i = 0; i < architectures.length; i++) 
    { 
     res = readDatabase(architectures[i], pathDatabase, tableName, rootMethod); 

     if (res.toString().contains("[error:")) 
     { 
      L.d(RootNetworkUtil.class, "Trial and Error - ERROR: " + architectures[i]); 
     } 
     else 
     { 
      int maxLength = (res.toString().length() < 100) ? res.toString().length() : 100; 
      L.d(RootNetworkUtil.class, "Trial and Error - RESULT: " + res.toString().substring(0, maxLength)); 
      L.d(RootNetworkUtil.class, "Architecture found via trial and error: " + architectures[i]); 
      csvData = res; 
      break; 
     } 
    } 

    return csvData; 
} 

private static List<String> readDatabase(String architecture, String pathDB, String tablename) throws InterruptedException, TimeoutException, RootDeniedException, IOException { 
    String sqlite = "sqlite3." + architecture; 
    String pathSQLite3 = getSQLitePath(architecture, tablename); 
    // OWN class, just copy the file from the assets to the sqlite3 path!!! 
    AssetUtil.copyAsset(sqlite, pathSQLite3); 

    String[] cmd = new String[]{ 
      "su\n", 
      //"chown root.root " + pathSQLite3 + "\n", 
      "chmod 777 " + pathSQLite3 + "\n", 
      pathSQLite3 + " " + pathDB + " \".dump '" + tablename + "'\"\n" 
    }; 
    List<String> res = new ArrayList<>(); 
    List<String> temp = RootUtils.execute(cmd); 
    for (int i = 0; i < temp.size(); i++) 
    { 
     // Fehlerzeilen behalten!!! 
     if (temp.get(i).contains("error:")) 
      res.add(temp.get(i)); 
     else if (temp.get(i).startsWith("INSERT INTO \"" + tablename + "\"")) 
      res.add(temp.get(i).replace("INSERT INTO \"" + tablename + "\" VALUES(", "").replace(");", "")); 
    } 
    return res; 
} 

public static String getSQLitePath(String architecture, String addon) 
{ 
    String sqlite = "sqlite3." + architecture; 
    String pathSQLite3 = "/data/data/" + MainApp.get().getPackageName() + "/files/" + sqlite + addon; 
    return pathSQLite3; 
} 
1

mi sono imbattuto in un problema simile di recente dove la mia app funziona bene su tutti i dispositivi Android ad eccezione di OnePlus Two con OxygenOS 2.1.

Dopo aver esaminato il problema, sembra che questa combinazione specifica sia molto sensibile e si blocchi in modo anomalo su un blocco di database di qualche tipo. Nel mio caso, la mia app stava copiando un nuovo database sul dispositivo alla prima esecuzione, quindi controllando la versione del database per vedere se è necessario un aggiornamento. Al momento del controllo si è schiantato su questi dispositivi. Ho realizzato nel mio codice che sto aprendo un'istanza separata al database invece di utilizzare il database attualmente aperto durante il controllo della versione. Dopo aver modificato il codice per evitare di aprire un'istanza separata del database, l'app si è arrestata in modo anomalo su OnePlus.

Il mio consiglio è di non aprire più istanze del database nell'app o provare a chiudere il database prima di aprirlo di nuovo (forse il metodo di copia non ha chiuso il database o utilizza un'altra istanza dello stesso database).

+0

il mio metodo di copia copia il file come uno stream in modo che eventuali flag interni rimangano come prima ... Come posso chiudere il database dopo aver copiato il file? Sto copiando un file da un'altra app (la mia app ha i diritti di root) e lo copio nella mia directory in modo che possa leggerlo con 'SQLiteDatabase' ... – prom85

+0

Nella mia app sto copiando anche come stream ma questo sta accadendo all'interno della stessa app e all'interno di un'altra funzione che tenta di aprire il database prima di controllare se esiste quindi CHIUDE e poi lo copia come un flusso. Quindi assicurati che sia chiuso prima che venga copiato. – hbustan

+0

Non posso ... Non ho il controllo del file di database ... Posso in qualche modo chiuderlo direttamente tramite sqlite3 ... Devo controllare che ... – prom85

1

appena incontrato questo in fase di sviluppo. Si è attivato quando il telefono ha esaurito le batterie e si è spento. Presumibilmente, devi semplicemente afferrare il blocco del database quando ciò accade.