diff options
6 files changed, 69 insertions, 12 deletions
diff --git a/legacy/src/com/android/providers/media/LegacyMediaProvider.java b/legacy/src/com/android/providers/media/LegacyMediaProvider.java index 488e72a8e..086f88c52 100644 --- a/legacy/src/com/android/providers/media/LegacyMediaProvider.java +++ b/legacy/src/com/android/providers/media/LegacyMediaProvider.java @@ -73,9 +73,9 @@ public class LegacyMediaProvider extends ContentProvider { Logging.initPersistent(persistentDir); mInternalDatabase = new DatabaseHelper(context, INTERNAL_DATABASE_NAME, - true, false, true, null, null, null, null); + true, false, true, null, null, null, null, null); mExternalDatabase = new DatabaseHelper(context, EXTERNAL_DATABASE_NAME, - false, false, true, null, null, null, null); + false, false, true, null, null, null, null, null); return true; } diff --git a/src/com/android/providers/media/DatabaseHelper.java b/src/com/android/providers/media/DatabaseHelper.java index 20b64237b..5ad5340a9 100644 --- a/src/com/android/providers/media/DatabaseHelper.java +++ b/src/com/android/providers/media/DatabaseHelper.java @@ -75,6 +75,7 @@ import java.util.Objects; import java.util.Set; import java.util.UUID; import java.util.function.LongSupplier; +import java.util.function.UnaryOperator; import java.util.regex.Matcher; /** @@ -104,6 +105,7 @@ public class DatabaseHelper extends SQLiteOpenHelper implements AutoCloseable { final @Nullable OnSchemaChangeListener mSchemaListener; final @Nullable OnFilesChangeListener mFilesListener; final @Nullable OnLegacyMigrationListener mMigrationListener; + final @Nullable UnaryOperator<String> mIdGenerator; final Set<String> mFilterVolumeNames = new ArraySet<>(); long mScanStartTime; long mScanStopTime; @@ -135,9 +137,10 @@ public class DatabaseHelper extends SQLiteOpenHelper implements AutoCloseable { @Nullable Class<? extends Annotation> columnAnnotation, @Nullable OnSchemaChangeListener schemaListener, @Nullable OnFilesChangeListener filesListener, - @Nullable OnLegacyMigrationListener migrationListener) { + @Nullable OnLegacyMigrationListener migrationListener, + @Nullable UnaryOperator<String> idGenerator) { this(context, name, getDatabaseVersion(context), internal, earlyUpgrade, legacyProvider, - columnAnnotation, schemaListener, filesListener, migrationListener); + columnAnnotation, schemaListener, filesListener, migrationListener, idGenerator); } public DatabaseHelper(Context context, String name, int version, @@ -145,7 +148,8 @@ public class DatabaseHelper extends SQLiteOpenHelper implements AutoCloseable { @Nullable Class<? extends Annotation> columnAnnotation, @Nullable OnSchemaChangeListener schemaListener, @Nullable OnFilesChangeListener filesListener, - @Nullable OnLegacyMigrationListener migrationListener) { + @Nullable OnLegacyMigrationListener migrationListener, + @Nullable UnaryOperator<String> idGenerator) { super(context, name, null, version); mContext = context; mName = name; @@ -158,6 +162,7 @@ public class DatabaseHelper extends SQLiteOpenHelper implements AutoCloseable { mSchemaListener = schemaListener; mFilesListener = filesListener; mMigrationListener = migrationListener; + mIdGenerator = idGenerator; // Configure default filters until we hear differently if (mInternal) { @@ -270,6 +275,17 @@ public class DatabaseHelper extends SQLiteOpenHelper implements AutoCloseable { } return null; }); + db.setCustomScalarFunction("_GET_ID", (arg) -> { + if (mIdGenerator != null && !mSchemaChanging) { + Trace.beginSection("_GET_ID"); + try { + return mIdGenerator.apply(arg); + } finally { + Trace.endSection(); + } + } + return null; + }); } @Override diff --git a/src/com/android/providers/media/MediaProvider.java b/src/com/android/providers/media/MediaProvider.java index 9259e9430..f4cbe9775 100644 --- a/src/com/android/providers/media/MediaProvider.java +++ b/src/com/android/providers/media/MediaProvider.java @@ -208,6 +208,7 @@ import java.util.Optional; import java.util.Set; import java.util.function.Consumer; import java.util.function.Supplier; +import java.util.function.UnaryOperator; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -584,6 +585,14 @@ public class MediaProvider extends ContentProvider { } }; + private final UnaryOperator<String> mIdGenerator = path -> { + final long rowId = mCallingIdentity.get().getDeletedRowId(path); + if (rowId != -1 && isFuseThread()) { + return String.valueOf(rowId); + } + return null; + }; + private final OnLegacyMigrationListener mMigrationListener = new OnLegacyMigrationListener() { @Override public void onStarted(ContentProviderClient client, String volumeName) { @@ -787,10 +796,10 @@ public class MediaProvider extends ContentProvider { mInternalDatabase = new DatabaseHelper(context, INTERNAL_DATABASE_NAME, true, false, mLegacyProvider, Column.class, - Metrics::logSchemaChange, mFilesListener, mMigrationListener); + Metrics::logSchemaChange, mFilesListener, mMigrationListener, mIdGenerator); mExternalDatabase = new DatabaseHelper(context, EXTERNAL_DATABASE_NAME, false, false, mLegacyProvider, Column.class, - Metrics::logSchemaChange, mFilesListener, mMigrationListener); + Metrics::logSchemaChange, mFilesListener, mMigrationListener, mIdGenerator); final IntentFilter packageFilter = new IntentFilter(); packageFilter.setPriority(10); diff --git a/src/com/android/providers/media/MediaUpgradeReceiver.java b/src/com/android/providers/media/MediaUpgradeReceiver.java index dd99fc48d..932b20b31 100644 --- a/src/com/android/providers/media/MediaUpgradeReceiver.java +++ b/src/com/android/providers/media/MediaUpgradeReceiver.java @@ -69,7 +69,8 @@ public class MediaUpgradeReceiver extends BroadcastReceiver { try { DatabaseHelper helper = new DatabaseHelper( context, file, MediaProvider.isInternalMediaDatabaseName(file), - false, false, Column.class, Metrics::logSchemaChange, null, null); + false, false, Column.class, Metrics::logSchemaChange, null, null, + null); db = helper.getWritableDatabase(); } catch (Throwable t) { Log.wtf(TAG, "Error during upgrade of media db " + file, t); diff --git a/src/com/android/providers/media/util/SQLiteQueryBuilder.java b/src/com/android/providers/media/util/SQLiteQueryBuilder.java index 990457c24..da279aa18 100644 --- a/src/com/android/providers/media/util/SQLiteQueryBuilder.java +++ b/src/com/android/providers/media/util/SQLiteQueryBuilder.java @@ -74,6 +74,18 @@ public class SQLiteQueryBuilder { private int mStrictFlags; + /** + * Raw SQL clause to obtain the value of {@link MediaColumns#_ID} from custom database function + * {@code _GET_ID} for INSERT operation. + */ + private static final String GET_ID_FOR_INSERT_CLAUSE = "_GET_ID('%s')"; + + /** + * Raw SQL clause to obtain the value of {@link MediaColumns#_ID} from custom database function + * {@code _GET_ID} for UPDATE operation. + */ + private static final String GET_ID_FOR_UPDATE_CLAUSE = "ifnull(_GET_ID('%s'), _id)"; + public SQLiteQueryBuilder() { mDistinct = false; } @@ -838,6 +850,11 @@ public class SQLiteQueryBuilder { sql.append(','); sql.append(MediaColumns.GENERATION_MODIFIED); } + if (shouldAppendRowId(values)) { + sql.append(','); + sql.append(MediaColumns._ID); + } + sql.append(") VALUES ("); for (int i = 0; i < rawValues.size(); i++) { if (i > 0) { @@ -855,6 +872,10 @@ public class SQLiteQueryBuilder { sql.append(DatabaseHelper.CURRENT_GENERATION_CLAUSE); sql.append(')'); } + if (shouldAppendRowId(values)) { + sql.append(','); + sql.append(String.format(GET_ID_FOR_INSERT_CLAUSE, values.get(MediaColumns.DATA))); + } sql.append(")"); return sql.toString(); } @@ -893,6 +914,12 @@ public class SQLiteQueryBuilder { sql.append(DatabaseHelper.CURRENT_GENERATION_CLAUSE); sql.append(')'); } + if (shouldAppendRowId(values)) { + sql.append(','); + sql.append(MediaColumns._ID); + sql.append('='); + sql.append(String.format(GET_ID_FOR_UPDATE_CLAUSE, values.get(MediaColumns.DATA))); + } final String where = computeWhere(selection); appendClause(sql, " WHERE ", where); @@ -1044,4 +1071,8 @@ public class SQLiteQueryBuilder { return "(" + arg + ")"; } } + + private static boolean shouldAppendRowId(ContentValues values) { + return !values.containsKey(MediaColumns._ID) && values.containsKey(MediaColumns.DATA); + } } diff --git a/tests/src/com/android/providers/media/DatabaseHelperTest.java b/tests/src/com/android/providers/media/DatabaseHelperTest.java index badff085e..114985440 100644 --- a/tests/src/com/android/providers/media/DatabaseHelperTest.java +++ b/tests/src/com/android/providers/media/DatabaseHelperTest.java @@ -426,7 +426,7 @@ public class DatabaseHelperTest { private static class DatabaseHelperO extends DatabaseHelper { public DatabaseHelperO(Context context, String name) { super(context, name, DatabaseHelper.VERSION_O, - false, false, true, Column.class, null, null, null); + false, false, true, Column.class, null, null, null, null); } @Override @@ -443,7 +443,7 @@ public class DatabaseHelperTest { private static class DatabaseHelperP extends DatabaseHelper { public DatabaseHelperP(Context context, String name) { super(context, name, DatabaseHelper.VERSION_P, - false, false, true, Column.class, null, null, null); + false, false, true, Column.class, null, null, null, null); } @Override @@ -460,7 +460,7 @@ public class DatabaseHelperTest { private static class DatabaseHelperQ extends DatabaseHelper { public DatabaseHelperQ(Context context, String name) { super(context, name, DatabaseHelper.VERSION_Q, - false, false, true, Column.class, null, null, null); + false, false, true, Column.class, null, null, null, null); } @Override @@ -477,7 +477,7 @@ public class DatabaseHelperTest { private static class DatabaseHelperR extends DatabaseHelper { public DatabaseHelperR(Context context, String name) { super(context, name, DatabaseHelper.VERSION_R, - false, false, true, Column.class, null, null, null); + false, false, true, Column.class, null, null, null, null); } } |