Ho il seguente SqlCipher DB. Funziona perfettamente quando installo l'app, ma se chiudo, rimuovi l'app dalla cronologia recente (fuori dallo stack) e riapri l'app che si blocca con il seguente errore. Il db non si aprirà dopo che si è verificata un'eccezione, ad esempio inserisco un 1/0 in un'attività per costringerlo a bloccarsi e lo stesso è accaduto di seguito.CREATE TABLE android_metadata ha avuto esito negativo quando si riapre sqlcipher DB
07-20 15:39:05.669: E/Database(21425): CREATE TABLE android_metadata failed
07-20 15:39:05.669: E/Database(21425): Failed to setLocale() when constructing, closing the database
07-20 15:39:05.669: E/Database(21425): net.sqlcipher.database.SQLiteException: file is encrypted or is not a database
.
Ho trovato il seguente link che sembra risolvere il problema (non sono sicuro che sia la soluzione) ma non sono sicuro di come implementarlo nel mio codice. Qualcuno potrebbe aiutare per favore o dirmi perché sto ricevendo questo errore?
http://rootslash.net/88542/sqlcipher-cant-open-database-after-apprestart
Questo è il mio codice DB, io uso SqlCipher SQLiteOpenHelper per creare il DB. Penso di aver bisogno di modificare questo codice in modo che restituisca un oggetto DB se ne esiste già uno e ne crea uno se non esiste. non sono sicuro di come.
Grazie in anticipo.
[EDIT1] Ho un LoginActivity che verifica le credenziali dell'utente. se sono validi carica il MenuActivity in cui ho messo un 1/0 per forzare un crash. Dopo l'arresto anomalo, se riaprio l'app si blocca in LoginActivity sulla riga in cui esegue una query sulla tabella Utente DB.
DBModel è una classe con i metodi SqliteOpenHelper e CRUD.
Quindi si blocca su checkUserInDB() nella classe DBModel, che a sua volta chiama queryAllFromUser().
07-25 13:45:43.043 10654-10654/? E/AppObj﹕ Build.SERIAL = SH43PWM07311
07-25 13:45:43.203 10654-10654/? E/AppObj﹕ secretKey = com.a[email protected]31a79cea
07-25 13:45:43.643 10654-10654/? E/Database﹕ CREATE TABLE android_metadata failed
07-25 13:45:43.643 10654-10654/? E/Database﹕ Failed to setLocale() when constructing, closing the database
net.sqlcipher.database.SQLiteException: file is encrypted or is not a database
at net.sqlcipher.database.SQLiteDatabase.native_setLocale(Native Method)
at net.sqlcipher.database.SQLiteDatabase.setLocale(SQLiteDatabase.java:2096)
at net.sqlcipher.database.SQLiteDatabase.<init>(SQLiteDatabase.java:1962)
at net.sqlcipher.database.SQLiteDatabase.openDatabase(SQLiteDatabase.java:881)
at net.sqlcipher.database.SQLiteDatabase.openOrCreateDatabase(SQLiteDatabase.java:913)
at net.sqlcipher.database.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:132)
at net.sqlcipher.database.SQLiteOpenHelper.getReadableDatabase(SQLiteOpenHelper.java:197)
at net.sqlcipher.database.SQLiteOpenHelper.getReadableDatabase(SQLiteOpenHelper.java:184)
at devreach.co.uk.devreach.DBModel.queryAllFromUser(DBModel.java:175)
at devreach.co.uk.devreach.DBModel.checkIfUserInDB(DBModel.java:262)
at devreach.co.uk.devreach.LoginActivity.onCreate(LoginActivity.java:62)
at android.app.Activity.performCreate(Activity.java:5958)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1129)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2364)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2474)
at android.app.ActivityThread.access$800(ActivityThread.java:144)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1359)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:155)
at android.app.ActivityThread.main(ActivityThread.java:5696)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1028)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:823)
07-25 13:45:43.643 10654-10654/? E/SQLiteOpenHelper﹕ Couldn't open devreach.db for writing (will try read-only):
net.sqlcipher.database.SQLiteException: file is encrypted or is not a database
at net.sqlcipher.database.SQLiteDatabase.native_setLocale(Native Method)
at net.sqlcipher.database.SQLiteDatabase.setLocale(SQLiteDatabase.java:2096)
at net.sqlcipher.database.SQLiteDatabase.<init>(SQLiteDatabase.java:1962)
at net.sqlcipher.database.SQLiteDatabase.openDatabase(SQLiteDatabase.java:881)
at net.sqlcipher.database.SQLiteDatabase.openOrCreateDatabase(SQLiteDatabase.java:913)
at net.sqlcipher.database.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:132)
at net.sqlcipher.database.SQLiteOpenHelper.getReadableDatabase(SQLiteOpenHelper.java:197)
at net.sqlcipher.database.SQLiteOpenHelper.getReadableDatabase(SQLiteOpenHelper.java:184)
at devreach.co.uk.devreach.DBModel.queryAllFromUser(DBModel.java:175)
at devreach.co.uk.devreach.DBModel.checkIfUserInDB(DBModel.java:262)
at devreach.co.uk.devreach.LoginActivity.onCreate(LoginActivity.java:62)
at android.app.Activity.performCreate(Activity.java:5958)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1129)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2364)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2474)
at android.app.ActivityThread.access$800(ActivityThread.java:144)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1359)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:155)
at android.app.ActivityThread.main(ActivityThread.java:5696)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1028)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:823)
07-25 13:45:43.983 10654-10654/? E/Database﹕ CREATE TABLE android_metadata failed
07-25 13:45:43.983 10654-10654/? E/Database﹕ Failed to setLocale() when constructing, closing the database
net.sqlcipher.database.SQLiteException: file is encrypted or is not a database
at net.sqlcipher.database.SQLiteDatabase.native_setLocale(Native Method)
at net.sqlcipher.database.SQLiteDatabase.setLocale(SQLiteDatabase.java:2096)
at net.sqlcipher.database.SQLiteDatabase.<init>(SQLiteDatabase.java:1962)
at net.sqlcipher.database.SQLiteDatabase.openDatabase(SQLiteDatabase.java:881)
at net.sqlcipher.database.SQLiteDatabase.openDatabase(SQLiteDatabase.java:940)
at net.sqlcipher.database.SQLiteOpenHelper.getReadableDatabase(SQLiteOpenHelper.java:219)
at net.sqlcipher.database.SQLiteOpenHelper.getReadableDatabase(SQLiteOpenHelper.java:184)
at devreach.co.uk.devreach.DBModel.queryAllFromUser(DBModel.java:175)
at devreach.co.uk.devreach.DBModel.checkIfUserInDB(DBModel.java:262)
at devreach.co.uk.devreach.LoginActivity.onCreate(LoginActivity.java:62)
at android.app.Activity.performCreate(Activity.java:5958)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1129)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2364)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2474)
at android.app.ActivityThread.access$800(ActivityThread.java:144)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1359)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:155)
at android.app.ActivityThread.main(ActivityThread.java:5696)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1028)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:823)
07-25 13:45:43.983 10654-10654/? E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: devreach.co.uk.devreach, PID: 10654
java.lang.RuntimeException: Unable to start activity ComponentInfo{devreach.co.uk.devreach/devreach.co.uk.devreach.LoginActivity}: net.sqlcipher.database.SQLiteException: file is encrypted or is not a database
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2411)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2474)
at android.app.ActivityThread.access$800(ActivityThread.java:144)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1359)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:155)
at android.app.ActivityThread.main(ActivityThread.java:5696)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1028)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:823)
Caused by: net.sqlcipher.database.SQLiteException: file is encrypted or is not a database
at net.sqlcipher.database.SQLiteDatabase.native_setLocale(Native Method)
at net.sqlcipher.database.SQLiteDatabase.setLocale(SQLiteDatabase.java:2096)
at net.sqlcipher.database.SQLiteDatabase.<init>(SQLiteDatabase.java:1962)
at net.sqlcipher.database.SQLiteDatabase.openDatabase(SQLiteDatabase.java:881)
at net.sqlcipher.database.SQLiteDatabase.openDatabase(SQLiteDatabase.java:940)
at net.sqlcipher.database.SQLiteOpenHelper.getReadableDatabase(SQLiteOpenHelper.java:219)
at net.sqlcipher.database.SQLiteOpenHelper.getReadableDatabase(SQLiteOpenHelper.java:184)
at devreach.co.uk.devreach.DBModel.queryAllFromUser(DBModel.java:175)
at devreach.co.uk.devreach.DBModel.checkIfUserInDB(DBModel.java:262)
at devreach.co.uk.devreach.LoginActivity.onCreate(LoginActivity.java:62)
at android.app.Activity.performCreate(Activity.java:5958)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1129)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2364)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2474)
at android.app.ActivityThread.access$800(ActivityThread.java:144)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1359)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:155)
at android.app.ActivityThread.main(ActivityThread.java:5696)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1028)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:823)
LoginActivity:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
appObj = (AppObj)getApplication();
editTextFirstName = (EditText)findViewById(R.id.edittextfirstname);
editTextPassword = (EditText)findViewById(R.id.editTextpassword);
String firstName = appObj.dbModel.checkIfUserInDB();
if(! firstName.equalsIgnoreCase("NO_USER")){
editTextFirstName.setText(firstName);
}
DBModel:
import net.sqlcipher.Cursor;
import net.sqlcipher.database.SQLiteDatabase;
import net.sqlcipher.database.SQLiteOpenHelper;
import android.content.ContentValues;
import android.content.Context;
import android.provider.BaseColumns;
import android.util.Log;
import android.widget.Toast;
public class DBModel {
private static final String TAG = DBModel.class.getSimpleName();
// table user column names
public static final String C_USER_ID_INDEX = BaseColumns._ID;
public static final String C_USER_ID = "userid";
public static final String C_USER_COMP_ID = "usercompid";
public static final String C_USER_FIRSTNAME = "userfirstname";
public static final String C_USER_LASTNAME = "userlastname";
public static final String C_USER_PASSWORD = "userpassword";
public static final String C_USER_DATE_TIME = "userdatetime";
// table company column names
public static final String C_COMPANY_ID_INDEX = BaseColumns._ID;
public static final String C_COMPANY_ID = "companyid";
public static final String C_COMPANY_NAME = "companyname";
public static final String C_COMPANY_URL = "companyurl";
public static final String C_COMPANY_GUID = "companyguid";
Context context;
DBHelper dbhelper;
AppObj appObj;
public DBModel(Context context) {
this.context = context;
dbhelper = new DBHelper();
appObj = (AppObj) context.getApplicationContext();
}
/**
* inner class to create/open/upgrade database
*
* @author matt
*
*/
private class DBHelper extends SQLiteOpenHelper {
// database name and version number
public static final String DB_NAME = "devreach.db";
public static final int DB_VERSION = 1;
// table names
public static final String TABLEUSER = "user";
public static final String TABLECOMPANY = "company";
public DBHelper() {
super(context, DB_NAME, null, DB_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
Log.e(TAG, "SQLiteOpenHelper oncreate ");
String sqlToCreateUserTable = String
.format("create table %s (%s INTEGER primary key, %s TEXT, %s TEXT, %s TEXT, %s TEXT, %s TEXT, %s TEXT)",
TABLEUSER, C_USER_ID_INDEX, C_USER_ID, C_USER_COMP_ID,
C_USER_FIRSTNAME, C_USER_LASTNAME, C_USER_PASSWORD,
C_USER_DATE_TIME);
db.execSQL(sqlToCreateUserTable);
Log.e(TAG, "oncreate " + sqlToCreateUserTable);
String sqlToCreateCompanyTable = String
.format("create table %s (%s INTEGER primary key, %s TEXT, %s TEXT, %s TEXT, %s TEXT)",
TABLECOMPANY, C_COMPANY_ID_INDEX, C_COMPANY_ID, C_COMPANY_NAME,
C_COMPANY_URL, C_COMPANY_GUID);
db.execSQL(sqlToCreateCompanyTable);
Log.e(TAG, "oncreate " + sqlToCreateCompanyTable);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}//end of onUpgrade
}//end of DBHelper
public void close() {
dbhelper.close();
}
public void deleteTableUser() {
// open database
SQLiteDatabase db = dbhelper.getWritableDatabase(AppObj.getSecretKey().toString());
// delete contents of table
db.delete(DBHelper.TABLEUSER, null, null);
}
public void insertIntoUser(ContentValues cv) {
SQLiteDatabase db = dbhelper.getWritableDatabase(AppObj.getSecretKey().toString());
db.insertWithOnConflict(DBHelper.TABLEUSER, null, cv, SQLiteDatabase.CONFLICT_REPLACE);
}
public Cursor queryAllFromUser() {
// open database
SQLiteDatabase db = dbhelper.getReadableDatabase(AppObj.getSecretKey().toString());
return db.query(DBHelper.TABLEUSER, null, null, null, null, null, null);
}
public void deleteTableCompany() {
// open database
SQLiteDatabase db = dbhelper.getWritableDatabase(AppObj.getSecretKey().toString());
// delete contents of table
db.delete(DBHelper.TABLECOMPANY, null, null);
}
public void insertIntoCompany(ContentValues cv) {
SQLiteDatabase db = dbhelper.getWritableDatabase(AppObj.getSecretKey().toString());
db.insertWithOnConflict(DBHelper.TABLECOMPANY, null, cv, SQLiteDatabase.CONFLICT_REPLACE);
}
public Cursor queryAllFromCompany() {
// open database
SQLiteDatabase db = dbhelper.getReadableDatabase(AppObj.getSecretKey().toString());
return db.query(DBHelper.TABLECOMPANY, null, null, null, null, null, null);
}
public String getCompanyGuid(){
String guid = null;
Cursor c = null;
SQLiteDatabase db = dbhelper.getReadableDatabase(AppObj.getSecretKey().toString());
c = db.query(DBHelper.TABLECOMPANY, null, null, null, null, null, null);
if(c != null){
if(c.moveToLast()){
guid = c.getString(c.getColumnIndex(DBModel.C_COMPANY_GUID));
}
}
try{
c.close();
}catch(Exception e){}
return guid;
}
public String getCompanyID(){
String id = null;
Cursor c = null;
SQLiteDatabase db = dbhelper.getReadableDatabase(AppObj.getSecretKey().toString());
c = db.query(DBHelper.TABLECOMPANY, null, null, null, null, null, null);
if(c != null){
if(c.moveToLast()){
id = c.getString(c.getColumnIndex(DBModel.C_COMPANY_ID));
}
}
try{
c.close();
}catch(Exception e){}
return id;
}
public String checkIfUserInDB() {
String firstName = null;
Cursor c = queryAllFromUser();
if(c != null && c.getCount() > 0){
if(c.moveToLast()){
Log.e(TAG,"c != null and > 0");
firstName = c.getString(c.getColumnIndex(DBModel.C_USER_FIRSTNAME));
}
}else{
Log.e(TAG,"c == null");
firstName = "NO_USER";
}
try{
c.close();
}catch(Exception e){}
Log.e(TAG,"firstName = " + firstName);
return firstName;
}
}//end of DBModel
[EDIT2]
@Override
public void onCreate() {
super.onCreate();
secretKey = null;
Log.e(TAG, "Build.SERIAL = " + Build.SERIAL);
SecureRandom secureRandom = new SecureRandom();
byte[] salt = secureRandom.generateSeed(256);
try {
secretKey = generateKey(Build.SERIAL.toCharArray(), salt);
Log.e(TAG, "key-Base64 before in appObj = "+new String(Base64.encode(RROnCallApplication.getSecretKey().getEncoded(),0)));
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvalidKeySpecException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Log.e(TAG, "secretKey = " + secretKey);
SQLiteDatabase.loadLibs(this);
dbModel = new DBModel(this);
webService = new WebService(this);
alertCount = 0;
// Cursor checkCarerTable = dbModel.queryAllFromCarer();
//
// if(checkCarerTable.getCount() == 0){
//
// //runGetCarersService();
// //runGetClientsService();
//
//
// }else{
//
// Log.e(TAG, "carer and client table is populated with some data");
// }
}
private static SecretKey generateKey(char[] passphraseOrPin, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException {
// Number of PBKDF2 hardening rounds to use. Larger values increase
// computation time. You should select a value that causes computation
// to take >100ms.
final int iterations = 1000;
// Generate a 256-bit key
final int outputKeyLength = 256;
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec keySpec = new PBEKeySpec(passphraseOrPin, salt, iterations, outputKeyLength);
SecretKey secretKey = secretKeyFactory.generateSecret(keySpec);
return secretKey;
}
"Penso di aver bisogno di modificare questo codice in modo che restituisca un oggetto DB se ne esiste già uno e ne crea uno se non esiste." - 'SQLiteOpenHelper' lo fa già.Dove e come stai creando l'istanza di 'SQLiteOpenHelper', dove e come stai chiamando' getReadableDatabase() 'o' getWriteableDatabase() 'su di esso che sta attivando questo crash? – CommonsWare
@CommonsWare Ho aggiunto più informazioni che posso in EDIT 1. Grazie – turtleboy
@CommonsWare Ho pensato che potrei aggiungere, creo la chiave per il DB nel metodo onCreate dell'oggetto dell'applicazione passando il Build.SERIAL a un metodo che genera la chiave con un sale casuale. Sto solo verificando che dopo un crash l'onCreate dell'oggetto dell'applicazione non venga eseguito nuovamente e generi una chiave diversa? solo un pensiero. – turtleboy