Loading mobile/android/base/db/FormHistoryProvider.java.in +6 −9 Original line number Diff line number Diff line Loading @@ -152,17 +152,14 @@ public class FormHistoryProvider extends GeckoProvider { if (!values.containsKey(FormHistory.GUID)) { return; } String guid = values.getAsString(FormHistory.GUID); try { if (guid == null) { db.delete(TABLE_DELETED_FORM_HISTORY, WHERE_GUID_IS_NULL, null); return; } String[] args = new String[] { guid }; db.delete(TABLE_DELETED_FORM_HISTORY, WHERE_GUID_IS_VALUE, args); } catch(SQLiteBridgeException ex) { Log.w(getLogTag(), "Error removing entry with GUID " + guid, ex); } } @Override Loading mobile/android/base/db/GeckoProvider.java.in +89 −8 Original line number Diff line number Diff line Loading @@ -10,6 +10,8 @@ import java.io.IOException; import java.lang.IllegalArgumentException; import java.util.HashMap; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.Random; import org.mozilla.gecko.GeckoApp; Loading Loading @@ -59,6 +61,30 @@ public abstract class GeckoProvider extends ContentProvider { private HashMap<String, SQLiteBridge> mDatabasePerProfile; protected Context mContext = null; @Override public void shutdown() { if (mDatabasePerProfile == null) return; Collection<SQLiteBridge> bridges = mDatabasePerProfile.values(); Iterator<SQLiteBridge> it = bridges.iterator(); while (it.hasNext()) { SQLiteBridge bridge = it.next(); if (bridge != null) { try { bridge.close(); } catch (Exception ex) { } } } mDatabasePerProfile = null; } public void finalize() { shutdown(); } protected void setLogTag(String aLogTag) { mLogTag = aLogTag; } Loading Loading @@ -91,11 +117,14 @@ public abstract class GeckoProvider extends ContentProvider { String resourcePath = context.getPackageResourcePath(); GeckoAppShell.loadSQLiteLibs(context, resourcePath); GeckoAppShell.loadNSSLibs(context, resourcePath); bridge = new SQLiteBridge(databasePath); bridge = SQLiteBridge.openDatabase(databasePath, null, 0); int version = bridge.getVersion(); Log.i(mLogTag, version + " == " + mDBVersion); dbNeedsSetup = version != mDBVersion; } catch (SQLiteBridgeException ex) { // close the database if (bridge != null) bridge.close(); // this will throw if the database can't be found // we should attempt to set it up if Gecko is running dbNeedsSetup = true; Loading @@ -117,6 +146,7 @@ public abstract class GeckoProvider extends ContentProvider { bridge = null; initGecko(); } if (bridge != null) mDatabasePerProfile.put(databasePath, bridge); return bridge; Loading Loading @@ -204,6 +234,7 @@ public abstract class GeckoProvider extends ContentProvider { deleted = db.delete(getTable(uri), selection, selectionArgs); } catch (SQLiteBridgeException ex) { Log.e(mLogTag, "Error deleting record", ex); throw ex; } return deleted; Loading @@ -222,17 +253,65 @@ public abstract class GeckoProvider extends ContentProvider { setupDefaults(uri, values); onPreInsert(values, uri, db); boolean useTransaction = !db.inTransaction(); try { if (useTransaction) { db.beginTransaction(); } // onPreInsert does a check for the item in the deleted table in some cases // so we put it inside this transaction onPreInsert(values, uri, db); id = db.insert(getTable(uri), null, values); if (useTransaction) { db.setTransactionSuccessful(); } } catch (SQLiteBridgeException ex) { Log.e(mLogTag, "Error inserting in db", ex); throw ex; } finally { if (useTransaction) { db.endTransaction(); } } return ContentUris.withAppendedId(uri, id); } @Override public int bulkInsert(Uri uri, ContentValues[] allValues) { final SQLiteBridge db = getDatabase(uri); // If we can not get a SQLiteBridge instance, its likely that the database // has not been set up and Gecko is not running. We return 0 and expect // callers to try again later if (db == null) return 0; long id = -1; int rowsAdded = 0; String table = getTable(uri); try { db.beginTransaction(); for (ContentValues initialValues : allValues) { ContentValues values = new ContentValues(initialValues); setupDefaults(uri, values); onPreInsert(values, uri, db); id = db.insert(table, null, values); rowsAdded++; } db.setTransactionSuccessful(); } catch (SQLiteBridgeException ex) { Log.e(mLogTag, "Error inserting in db", ex); throw ex; } finally { db.endTransaction(); } return rowsAdded; } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { Loading @@ -251,6 +330,7 @@ public abstract class GeckoProvider extends ContentProvider { updated = db.update(getTable(uri), values, selection, selectionArgs); } catch (SQLiteBridgeException ex) { Log.e(mLogTag, "Error updating table", ex); throw ex; } return updated; Loading @@ -275,6 +355,7 @@ public abstract class GeckoProvider extends ContentProvider { onPostQuery(cursor, uri, db); } catch (SQLiteBridgeException ex) { Log.e(mLogTag, "Error querying database", ex); throw ex; } return cursor; Loading mobile/android/base/db/PasswordsProvider.java.in +5 −9 Original line number Diff line number Diff line Loading @@ -217,16 +217,12 @@ public class PasswordsProvider extends GeckoProvider { public void onPreInsert(ContentValues values, Uri uri, SQLiteBridge db) { if (values.containsKey(Passwords.GUID)) { String guid = values.getAsString(Passwords.GUID); try { if (guid == null) { db.delete(TABLE_DELETED_PASSWORDS, WHERE_GUID_IS_NULL, null); return; } String[] args = new String[] { guid }; db.delete(TABLE_DELETED_PASSWORDS, WHERE_GUID_IS_VALUE, args); } catch(SQLiteBridgeException ex) { Log.w(getLogTag(), "Error removing entry with GUID " + guid, ex); } } if (values.containsKey(Passwords.ENCRYPTED_PASSWORD)) { Loading mobile/android/base/sqlite/SQLiteBridge.java +101 −4 Original line number Diff line number Diff line Loading @@ -8,14 +8,17 @@ import org.mozilla.gecko.sqlite.SQLiteBridgeException; import org.mozilla.gecko.sqlite.MatrixBlobCursor; import android.content.ContentValues; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteException; import android.database.DatabaseErrorHandler; import android.text.TextUtils; import android.util.Log; import java.lang.String; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import android.util.Log; import java.util.Map.Entry; import java.util.Set; Loading @@ -27,12 +30,17 @@ import java.util.Set; public class SQLiteBridge { private static final String LOGTAG = "SQLiteBridge"; // Path to the database. We reopen it every query. // Path to the database. If this database was not opened with openDatabase, we reopen it every query. private String mDb; // pointer to the database if it was opened with openDatabase protected long mDbPointer = 0; // Values remembered after a query. private long[] mQueryResults; private boolean mTransactionSuccess = false; private boolean mInTransaction = false; private static final int RESULT_INSERT_ROW_ID = 0; private static final int RESULT_ROWS_CHANGED = 1; Loading @@ -41,6 +49,13 @@ public class SQLiteBridge { String[] aParams, long[] aUpdateResult) throws SQLiteBridgeException; private static native MatrixBlobCursor sqliteCallWithDb(long aDb, String aQuery, String[] aParams, long[] aUpdateResult) throws SQLiteBridgeException; private static native long openDatabase(String aDb) throws SQLiteBridgeException; private static native void closeDatabase(long aDb); // Takes the path to the database we want to access. public SQLiteBridge(String aDb) throws SQLiteBridgeException { Loading Loading @@ -204,10 +219,92 @@ public class SQLiteBridge { // are not supported. private Cursor internalQuery(String aQuery, String[] aParams) throws SQLiteBridgeException { mQueryResults = new long[2]; if (isOpen()) { return sqliteCallWithDb(mDbPointer, aQuery, aParams, mQueryResults); } return sqliteCall(mDb, aQuery, aParams, mQueryResults); } // nop, provided for API compatibility with SQLiteDatabase. public void close() { } /* * The second two parameters here are just provided for compatbility with SQLiteDatabase * Support for them is not currently implemented */ public static SQLiteBridge openDatabase(String path, SQLiteDatabase.CursorFactory factory, int flags) throws SQLiteException { SQLiteBridge bridge = null; try { bridge = new SQLiteBridge(path); bridge.mDbPointer = bridge.openDatabase(path); } catch(SQLiteBridgeException ex) { // catch and rethrow as a SQLiteException to match SQLiteDatabase throw new SQLiteException(ex.getMessage()); } return bridge; } public void close() { if (isOpen()) { closeDatabase(mDbPointer); } mDbPointer = 0; } public boolean isOpen() { return mDbPointer > 0; } public void beginTransaction() throws SQLiteBridgeException { if (inTransaction()) { throw new SQLiteBridgeException("Nested transactions are not supported"); } execSQL("BEGIN EXCLUSIVE"); mTransactionSuccess = false; mInTransaction = true; } public void beginTransactionNonExclusive() throws SQLiteBridgeException { if (inTransaction()) { throw new SQLiteBridgeException("Nested transactions are not supported"); } execSQL("BEGIN IMMEDIATE"); mTransactionSuccess = false; mInTransaction = true; } public void endTransaction() { if (!inTransaction()) return; try { if (mTransactionSuccess) { execSQL("COMMIT TRANSACTION"); } else { execSQL("ROLLBACK TRANSACTION"); } } catch(SQLiteBridgeException ex) { Log.e(LOGTAG, "Error ending transaction", ex); } mInTransaction = false; mTransactionSuccess = false; } public void setTransactionSuccessful() throws SQLiteBridgeException { if (!inTransaction()) { throw new SQLiteBridgeException("setTransactionSuccessful called outside a transaction"); } mTransactionSuccess = true; } public boolean inTransaction() { return mInTransaction; } public void finalize() { if (isOpen()) { Log.e(LOGTAG, "Bridge finalized without closing the database"); close(); } } } mobile/android/base/sqlite/SQLiteBridgeException.java +2 −2 Original line number Diff line number Diff line Loading @@ -37,7 +37,7 @@ package org.mozilla.gecko.sqlite; public class SQLiteBridgeException extends Exception { public class SQLiteBridgeException extends RuntimeException { static final long serialVersionUID = 1L; public SQLiteBridgeException() {} Loading Loading
mobile/android/base/db/FormHistoryProvider.java.in +6 −9 Original line number Diff line number Diff line Loading @@ -152,17 +152,14 @@ public class FormHistoryProvider extends GeckoProvider { if (!values.containsKey(FormHistory.GUID)) { return; } String guid = values.getAsString(FormHistory.GUID); try { if (guid == null) { db.delete(TABLE_DELETED_FORM_HISTORY, WHERE_GUID_IS_NULL, null); return; } String[] args = new String[] { guid }; db.delete(TABLE_DELETED_FORM_HISTORY, WHERE_GUID_IS_VALUE, args); } catch(SQLiteBridgeException ex) { Log.w(getLogTag(), "Error removing entry with GUID " + guid, ex); } } @Override Loading
mobile/android/base/db/GeckoProvider.java.in +89 −8 Original line number Diff line number Diff line Loading @@ -10,6 +10,8 @@ import java.io.IOException; import java.lang.IllegalArgumentException; import java.util.HashMap; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.Random; import org.mozilla.gecko.GeckoApp; Loading Loading @@ -59,6 +61,30 @@ public abstract class GeckoProvider extends ContentProvider { private HashMap<String, SQLiteBridge> mDatabasePerProfile; protected Context mContext = null; @Override public void shutdown() { if (mDatabasePerProfile == null) return; Collection<SQLiteBridge> bridges = mDatabasePerProfile.values(); Iterator<SQLiteBridge> it = bridges.iterator(); while (it.hasNext()) { SQLiteBridge bridge = it.next(); if (bridge != null) { try { bridge.close(); } catch (Exception ex) { } } } mDatabasePerProfile = null; } public void finalize() { shutdown(); } protected void setLogTag(String aLogTag) { mLogTag = aLogTag; } Loading Loading @@ -91,11 +117,14 @@ public abstract class GeckoProvider extends ContentProvider { String resourcePath = context.getPackageResourcePath(); GeckoAppShell.loadSQLiteLibs(context, resourcePath); GeckoAppShell.loadNSSLibs(context, resourcePath); bridge = new SQLiteBridge(databasePath); bridge = SQLiteBridge.openDatabase(databasePath, null, 0); int version = bridge.getVersion(); Log.i(mLogTag, version + " == " + mDBVersion); dbNeedsSetup = version != mDBVersion; } catch (SQLiteBridgeException ex) { // close the database if (bridge != null) bridge.close(); // this will throw if the database can't be found // we should attempt to set it up if Gecko is running dbNeedsSetup = true; Loading @@ -117,6 +146,7 @@ public abstract class GeckoProvider extends ContentProvider { bridge = null; initGecko(); } if (bridge != null) mDatabasePerProfile.put(databasePath, bridge); return bridge; Loading Loading @@ -204,6 +234,7 @@ public abstract class GeckoProvider extends ContentProvider { deleted = db.delete(getTable(uri), selection, selectionArgs); } catch (SQLiteBridgeException ex) { Log.e(mLogTag, "Error deleting record", ex); throw ex; } return deleted; Loading @@ -222,17 +253,65 @@ public abstract class GeckoProvider extends ContentProvider { setupDefaults(uri, values); onPreInsert(values, uri, db); boolean useTransaction = !db.inTransaction(); try { if (useTransaction) { db.beginTransaction(); } // onPreInsert does a check for the item in the deleted table in some cases // so we put it inside this transaction onPreInsert(values, uri, db); id = db.insert(getTable(uri), null, values); if (useTransaction) { db.setTransactionSuccessful(); } } catch (SQLiteBridgeException ex) { Log.e(mLogTag, "Error inserting in db", ex); throw ex; } finally { if (useTransaction) { db.endTransaction(); } } return ContentUris.withAppendedId(uri, id); } @Override public int bulkInsert(Uri uri, ContentValues[] allValues) { final SQLiteBridge db = getDatabase(uri); // If we can not get a SQLiteBridge instance, its likely that the database // has not been set up and Gecko is not running. We return 0 and expect // callers to try again later if (db == null) return 0; long id = -1; int rowsAdded = 0; String table = getTable(uri); try { db.beginTransaction(); for (ContentValues initialValues : allValues) { ContentValues values = new ContentValues(initialValues); setupDefaults(uri, values); onPreInsert(values, uri, db); id = db.insert(table, null, values); rowsAdded++; } db.setTransactionSuccessful(); } catch (SQLiteBridgeException ex) { Log.e(mLogTag, "Error inserting in db", ex); throw ex; } finally { db.endTransaction(); } return rowsAdded; } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { Loading @@ -251,6 +330,7 @@ public abstract class GeckoProvider extends ContentProvider { updated = db.update(getTable(uri), values, selection, selectionArgs); } catch (SQLiteBridgeException ex) { Log.e(mLogTag, "Error updating table", ex); throw ex; } return updated; Loading @@ -275,6 +355,7 @@ public abstract class GeckoProvider extends ContentProvider { onPostQuery(cursor, uri, db); } catch (SQLiteBridgeException ex) { Log.e(mLogTag, "Error querying database", ex); throw ex; } return cursor; Loading
mobile/android/base/db/PasswordsProvider.java.in +5 −9 Original line number Diff line number Diff line Loading @@ -217,16 +217,12 @@ public class PasswordsProvider extends GeckoProvider { public void onPreInsert(ContentValues values, Uri uri, SQLiteBridge db) { if (values.containsKey(Passwords.GUID)) { String guid = values.getAsString(Passwords.GUID); try { if (guid == null) { db.delete(TABLE_DELETED_PASSWORDS, WHERE_GUID_IS_NULL, null); return; } String[] args = new String[] { guid }; db.delete(TABLE_DELETED_PASSWORDS, WHERE_GUID_IS_VALUE, args); } catch(SQLiteBridgeException ex) { Log.w(getLogTag(), "Error removing entry with GUID " + guid, ex); } } if (values.containsKey(Passwords.ENCRYPTED_PASSWORD)) { Loading
mobile/android/base/sqlite/SQLiteBridge.java +101 −4 Original line number Diff line number Diff line Loading @@ -8,14 +8,17 @@ import org.mozilla.gecko.sqlite.SQLiteBridgeException; import org.mozilla.gecko.sqlite.MatrixBlobCursor; import android.content.ContentValues; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteException; import android.database.DatabaseErrorHandler; import android.text.TextUtils; import android.util.Log; import java.lang.String; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import android.util.Log; import java.util.Map.Entry; import java.util.Set; Loading @@ -27,12 +30,17 @@ import java.util.Set; public class SQLiteBridge { private static final String LOGTAG = "SQLiteBridge"; // Path to the database. We reopen it every query. // Path to the database. If this database was not opened with openDatabase, we reopen it every query. private String mDb; // pointer to the database if it was opened with openDatabase protected long mDbPointer = 0; // Values remembered after a query. private long[] mQueryResults; private boolean mTransactionSuccess = false; private boolean mInTransaction = false; private static final int RESULT_INSERT_ROW_ID = 0; private static final int RESULT_ROWS_CHANGED = 1; Loading @@ -41,6 +49,13 @@ public class SQLiteBridge { String[] aParams, long[] aUpdateResult) throws SQLiteBridgeException; private static native MatrixBlobCursor sqliteCallWithDb(long aDb, String aQuery, String[] aParams, long[] aUpdateResult) throws SQLiteBridgeException; private static native long openDatabase(String aDb) throws SQLiteBridgeException; private static native void closeDatabase(long aDb); // Takes the path to the database we want to access. public SQLiteBridge(String aDb) throws SQLiteBridgeException { Loading Loading @@ -204,10 +219,92 @@ public class SQLiteBridge { // are not supported. private Cursor internalQuery(String aQuery, String[] aParams) throws SQLiteBridgeException { mQueryResults = new long[2]; if (isOpen()) { return sqliteCallWithDb(mDbPointer, aQuery, aParams, mQueryResults); } return sqliteCall(mDb, aQuery, aParams, mQueryResults); } // nop, provided for API compatibility with SQLiteDatabase. public void close() { } /* * The second two parameters here are just provided for compatbility with SQLiteDatabase * Support for them is not currently implemented */ public static SQLiteBridge openDatabase(String path, SQLiteDatabase.CursorFactory factory, int flags) throws SQLiteException { SQLiteBridge bridge = null; try { bridge = new SQLiteBridge(path); bridge.mDbPointer = bridge.openDatabase(path); } catch(SQLiteBridgeException ex) { // catch and rethrow as a SQLiteException to match SQLiteDatabase throw new SQLiteException(ex.getMessage()); } return bridge; } public void close() { if (isOpen()) { closeDatabase(mDbPointer); } mDbPointer = 0; } public boolean isOpen() { return mDbPointer > 0; } public void beginTransaction() throws SQLiteBridgeException { if (inTransaction()) { throw new SQLiteBridgeException("Nested transactions are not supported"); } execSQL("BEGIN EXCLUSIVE"); mTransactionSuccess = false; mInTransaction = true; } public void beginTransactionNonExclusive() throws SQLiteBridgeException { if (inTransaction()) { throw new SQLiteBridgeException("Nested transactions are not supported"); } execSQL("BEGIN IMMEDIATE"); mTransactionSuccess = false; mInTransaction = true; } public void endTransaction() { if (!inTransaction()) return; try { if (mTransactionSuccess) { execSQL("COMMIT TRANSACTION"); } else { execSQL("ROLLBACK TRANSACTION"); } } catch(SQLiteBridgeException ex) { Log.e(LOGTAG, "Error ending transaction", ex); } mInTransaction = false; mTransactionSuccess = false; } public void setTransactionSuccessful() throws SQLiteBridgeException { if (!inTransaction()) { throw new SQLiteBridgeException("setTransactionSuccessful called outside a transaction"); } mTransactionSuccess = true; } public boolean inTransaction() { return mInTransaction; } public void finalize() { if (isOpen()) { Log.e(LOGTAG, "Bridge finalized without closing the database"); close(); } } }
mobile/android/base/sqlite/SQLiteBridgeException.java +2 −2 Original line number Diff line number Diff line Loading @@ -37,7 +37,7 @@ package org.mozilla.gecko.sqlite; public class SQLiteBridgeException extends Exception { public class SQLiteBridgeException extends RuntimeException { static final long serialVersionUID = 1L; public SQLiteBridgeException() {} Loading