Loading core/java/android/database/sqlite/SQLiteOpenHelper.java +85 −55 Original line number Diff line number Diff line Loading @@ -25,10 +25,15 @@ import android.database.DatabaseErrorHandler; import android.database.SQLException; import android.database.sqlite.SQLiteDatabase.CursorFactory; import android.os.FileUtils; import android.util.ArrayMap; import android.util.Log; import com.android.internal.annotations.GuardedBy; import java.io.File; import java.io.IOException; import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; /** * A helper class to manage database creation and version management. Loading @@ -54,6 +59,13 @@ import java.util.Objects; public abstract class SQLiteOpenHelper implements AutoCloseable { private static final String TAG = SQLiteOpenHelper.class.getSimpleName(); // Every database file has a lock, saved in this map. The lock is held while the database is // opened. private static final ConcurrentHashMap<String, Object> sDbLock = new ConcurrentHashMap<>(); // The lock that this open helper instance must hold when the database is opened. private final Object mLock; private final Context mContext; @UnsupportedAppUsage private final String mName; Loading Loading @@ -168,6 +180,21 @@ public abstract class SQLiteOpenHelper implements AutoCloseable { mNewVersion = version; mMinimumSupportedVersion = Math.max(0, minimumSupportedVersion); setOpenParamsBuilder(openParamsBuilder); Object lock = null; if (mName == null || !Flags.concurrentOpenHelper()) { lock = new Object(); } else { try { final String path = mContext.getDatabasePath(mName).getCanonicalPath(); lock = sDbLock.computeIfAbsent(path, (String k) -> new Object()); } catch (IOException e) { Log.d(TAG, "failed to construct db path for " + mName); // Ensure the lock is not null. lock = new Object(); } } mLock = lock; } /** Loading Loading @@ -358,6 +385,7 @@ public abstract class SQLiteOpenHelper implements AutoCloseable { SQLiteDatabase db = mDatabase; try { synchronized (mLock) { mIsInitializing = true; if (db != null) { Loading @@ -378,7 +406,8 @@ public abstract class SQLiteOpenHelper implements AutoCloseable { throw ex; } Log.e(TAG, "Couldn't open database for writing (will try read-only):", ex); params = params.toBuilder().addOpenFlags(SQLiteDatabase.OPEN_READONLY).build(); params = params.toBuilder() .addOpenFlags(SQLiteDatabase.OPEN_READONLY).build(); db = SQLiteDatabase.openDatabase(filePath, params); } } Loading @@ -388,8 +417,8 @@ public abstract class SQLiteOpenHelper implements AutoCloseable { final int version = db.getVersion(); if (version != mNewVersion) { if (db.isReadOnly()) { throw new SQLiteException("Can't upgrade read-only database from version " + db.getVersion() + " to " + mNewVersion + ": " + mName); throw new SQLiteException("Can't upgrade read-only database from version " + db.getVersion() + " to " + mNewVersion + ": " + mName); } if (version > 0 && version < mMinimumSupportedVersion) { Loading Loading @@ -426,6 +455,7 @@ public abstract class SQLiteOpenHelper implements AutoCloseable { onOpen(db); mDatabase = db; return db; } } finally { mIsInitializing = false; if (db != null && db != mDatabase) { Loading core/java/android/database/sqlite/flags.aconfig +9 −0 Original line number Diff line number Diff line Loading @@ -17,3 +17,12 @@ flag { description: "SQLite APIs held back for Android 15" bug: "279043253" } flag { name: "concurrent_open_helper" is_exported: true namespace: "system_performance" is_fixed_read_only: false description: "Make SQLiteOpenHelper thread-safe" bug: "335904370" } Loading
core/java/android/database/sqlite/SQLiteOpenHelper.java +85 −55 Original line number Diff line number Diff line Loading @@ -25,10 +25,15 @@ import android.database.DatabaseErrorHandler; import android.database.SQLException; import android.database.sqlite.SQLiteDatabase.CursorFactory; import android.os.FileUtils; import android.util.ArrayMap; import android.util.Log; import com.android.internal.annotations.GuardedBy; import java.io.File; import java.io.IOException; import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; /** * A helper class to manage database creation and version management. Loading @@ -54,6 +59,13 @@ import java.util.Objects; public abstract class SQLiteOpenHelper implements AutoCloseable { private static final String TAG = SQLiteOpenHelper.class.getSimpleName(); // Every database file has a lock, saved in this map. The lock is held while the database is // opened. private static final ConcurrentHashMap<String, Object> sDbLock = new ConcurrentHashMap<>(); // The lock that this open helper instance must hold when the database is opened. private final Object mLock; private final Context mContext; @UnsupportedAppUsage private final String mName; Loading Loading @@ -168,6 +180,21 @@ public abstract class SQLiteOpenHelper implements AutoCloseable { mNewVersion = version; mMinimumSupportedVersion = Math.max(0, minimumSupportedVersion); setOpenParamsBuilder(openParamsBuilder); Object lock = null; if (mName == null || !Flags.concurrentOpenHelper()) { lock = new Object(); } else { try { final String path = mContext.getDatabasePath(mName).getCanonicalPath(); lock = sDbLock.computeIfAbsent(path, (String k) -> new Object()); } catch (IOException e) { Log.d(TAG, "failed to construct db path for " + mName); // Ensure the lock is not null. lock = new Object(); } } mLock = lock; } /** Loading Loading @@ -358,6 +385,7 @@ public abstract class SQLiteOpenHelper implements AutoCloseable { SQLiteDatabase db = mDatabase; try { synchronized (mLock) { mIsInitializing = true; if (db != null) { Loading @@ -378,7 +406,8 @@ public abstract class SQLiteOpenHelper implements AutoCloseable { throw ex; } Log.e(TAG, "Couldn't open database for writing (will try read-only):", ex); params = params.toBuilder().addOpenFlags(SQLiteDatabase.OPEN_READONLY).build(); params = params.toBuilder() .addOpenFlags(SQLiteDatabase.OPEN_READONLY).build(); db = SQLiteDatabase.openDatabase(filePath, params); } } Loading @@ -388,8 +417,8 @@ public abstract class SQLiteOpenHelper implements AutoCloseable { final int version = db.getVersion(); if (version != mNewVersion) { if (db.isReadOnly()) { throw new SQLiteException("Can't upgrade read-only database from version " + db.getVersion() + " to " + mNewVersion + ": " + mName); throw new SQLiteException("Can't upgrade read-only database from version " + db.getVersion() + " to " + mNewVersion + ": " + mName); } if (version > 0 && version < mMinimumSupportedVersion) { Loading Loading @@ -426,6 +455,7 @@ public abstract class SQLiteOpenHelper implements AutoCloseable { onOpen(db); mDatabase = db; return db; } } finally { mIsInitializing = false; if (db != null && db != mDatabase) { Loading
core/java/android/database/sqlite/flags.aconfig +9 −0 Original line number Diff line number Diff line Loading @@ -17,3 +17,12 @@ flag { description: "SQLite APIs held back for Android 15" bug: "279043253" } flag { name: "concurrent_open_helper" is_exported: true namespace: "system_performance" is_fixed_read_only: false description: "Make SQLiteOpenHelper thread-safe" bug: "335904370" }