Ich habe die folgende SqlCipher DB. Es funktioniert gut, wenn ich die App zum ersten Mal installiere, aber wenn ich schließe, entferne die App aus dem letzten Verlauf (aus dem Stapel) und öffne die App erneut, die mit dem folgenden Fehler abstürzt. Die db wird nicht geöffnet, sobald eine Exception auftritt, zum Beispiel setze ich eine 1/0 in eine Activity, um sie zum Absturz zu bringen und das selbe passiert darunter.CREATE TABLE android_metadata fehlgeschlagen beim erneuten Öffnen von 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
.
Ich habe den folgenden Link gefunden, der das Problem zu beheben scheint (ich bin mir nicht sicher, ob es die Lösung ist), aber ich bin mir nicht sicher, wie ich es in meinen Code implementieren soll. Könnte jemand bitte helfen oder mir sagen, warum ich diesen Fehler bekomme?
http://rootslash.net/88542/sqlcipher-cant-open-database-after-apprestart
Das ist mein DB-Code ist, verwende ich SqlCipher SQLiteOpenHelper die DB zu erstellen. Ich denke, dass ich diesen Code ändern muss, damit es ein DB-Objekt zurückgibt, wenn eins bereits existiert, und eines erzeugt, wenn es nicht existiert. Ich bin mir nicht sicher wie.
Vielen Dank im Voraus.
[EDIT1] Ich habe eine LoginActivity, die die Anmeldeinformationen des Benutzers überprüft. Wenn sie gültig sind, lädt sie die MenuActivity, in die ich eine 1/0 gesetzt habe, um einen Crash zu erzwingen. Nach dem Absturz, wenn ich die App wieder öffne, stürzt es in der LoginActivity in der Zeile ab, in der es die DB-Benutzertabelle abfragt.
DBModel ist eine Klasse mit den Methoden SqliteOpenHelper und CRUD.
So stürzt es bei checkUserInDB() in der DBModel-Klasse ab, die ihrerseits queryAllFromUser() aufruft.
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
[EDIT 2]
@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;
}
"Ich denke, ich muss diesen Code ändern, so dass es ein DB-Objekt zurückgibt, wenn eines bereits existiert und eines erstellt, wenn es nicht existiert." - 'SQLiteOpenHelper' macht das schon.Wo und wie erstellen Sie Ihre 'SQLiteOpenHelper'-Instanz und wo und wie rufen Sie' getReadableDatabase() 'oder' getWriteableDatabase() 'darauf auf, die diesen Absturz auslösen? – CommonsWare
@CommonsWare Ich habe so viele Informationen wie möglich in EDIT 1 hinzugefügt. Danke – turtleboy
@CommonsWare Ich dachte ich könnte hinzufügen, ich erstelle den Schlüssel zur DB in der onCreate Methode des Anwendungsobjekts, indem ich Build.SERIAL an a Methode, die den Schlüssel mit einem zufälligen Salz erzeugt. Ich überprüfe nur, dass das Anwendungsobjekt onCreate nach einem Absturz nicht erneut ausgeführt wird und einen anderen Schlüssel generiert? nur ein Gedanke. – turtleboy