discord-jadx/app/src/main/java/androidx/room/RoomDatabase.java

509 lines
20 KiB
Java

package androidx.room;
import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.content.Context;
import android.database.Cursor;
import android.os.CancellationSignal;
import android.os.Looper;
import android.util.Log;
import androidx.annotation.CallSuper;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.annotation.WorkerThread;
import androidx.arch.core.executor.ArchTaskExecutor;
import androidx.room.migration.Migration;
import androidx.room.util.SneakyThrow;
import androidx.sqlite.db.SimpleSQLiteQuery;
import androidx.sqlite.db.SupportSQLiteDatabase;
import androidx.sqlite.db.SupportSQLiteOpenHelper;
import androidx.sqlite.db.SupportSQLiteQuery;
import androidx.sqlite.db.SupportSQLiteStatement;
import androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public abstract class RoomDatabase {
private static final String DB_IMPL_SUFFIX = "_Impl";
@RestrictTo({RestrictTo.Scope.LIBRARY_GROUP_PREFIX})
public static final int MAX_BIND_PARAMETER_CNT = 999;
private boolean mAllowMainThreadQueries;
private final Map<String, Object> mBackingFieldMap = new ConcurrentHashMap();
@Nullable
@Deprecated
public List<Callback> mCallbacks;
private final ReentrantReadWriteLock mCloseLock = new ReentrantReadWriteLock();
@Deprecated
public volatile SupportSQLiteDatabase mDatabase;
private final InvalidationTracker mInvalidationTracker = createInvalidationTracker();
private SupportSQLiteOpenHelper mOpenHelper;
private Executor mQueryExecutor;
private final ThreadLocal<Integer> mSuspendingTransactionId = new ThreadLocal<>();
private Executor mTransactionExecutor;
public boolean mWriteAheadLoggingEnabled;
public static class Builder<T extends RoomDatabase> {
private boolean mAllowDestructiveMigrationOnDowngrade;
private boolean mAllowMainThreadQueries;
private ArrayList<Callback> mCallbacks;
private final Context mContext;
private String mCopyFromAssetPath;
private File mCopyFromFile;
private final Class<T> mDatabaseClass;
private SupportSQLiteOpenHelper.Factory mFactory;
private JournalMode mJournalMode = JournalMode.AUTOMATIC;
private final MigrationContainer mMigrationContainer = new MigrationContainer();
private Set<Integer> mMigrationStartAndEndVersions;
private Set<Integer> mMigrationsNotRequiredFrom;
private boolean mMultiInstanceInvalidation;
private final String mName;
private Executor mQueryExecutor;
private boolean mRequireMigration = true;
private Executor mTransactionExecutor;
public Builder(@NonNull Context context, @NonNull Class<T> cls, @Nullable String str) {
this.mContext = context;
this.mDatabaseClass = cls;
this.mName = str;
}
@NonNull
public Builder<T> addCallback(@NonNull Callback callback) {
if (this.mCallbacks == null) {
this.mCallbacks = new ArrayList<>();
}
this.mCallbacks.add(callback);
return this;
}
@NonNull
public Builder<T> addMigrations(@NonNull Migration... migrationArr) {
if (this.mMigrationStartAndEndVersions == null) {
this.mMigrationStartAndEndVersions = new HashSet();
}
for (Migration migration : migrationArr) {
this.mMigrationStartAndEndVersions.add(Integer.valueOf(migration.startVersion));
this.mMigrationStartAndEndVersions.add(Integer.valueOf(migration.endVersion));
}
this.mMigrationContainer.addMigrations(migrationArr);
return this;
}
@NonNull
public Builder<T> allowMainThreadQueries() {
this.mAllowMainThreadQueries = true;
return this;
}
@NonNull
@SuppressLint({"RestrictedApi"})
public T build() {
Executor executor;
if (this.mContext == null) {
throw new IllegalArgumentException("Cannot provide null context for the database.");
} else if (this.mDatabaseClass != null) {
Executor executor2 = this.mQueryExecutor;
if (executor2 == null && this.mTransactionExecutor == null) {
Executor iOThreadExecutor = ArchTaskExecutor.getIOThreadExecutor();
this.mTransactionExecutor = iOThreadExecutor;
this.mQueryExecutor = iOThreadExecutor;
} else if (executor2 != null && this.mTransactionExecutor == null) {
this.mTransactionExecutor = executor2;
} else if (executor2 == null && (executor = this.mTransactionExecutor) != null) {
this.mQueryExecutor = executor;
}
Set<Integer> set = this.mMigrationStartAndEndVersions;
if (!(set == null || this.mMigrationsNotRequiredFrom == null)) {
for (Integer num : set) {
if (this.mMigrationsNotRequiredFrom.contains(num)) {
throw new IllegalArgumentException("Inconsistency detected. A Migration was supplied to addMigration(Migration... migrations) that has a start or end version equal to a start version supplied to fallbackToDestructiveMigrationFrom(int... startVersions). Start version: " + num);
}
}
}
if (this.mFactory == null) {
this.mFactory = new FrameworkSQLiteOpenHelperFactory();
}
String str = this.mCopyFromAssetPath;
if (!(str == null && this.mCopyFromFile == null)) {
if (this.mName == null) {
throw new IllegalArgumentException("Cannot create from asset or file for an in-memory database.");
} else if (str == null || this.mCopyFromFile == null) {
this.mFactory = new SQLiteCopyOpenHelperFactory(str, this.mCopyFromFile, this.mFactory);
} else {
throw new IllegalArgumentException("Both createFromAsset() and createFromFile() was called on this Builder but the database can only be created using one of the two configurations.");
}
}
Context context = this.mContext;
DatabaseConfiguration databaseConfiguration = new DatabaseConfiguration(context, this.mName, this.mFactory, this.mMigrationContainer, this.mCallbacks, this.mAllowMainThreadQueries, this.mJournalMode.resolve(context), this.mQueryExecutor, this.mTransactionExecutor, this.mMultiInstanceInvalidation, this.mRequireMigration, this.mAllowDestructiveMigrationOnDowngrade, this.mMigrationsNotRequiredFrom, this.mCopyFromAssetPath, this.mCopyFromFile);
T t = (T) ((RoomDatabase) Room.getGeneratedImplementation(this.mDatabaseClass, "_Impl"));
t.init(databaseConfiguration);
return t;
} else {
throw new IllegalArgumentException("Must provide an abstract class that extends RoomDatabase");
}
}
@NonNull
public Builder<T> createFromAsset(@NonNull String str) {
this.mCopyFromAssetPath = str;
return this;
}
@NonNull
public Builder<T> createFromFile(@NonNull File file) {
this.mCopyFromFile = file;
return this;
}
@NonNull
public Builder<T> enableMultiInstanceInvalidation() {
this.mMultiInstanceInvalidation = this.mName != null;
return this;
}
@NonNull
public Builder<T> fallbackToDestructiveMigration() {
this.mRequireMigration = false;
this.mAllowDestructiveMigrationOnDowngrade = true;
return this;
}
@NonNull
public Builder<T> fallbackToDestructiveMigrationFrom(int... iArr) {
if (this.mMigrationsNotRequiredFrom == null) {
this.mMigrationsNotRequiredFrom = new HashSet(iArr.length);
}
for (int i : iArr) {
this.mMigrationsNotRequiredFrom.add(Integer.valueOf(i));
}
return this;
}
@NonNull
public Builder<T> fallbackToDestructiveMigrationOnDowngrade() {
this.mRequireMigration = true;
this.mAllowDestructiveMigrationOnDowngrade = true;
return this;
}
@NonNull
public Builder<T> openHelperFactory(@Nullable SupportSQLiteOpenHelper.Factory factory) {
this.mFactory = factory;
return this;
}
@NonNull
public Builder<T> setJournalMode(@NonNull JournalMode journalMode) {
this.mJournalMode = journalMode;
return this;
}
@NonNull
public Builder<T> setQueryExecutor(@NonNull Executor executor) {
this.mQueryExecutor = executor;
return this;
}
@NonNull
public Builder<T> setTransactionExecutor(@NonNull Executor executor) {
this.mTransactionExecutor = executor;
return this;
}
}
public static abstract class Callback {
public void onCreate(@NonNull SupportSQLiteDatabase supportSQLiteDatabase) {
}
public void onDestructiveMigration(@NonNull SupportSQLiteDatabase supportSQLiteDatabase) {
}
public void onOpen(@NonNull SupportSQLiteDatabase supportSQLiteDatabase) {
}
}
public enum JournalMode {
AUTOMATIC,
TRUNCATE,
WRITE_AHEAD_LOGGING;
private static boolean isLowRamDevice(@NonNull ActivityManager activityManager) {
return activityManager.isLowRamDevice();
}
@SuppressLint({"NewApi"})
public JournalMode resolve(Context context) {
if (this != AUTOMATIC) {
return this;
}
ActivityManager activityManager = (ActivityManager) context.getSystemService("activity");
return (activityManager == null || isLowRamDevice(activityManager)) ? TRUNCATE : WRITE_AHEAD_LOGGING;
}
}
public static class MigrationContainer {
private HashMap<Integer, TreeMap<Integer, Migration>> mMigrations = new HashMap<>();
private void addMigration(Migration migration) {
int i = migration.startVersion;
int i2 = migration.endVersion;
TreeMap<Integer, Migration> treeMap = this.mMigrations.get(Integer.valueOf(i));
if (treeMap == null) {
treeMap = new TreeMap<>();
this.mMigrations.put(Integer.valueOf(i), treeMap);
}
Migration migration2 = treeMap.get(Integer.valueOf(i2));
if (migration2 != null) {
Log.w("ROOM", "Overriding migration " + migration2 + " with " + migration);
}
treeMap.put(Integer.valueOf(i2), migration);
}
private List<Migration> findUpMigrationPath(List<Migration> list, boolean z2, int i, int i2) {
boolean z3;
do {
if (z2) {
if (i >= i2) {
return list;
}
} else if (i <= i2) {
return list;
}
TreeMap<Integer, Migration> treeMap = this.mMigrations.get(Integer.valueOf(i));
if (treeMap != null) {
Iterator<Integer> it = (z2 ? treeMap.descendingKeySet() : treeMap.keySet()).iterator();
while (true) {
z3 = true;
boolean z4 = false;
if (!it.hasNext()) {
z3 = false;
continue;
break;
}
int intValue = it.next().intValue();
if (!z2 ? !(intValue < i2 || intValue >= i) : !(intValue > i2 || intValue <= i)) {
z4 = true;
continue;
}
if (z4) {
list.add(treeMap.get(Integer.valueOf(intValue)));
i = intValue;
continue;
break;
}
}
} else {
return null;
}
} while (z3);
return null;
}
public void addMigrations(@NonNull Migration... migrationArr) {
for (Migration migration : migrationArr) {
addMigration(migration);
}
}
@Nullable
public List<Migration> findMigrationPath(int i, int i2) {
if (i == i2) {
return Collections.emptyList();
}
return findUpMigrationPath(new ArrayList(), i2 > i, i, i2);
}
}
private static boolean isMainThread() {
return Looper.getMainLooper().getThread() == Thread.currentThread();
}
@RestrictTo({RestrictTo.Scope.LIBRARY_GROUP_PREFIX})
public void assertNotMainThread() {
if (!this.mAllowMainThreadQueries && isMainThread()) {
throw new IllegalStateException("Cannot access database on the main thread since it may potentially lock the UI for a long period of time.");
}
}
@RestrictTo({RestrictTo.Scope.LIBRARY_GROUP})
public void assertNotSuspendingTransaction() {
if (!inTransaction() && this.mSuspendingTransactionId.get() != null) {
throw new IllegalStateException("Cannot access database on a different coroutine context inherited from a suspending transaction.");
}
}
@Deprecated
public void beginTransaction() {
assertNotMainThread();
SupportSQLiteDatabase writableDatabase = this.mOpenHelper.getWritableDatabase();
this.mInvalidationTracker.syncTriggers(writableDatabase);
writableDatabase.beginTransaction();
}
@WorkerThread
public abstract void clearAllTables();
public void close() {
if (isOpen()) {
ReentrantReadWriteLock.WriteLock writeLock = this.mCloseLock.writeLock();
try {
writeLock.lock();
this.mInvalidationTracker.stopMultiInstanceInvalidation();
this.mOpenHelper.close();
} finally {
writeLock.unlock();
}
}
}
public SupportSQLiteStatement compileStatement(@NonNull String str) {
assertNotMainThread();
assertNotSuspendingTransaction();
return this.mOpenHelper.getWritableDatabase().compileStatement(str);
}
@NonNull
public abstract InvalidationTracker createInvalidationTracker();
@NonNull
public abstract SupportSQLiteOpenHelper createOpenHelper(DatabaseConfiguration databaseConfiguration);
@Deprecated
public void endTransaction() {
this.mOpenHelper.getWritableDatabase().endTransaction();
if (!inTransaction()) {
this.mInvalidationTracker.refreshVersionsAsync();
}
}
@RestrictTo({RestrictTo.Scope.LIBRARY_GROUP})
public Map<String, Object> getBackingFieldMap() {
return this.mBackingFieldMap;
}
public Lock getCloseLock() {
return this.mCloseLock.readLock();
}
@NonNull
public InvalidationTracker getInvalidationTracker() {
return this.mInvalidationTracker;
}
@NonNull
public SupportSQLiteOpenHelper getOpenHelper() {
return this.mOpenHelper;
}
@NonNull
public Executor getQueryExecutor() {
return this.mQueryExecutor;
}
@RestrictTo({RestrictTo.Scope.LIBRARY_GROUP})
public ThreadLocal<Integer> getSuspendingTransactionId() {
return this.mSuspendingTransactionId;
}
@NonNull
public Executor getTransactionExecutor() {
return this.mTransactionExecutor;
}
public boolean inTransaction() {
return this.mOpenHelper.getWritableDatabase().inTransaction();
}
@CallSuper
public void init(@NonNull DatabaseConfiguration databaseConfiguration) {
SupportSQLiteOpenHelper createOpenHelper = createOpenHelper(databaseConfiguration);
this.mOpenHelper = createOpenHelper;
if (createOpenHelper instanceof SQLiteCopyOpenHelper) {
((SQLiteCopyOpenHelper) createOpenHelper).setDatabaseConfiguration(databaseConfiguration);
}
boolean z2 = databaseConfiguration.journalMode == JournalMode.WRITE_AHEAD_LOGGING;
this.mOpenHelper.setWriteAheadLoggingEnabled(z2);
this.mCallbacks = databaseConfiguration.callbacks;
this.mQueryExecutor = databaseConfiguration.queryExecutor;
this.mTransactionExecutor = new TransactionExecutor(databaseConfiguration.transactionExecutor);
this.mAllowMainThreadQueries = databaseConfiguration.allowMainThreadQueries;
this.mWriteAheadLoggingEnabled = z2;
if (databaseConfiguration.multiInstanceInvalidation) {
this.mInvalidationTracker.startMultiInstanceInvalidation(databaseConfiguration.context, databaseConfiguration.name);
}
}
public void internalInitInvalidationTracker(@NonNull SupportSQLiteDatabase supportSQLiteDatabase) {
this.mInvalidationTracker.internalInit(supportSQLiteDatabase);
}
public boolean isOpen() {
SupportSQLiteDatabase supportSQLiteDatabase = this.mDatabase;
return supportSQLiteDatabase != null && supportSQLiteDatabase.isOpen();
}
@NonNull
public Cursor query(@NonNull SupportSQLiteQuery supportSQLiteQuery) {
return query(supportSQLiteQuery, (CancellationSignal) null);
}
@NonNull
public Cursor query(@NonNull SupportSQLiteQuery supportSQLiteQuery, @Nullable CancellationSignal cancellationSignal) {
assertNotMainThread();
assertNotSuspendingTransaction();
return cancellationSignal != null ? this.mOpenHelper.getWritableDatabase().query(supportSQLiteQuery, cancellationSignal) : this.mOpenHelper.getWritableDatabase().query(supportSQLiteQuery);
}
@NonNull
public Cursor query(@NonNull String str, @Nullable Object[] objArr) {
return this.mOpenHelper.getWritableDatabase().query(new SimpleSQLiteQuery(str, objArr));
}
public <V> V runInTransaction(@NonNull Callable<V> callable) {
beginTransaction();
try {
V call = callable.call();
setTransactionSuccessful();
endTransaction();
return call;
} catch (RuntimeException e) {
throw e;
} catch (Exception e2) {
SneakyThrow.reThrow(e2);
endTransaction();
return null;
} catch (Throwable th) {
endTransaction();
throw th;
}
}
public void runInTransaction(@NonNull Runnable runnable) {
beginTransaction();
try {
runnable.run();
setTransactionSuccessful();
} finally {
endTransaction();
}
}
@Deprecated
public void setTransactionSuccessful() {
this.mOpenHelper.getWritableDatabase().setTransactionSuccessful();
}
}