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

619 lines
24 KiB
Java

package androidx.room;
import android.annotation.SuppressLint;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteException;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.annotation.VisibleForTesting;
import androidx.annotation.WorkerThread;
import androidx.arch.core.internal.SafeIterableMap;
import androidx.lifecycle.LiveData;
import androidx.sqlite.db.SimpleSQLiteQuery;
import androidx.sqlite.db.SupportSQLiteDatabase;
import androidx.sqlite.db.SupportSQLiteStatement;
import c.d.b.a.a;
import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Lock;
public class InvalidationTracker {
private static final String CREATE_TRACKING_TABLE_SQL = "CREATE TEMP TABLE room_table_modification_log(table_id INTEGER PRIMARY KEY, invalidated INTEGER NOT NULL DEFAULT 0)";
private static final String INVALIDATED_COLUMN_NAME = "invalidated";
@VisibleForTesting
public static final String RESET_UPDATED_TABLES_SQL = "UPDATE room_table_modification_log SET invalidated = 0 WHERE invalidated = 1 ";
@VisibleForTesting
public static final String SELECT_UPDATED_TABLES_SQL = "SELECT * FROM room_table_modification_log WHERE invalidated = 1;";
private static final String TABLE_ID_COLUMN_NAME = "table_id";
private static final String[] TRIGGERS = {"UPDATE", "DELETE", "INSERT"};
private static final String UPDATE_TABLE_NAME = "room_table_modification_log";
public volatile SupportSQLiteStatement mCleanupStatement;
public final RoomDatabase mDatabase;
private volatile boolean mInitialized;
private final InvalidationLiveDataContainer mInvalidationLiveDataContainer;
private MultiInstanceInvalidationClient mMultiInstanceInvalidationClient;
private ObservedTableTracker mObservedTableTracker;
@SuppressLint({"RestrictedApi"})
@VisibleForTesting
public final SafeIterableMap<Observer, ObserverWrapper> mObserverMap;
public AtomicBoolean mPendingRefresh;
@VisibleForTesting
public Runnable mRefreshRunnable;
@NonNull
public final HashMap<String, Integer> mTableIdLookup;
public final String[] mTableNames;
@NonNull
private Map<String, Set<String>> mViewTables;
/* renamed from: androidx.room.InvalidationTracker$1 reason: invalid class name */
public class AnonymousClass1 implements Runnable {
public AnonymousClass1() {
}
/* JADX INFO: finally extract failed */
private Set<Integer> checkUpdatedTable() {
HashSet hashSet = new HashSet();
Cursor query = InvalidationTracker.this.mDatabase.query(new SimpleSQLiteQuery("SELECT * FROM room_table_modification_log WHERE invalidated = 1;"));
while (query.moveToNext()) {
try {
hashSet.add(Integer.valueOf(query.getInt(0)));
} catch (Throwable th) {
query.close();
throw th;
}
}
query.close();
if (!hashSet.isEmpty()) {
InvalidationTracker.this.mCleanupStatement.executeUpdateDelete();
}
return hashSet;
}
@Override // java.lang.Runnable
public void run() {
Lock closeLock = InvalidationTracker.this.mDatabase.getCloseLock();
Set<Integer> set = null;
try {
closeLock.lock();
if (!InvalidationTracker.this.ensureInitialization()) {
closeLock.unlock();
} else if (!InvalidationTracker.this.mPendingRefresh.compareAndSet(true, false)) {
closeLock.unlock();
} else if (InvalidationTracker.this.mDatabase.inTransaction()) {
closeLock.unlock();
} else {
RoomDatabase roomDatabase = InvalidationTracker.this.mDatabase;
if (roomDatabase.mWriteAheadLoggingEnabled) {
SupportSQLiteDatabase writableDatabase = roomDatabase.getOpenHelper().getWritableDatabase();
writableDatabase.beginTransaction();
try {
set = checkUpdatedTable();
writableDatabase.setTransactionSuccessful();
} finally {
writableDatabase.endTransaction();
}
} else {
set = checkUpdatedTable();
}
closeLock.unlock();
if (set != null && !set.isEmpty()) {
synchronized (InvalidationTracker.this.mObserverMap) {
Iterator<Map.Entry<Observer, ObserverWrapper>> it = InvalidationTracker.this.mObserverMap.iterator();
while (it.hasNext()) {
it.next().getValue().notifyByTableInvalidStatus(set);
}
}
}
}
} catch (SQLiteException | IllegalStateException e) {
Log.e("ROOM", "Cannot run invalidation tracker. Is the db closed?", e);
} catch (Throwable th) {
closeLock.unlock();
throw th;
}
}
}
public static class ObservedTableTracker {
public static final int ADD = 1;
public static final int NO_OP = 0;
public static final int REMOVE = 2;
public boolean mNeedsSync;
public boolean mPendingSync;
public final long[] mTableObservers;
public final int[] mTriggerStateChanges;
public final boolean[] mTriggerStates;
public ObservedTableTracker(int i) {
long[] jArr = new long[i];
this.mTableObservers = jArr;
boolean[] zArr = new boolean[i];
this.mTriggerStates = zArr;
this.mTriggerStateChanges = new int[i];
Arrays.fill(jArr, 0L);
Arrays.fill(zArr, false);
}
@Nullable
public int[] getTablesToSync() {
synchronized (this) {
if (this.mNeedsSync) {
if (!this.mPendingSync) {
int length = this.mTableObservers.length;
int i = 0;
while (true) {
int i2 = 1;
if (i < length) {
boolean z2 = this.mTableObservers[i] > 0;
boolean[] zArr = this.mTriggerStates;
if (z2 != zArr[i]) {
int[] iArr = this.mTriggerStateChanges;
if (!z2) {
i2 = 2;
}
iArr[i] = i2;
} else {
this.mTriggerStateChanges[i] = 0;
}
zArr[i] = z2;
i++;
} else {
this.mPendingSync = true;
this.mNeedsSync = false;
return this.mTriggerStateChanges;
}
}
}
}
return null;
}
}
public boolean onAdded(int... iArr) {
boolean z2;
synchronized (this) {
z2 = false;
for (int i : iArr) {
long[] jArr = this.mTableObservers;
long j = jArr[i];
jArr[i] = 1 + j;
if (j == 0) {
this.mNeedsSync = true;
z2 = true;
}
}
}
return z2;
}
public boolean onRemoved(int... iArr) {
boolean z2;
synchronized (this) {
z2 = false;
for (int i : iArr) {
long[] jArr = this.mTableObservers;
long j = jArr[i];
jArr[i] = j - 1;
if (j == 1) {
this.mNeedsSync = true;
z2 = true;
}
}
}
return z2;
}
public void onSyncCompleted() {
synchronized (this) {
this.mPendingSync = false;
}
}
}
public static abstract class Observer {
public final String[] mTables;
public Observer(@NonNull String str, String... strArr) {
String[] strArr2 = (String[]) Arrays.copyOf(strArr, strArr.length + 1);
this.mTables = strArr2;
strArr2[strArr.length] = str;
}
public Observer(@NonNull String[] strArr) {
this.mTables = (String[]) Arrays.copyOf(strArr, strArr.length);
}
public boolean isRemote() {
return false;
}
public abstract void onInvalidated(@NonNull Set<String> set);
}
public static class ObserverWrapper {
public final Observer mObserver;
private final Set<String> mSingleTableSet;
public final int[] mTableIds;
private final String[] mTableNames;
public ObserverWrapper(Observer observer, int[] iArr, String[] strArr) {
this.mObserver = observer;
this.mTableIds = iArr;
this.mTableNames = strArr;
if (iArr.length == 1) {
HashSet hashSet = new HashSet();
hashSet.add(strArr[0]);
this.mSingleTableSet = Collections.unmodifiableSet(hashSet);
return;
}
this.mSingleTableSet = null;
}
public void notifyByTableInvalidStatus(Set<Integer> set) {
int length = this.mTableIds.length;
Set<String> set2 = null;
for (int i = 0; i < length; i++) {
if (set.contains(Integer.valueOf(this.mTableIds[i]))) {
if (length == 1) {
set2 = this.mSingleTableSet;
} else {
if (set2 == null) {
set2 = new HashSet<>(length);
}
set2.add(this.mTableNames[i]);
}
}
}
if (set2 != null) {
this.mObserver.onInvalidated(set2);
}
}
public void notifyByTableNames(String[] strArr) {
Set<String> set = null;
if (this.mTableNames.length == 1) {
int length = strArr.length;
int i = 0;
while (true) {
if (i >= length) {
break;
} else if (strArr[i].equalsIgnoreCase(this.mTableNames[0])) {
set = this.mSingleTableSet;
break;
} else {
i++;
}
}
} else {
HashSet hashSet = new HashSet();
for (String str : strArr) {
String[] strArr2 = this.mTableNames;
int length2 = strArr2.length;
int i2 = 0;
while (true) {
if (i2 >= length2) {
break;
}
String str2 = strArr2[i2];
if (str2.equalsIgnoreCase(str)) {
hashSet.add(str2);
break;
}
i2++;
}
}
if (hashSet.size() > 0) {
set = hashSet;
}
}
if (set != null) {
this.mObserver.onInvalidated(set);
}
}
}
public static class WeakObserver extends Observer {
public final WeakReference<Observer> mDelegateRef;
public final InvalidationTracker mTracker;
public WeakObserver(InvalidationTracker invalidationTracker, Observer observer) {
super(observer.mTables);
this.mTracker = invalidationTracker;
this.mDelegateRef = new WeakReference<>(observer);
}
@Override // androidx.room.InvalidationTracker.Observer
public void onInvalidated(@NonNull Set<String> set) {
Observer observer = this.mDelegateRef.get();
if (observer == null) {
this.mTracker.removeObserver(this);
} else {
observer.onInvalidated(set);
}
}
}
@RestrictTo({RestrictTo.Scope.LIBRARY_GROUP_PREFIX})
public InvalidationTracker(RoomDatabase roomDatabase, Map<String, String> map, Map<String, Set<String>> map2, String... strArr) {
this.mPendingRefresh = new AtomicBoolean(false);
this.mInitialized = false;
this.mObserverMap = new SafeIterableMap<>();
this.mRefreshRunnable = new AnonymousClass1();
this.mDatabase = roomDatabase;
this.mObservedTableTracker = new ObservedTableTracker(strArr.length);
this.mTableIdLookup = new HashMap<>();
this.mViewTables = map2;
this.mInvalidationLiveDataContainer = new InvalidationLiveDataContainer(roomDatabase);
int length = strArr.length;
this.mTableNames = new String[length];
for (int i = 0; i < length; i++) {
String str = strArr[i];
Locale locale = Locale.US;
String lowerCase = str.toLowerCase(locale);
this.mTableIdLookup.put(lowerCase, Integer.valueOf(i));
String str2 = map.get(strArr[i]);
if (str2 != null) {
this.mTableNames[i] = str2.toLowerCase(locale);
} else {
this.mTableNames[i] = lowerCase;
}
}
for (Map.Entry<String, String> entry : map.entrySet()) {
Locale locale2 = Locale.US;
String lowerCase2 = entry.getValue().toLowerCase(locale2);
if (this.mTableIdLookup.containsKey(lowerCase2)) {
String lowerCase3 = entry.getKey().toLowerCase(locale2);
HashMap<String, Integer> hashMap = this.mTableIdLookup;
hashMap.put(lowerCase3, hashMap.get(lowerCase2));
}
}
}
@RestrictTo({RestrictTo.Scope.LIBRARY_GROUP_PREFIX})
public InvalidationTracker(RoomDatabase roomDatabase, String... strArr) {
this(roomDatabase, new HashMap(), Collections.emptyMap(), strArr);
}
private static void appendTriggerName(StringBuilder sb, String str, String str2) {
a.k0(sb, "`", "room_table_modification_trigger_", str, "_");
sb.append(str2);
sb.append("`");
}
private String[] resolveViews(String[] strArr) {
HashSet hashSet = new HashSet();
for (String str : strArr) {
String lowerCase = str.toLowerCase(Locale.US);
if (this.mViewTables.containsKey(lowerCase)) {
hashSet.addAll(this.mViewTables.get(lowerCase));
} else {
hashSet.add(str);
}
}
return (String[]) hashSet.toArray(new String[hashSet.size()]);
}
private void startTrackingTable(SupportSQLiteDatabase supportSQLiteDatabase, int i) {
supportSQLiteDatabase.execSQL("INSERT OR IGNORE INTO room_table_modification_log VALUES(" + i + ", 0)");
String str = this.mTableNames[i];
StringBuilder sb = new StringBuilder();
String[] strArr = TRIGGERS;
for (String str2 : strArr) {
sb.setLength(0);
sb.append("CREATE TEMP TRIGGER IF NOT EXISTS ");
appendTriggerName(sb, str, str2);
a.k0(sb, " AFTER ", str2, " ON `", str);
a.k0(sb, "` BEGIN UPDATE ", "room_table_modification_log", " SET ", "invalidated");
a.k0(sb, " = 1", " WHERE ", "table_id", " = ");
sb.append(i);
sb.append(" AND ");
sb.append("invalidated");
sb.append(" = 0");
sb.append("; END");
supportSQLiteDatabase.execSQL(sb.toString());
}
}
private void stopTrackingTable(SupportSQLiteDatabase supportSQLiteDatabase, int i) {
String str = this.mTableNames[i];
StringBuilder sb = new StringBuilder();
String[] strArr = TRIGGERS;
for (String str2 : strArr) {
sb.setLength(0);
sb.append("DROP TRIGGER IF EXISTS ");
appendTriggerName(sb, str, str2);
supportSQLiteDatabase.execSQL(sb.toString());
}
}
private String[] validateAndResolveTableNames(String[] strArr) {
String[] resolveViews = resolveViews(strArr);
for (String str : resolveViews) {
if (!this.mTableIdLookup.containsKey(str.toLowerCase(Locale.US))) {
throw new IllegalArgumentException(a.t("There is no table with name ", str));
}
}
return resolveViews;
}
@SuppressLint({"RestrictedApi"})
@WorkerThread
public void addObserver(@NonNull Observer observer) {
ObserverWrapper putIfAbsent;
String[] resolveViews = resolveViews(observer.mTables);
int[] iArr = new int[resolveViews.length];
int length = resolveViews.length;
for (int i = 0; i < length; i++) {
Integer num = this.mTableIdLookup.get(resolveViews[i].toLowerCase(Locale.US));
if (num != null) {
iArr[i] = num.intValue();
} else {
StringBuilder L = a.L("There is no table with name ");
L.append(resolveViews[i]);
throw new IllegalArgumentException(L.toString());
}
}
ObserverWrapper observerWrapper = new ObserverWrapper(observer, iArr, resolveViews);
synchronized (this.mObserverMap) {
putIfAbsent = this.mObserverMap.putIfAbsent(observer, observerWrapper);
}
if (putIfAbsent == null && this.mObservedTableTracker.onAdded(iArr)) {
syncTriggers();
}
}
@RestrictTo({RestrictTo.Scope.LIBRARY_GROUP_PREFIX})
public void addWeakObserver(Observer observer) {
addObserver(new WeakObserver(this, observer));
}
@RestrictTo({RestrictTo.Scope.LIBRARY_GROUP_PREFIX})
@Deprecated
public <T> LiveData<T> createLiveData(String[] strArr, Callable<T> callable) {
return createLiveData(strArr, false, callable);
}
@RestrictTo({RestrictTo.Scope.LIBRARY_GROUP_PREFIX})
public <T> LiveData<T> createLiveData(String[] strArr, boolean z2, Callable<T> callable) {
return this.mInvalidationLiveDataContainer.create(validateAndResolveTableNames(strArr), z2, callable);
}
public boolean ensureInitialization() {
if (!this.mDatabase.isOpen()) {
return false;
}
if (!this.mInitialized) {
this.mDatabase.getOpenHelper().getWritableDatabase();
}
if (this.mInitialized) {
return true;
}
Log.e("ROOM", "database is not initialized even though it is open");
return false;
}
public void internalInit(SupportSQLiteDatabase supportSQLiteDatabase) {
synchronized (this) {
if (this.mInitialized) {
Log.e("ROOM", "Invalidation tracker is initialized twice :/.");
return;
}
supportSQLiteDatabase.execSQL("PRAGMA temp_store = MEMORY;");
supportSQLiteDatabase.execSQL("PRAGMA recursive_triggers='ON';");
supportSQLiteDatabase.execSQL("CREATE TEMP TABLE room_table_modification_log(table_id INTEGER PRIMARY KEY, invalidated INTEGER NOT NULL DEFAULT 0)");
syncTriggers(supportSQLiteDatabase);
this.mCleanupStatement = supportSQLiteDatabase.compileStatement("UPDATE room_table_modification_log SET invalidated = 0 WHERE invalidated = 1 ");
this.mInitialized = true;
}
}
@RestrictTo({RestrictTo.Scope.LIBRARY})
@VisibleForTesting(otherwise = 3)
public void notifyObserversByTableNames(String... strArr) {
synchronized (this.mObserverMap) {
Iterator<Map.Entry<Observer, ObserverWrapper>> it = this.mObserverMap.iterator();
while (it.hasNext()) {
Map.Entry<Observer, ObserverWrapper> next = it.next();
if (!next.getKey().isRemote()) {
next.getValue().notifyByTableNames(strArr);
}
}
}
}
public void refreshVersionsAsync() {
if (this.mPendingRefresh.compareAndSet(false, true)) {
this.mDatabase.getQueryExecutor().execute(this.mRefreshRunnable);
}
}
@RestrictTo({RestrictTo.Scope.LIBRARY_GROUP_PREFIX})
@WorkerThread
public void refreshVersionsSync() {
syncTriggers();
this.mRefreshRunnable.run();
}
@SuppressLint({"RestrictedApi"})
@WorkerThread
public void removeObserver(@NonNull Observer observer) {
ObserverWrapper remove;
synchronized (this.mObserverMap) {
remove = this.mObserverMap.remove(observer);
}
if (remove != null && this.mObservedTableTracker.onRemoved(remove.mTableIds)) {
syncTriggers();
}
}
public void startMultiInstanceInvalidation(Context context, String str) {
this.mMultiInstanceInvalidationClient = new MultiInstanceInvalidationClient(context, str, this, this.mDatabase.getQueryExecutor());
}
public void stopMultiInstanceInvalidation() {
MultiInstanceInvalidationClient multiInstanceInvalidationClient = this.mMultiInstanceInvalidationClient;
if (multiInstanceInvalidationClient != null) {
multiInstanceInvalidationClient.stop();
this.mMultiInstanceInvalidationClient = null;
}
}
public void syncTriggers() {
if (this.mDatabase.isOpen()) {
syncTriggers(this.mDatabase.getOpenHelper().getWritableDatabase());
}
}
public void syncTriggers(SupportSQLiteDatabase supportSQLiteDatabase) {
if (!supportSQLiteDatabase.inTransaction()) {
while (true) {
try {
Lock closeLock = this.mDatabase.getCloseLock();
closeLock.lock();
try {
int[] tablesToSync = this.mObservedTableTracker.getTablesToSync();
if (tablesToSync == null) {
closeLock.unlock();
return;
}
int length = tablesToSync.length;
supportSQLiteDatabase.beginTransaction();
for (int i = 0; i < length; i++) {
try {
int i2 = tablesToSync[i];
if (i2 == 1) {
startTrackingTable(supportSQLiteDatabase, i);
} else if (i2 == 2) {
stopTrackingTable(supportSQLiteDatabase, i);
}
} catch (Throwable th) {
supportSQLiteDatabase.endTransaction();
throw th;
}
}
supportSQLiteDatabase.setTransactionSuccessful();
supportSQLiteDatabase.endTransaction();
this.mObservedTableTracker.onSyncCompleted();
} finally {
closeLock.unlock();
}
} catch (SQLiteException | IllegalStateException e) {
Log.e("ROOM", "Cannot run invalidation tracker. Is the db closed?", e);
return;
}
}
}
}
}