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 mObserverMap; public AtomicBoolean mPendingRefresh; @VisibleForTesting public Runnable mRefreshRunnable; @NonNull public final HashMap mTableIdLookup; public final String[] mTableNames; @NonNull private Map> 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 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 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> 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 set); } public static class ObserverWrapper { public final Observer mObserver; private final Set 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 set) { int length = this.mTableIds.length; Set 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 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 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 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 map, Map> 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 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 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 LiveData createLiveData(String[] strArr, Callable callable) { return createLiveData(strArr, false, callable); } @RestrictTo({RestrictTo.Scope.LIBRARY_GROUP_PREFIX}) public LiveData createLiveData(String[] strArr, boolean z2, Callable 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> it = this.mObserverMap.iterator(); while (it.hasNext()) { Map.Entry 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; } } } } }