package androidx.media3.datasource.cache; import android.content.ContentValues; import android.database.Cursor; import android.database.SQLException; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteException; import android.util.SparseArray; import android.util.SparseBooleanArray; import androidx.media3.common.util.Assertions; import androidx.media3.common.util.AtomicFile; import androidx.media3.common.util.Util; import androidx.media3.database.DatabaseIOException; import androidx.media3.database.DatabaseProvider; import androidx.media3.database.VersionTable; import com.google.common.collect.ImmutableSet; import com.google.common.collect.UnmodifiableIterator; import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.Closeable; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; import java.io.IOException; import java.io.OutputStream; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.Key; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; import javax.crypto.Cipher; import javax.crypto.CipherInputStream; import javax.crypto.CipherOutputStream; import javax.crypto.NoSuchPaddingException; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; /* JADX INFO: Access modifiers changed from: package-private */ /* loaded from: classes2.dex */ public class CachedContentIndex { static final String FILE_NAME_ATOMIC = "cached_content_index.exi"; private static final int INCREMENTAL_METADATA_READ_LENGTH = 10485760; private final SparseArray idToKey; private final HashMap keyToContent; private final SparseBooleanArray newIds; private Storage previousStorage; private final SparseBooleanArray removedIds; private Storage storage; /* JADX INFO: Access modifiers changed from: private */ /* loaded from: classes2.dex */ public interface Storage { void delete() throws IOException; boolean exists() throws IOException; void initialize(long j); void load(HashMap hashMap, SparseArray sparseArray) throws IOException; void onRemove(CachedContent cachedContent, boolean z); void onUpdate(CachedContent cachedContent); void storeFully(HashMap hashMap) throws IOException; void storeIncremental(HashMap hashMap) throws IOException; } static /* synthetic */ Cipher access$000() throws NoSuchPaddingException, NoSuchAlgorithmException { return getCipher(); } public static boolean isIndexFile(String str) { return str.startsWith(FILE_NAME_ATOMIC); } public static void delete(DatabaseProvider databaseProvider, long j) throws DatabaseIOException { DatabaseStorage.delete(databaseProvider, j); } public CachedContentIndex(DatabaseProvider databaseProvider) { this(databaseProvider, null, null, false, false); } public CachedContentIndex(DatabaseProvider databaseProvider, File file, byte[] bArr, boolean z, boolean z2) { Assertions.checkState((databaseProvider == null && file == null) ? false : true); this.keyToContent = new HashMap<>(); this.idToKey = new SparseArray<>(); this.removedIds = new SparseBooleanArray(); this.newIds = new SparseBooleanArray(); DatabaseStorage databaseStorage = databaseProvider != null ? new DatabaseStorage(databaseProvider) : null; LegacyStorage legacyStorage = file != null ? new LegacyStorage(new File(file, FILE_NAME_ATOMIC), bArr, z) : null; if (databaseStorage == null || (legacyStorage != null && z2)) { this.storage = (Storage) Util.castNonNull(legacyStorage); this.previousStorage = databaseStorage; } else { this.storage = databaseStorage; this.previousStorage = legacyStorage; } } public void initialize(long j) throws IOException { Storage storage; this.storage.initialize(j); Storage storage2 = this.previousStorage; if (storage2 != null) { storage2.initialize(j); } if (!this.storage.exists() && (storage = this.previousStorage) != null && storage.exists()) { this.previousStorage.load(this.keyToContent, this.idToKey); this.storage.storeFully(this.keyToContent); } else { this.storage.load(this.keyToContent, this.idToKey); } Storage storage3 = this.previousStorage; if (storage3 != null) { storage3.delete(); this.previousStorage = null; } } public void store() throws IOException { this.storage.storeIncremental(this.keyToContent); int size = this.removedIds.size(); for (int i = 0; i < size; i++) { this.idToKey.remove(this.removedIds.keyAt(i)); } this.removedIds.clear(); this.newIds.clear(); } public CachedContent getOrAdd(String str) { CachedContent cachedContent = this.keyToContent.get(str); return cachedContent == null ? addNew(str) : cachedContent; } public CachedContent get(String str) { return this.keyToContent.get(str); } public Collection getAll() { return Collections.unmodifiableCollection(this.keyToContent.values()); } public int assignIdForKey(String str) { return getOrAdd(str).id; } public String getKeyForId(int i) { return this.idToKey.get(i); } public void maybeRemove(String str) { CachedContent cachedContent = this.keyToContent.get(str); if (cachedContent != null && cachedContent.isEmpty() && cachedContent.isFullyUnlocked()) { this.keyToContent.remove(str); int i = cachedContent.id; boolean z = this.newIds.get(i); this.storage.onRemove(cachedContent, z); if (z) { this.idToKey.remove(i); this.newIds.delete(i); } else { this.idToKey.put(i, null); this.removedIds.put(i, true); } } } /* JADX WARN: Multi-variable type inference failed */ public void removeEmpty() { UnmodifiableIterator it = ImmutableSet.copyOf((Collection) this.keyToContent.keySet()).iterator(); while (it.hasNext()) { maybeRemove((String) it.next()); } } public Set getKeys() { return this.keyToContent.keySet(); } public void applyContentMetadataMutations(String str, ContentMetadataMutations contentMetadataMutations) { CachedContent orAdd = getOrAdd(str); if (orAdd.applyMetadataMutations(contentMetadataMutations)) { this.storage.onUpdate(orAdd); } } public ContentMetadata getContentMetadata(String str) { CachedContent cachedContent = get(str); return cachedContent != null ? cachedContent.getMetadata() : DefaultContentMetadata.EMPTY; } private CachedContent addNew(String str) { int newId = getNewId(this.idToKey); CachedContent cachedContent = new CachedContent(newId, str); this.keyToContent.put(str, cachedContent); this.idToKey.put(newId, str); this.newIds.put(newId, true); this.storage.onUpdate(cachedContent); return cachedContent; } private static Cipher getCipher() throws NoSuchPaddingException, NoSuchAlgorithmException { if (Util.SDK_INT == 18) { try { return Cipher.getInstance("AES/CBC/PKCS5PADDING", "BC"); } catch (Throwable unused) { } } return Cipher.getInstance("AES/CBC/PKCS5PADDING"); } static int getNewId(SparseArray sparseArray) { int size = sparseArray.size(); int i = 0; int keyAt = size == 0 ? 0 : sparseArray.keyAt(size - 1) + 1; if (keyAt >= 0) { return keyAt; } while (i < size && i == sparseArray.keyAt(i)) { i++; } return i; } /* JADX INFO: Access modifiers changed from: private */ public static DefaultContentMetadata readContentMetadata(DataInputStream dataInputStream) throws IOException { int readInt = dataInputStream.readInt(); HashMap hashMap = new HashMap(); for (int i = 0; i < readInt; i++) { String readUTF = dataInputStream.readUTF(); int readInt2 = dataInputStream.readInt(); if (readInt2 < 0) { throw new IOException("Invalid value size: " + readInt2); } int min = Math.min(readInt2, INCREMENTAL_METADATA_READ_LENGTH); byte[] bArr = Util.EMPTY_BYTE_ARRAY; int i2 = 0; while (i2 != readInt2) { int i3 = i2 + min; bArr = Arrays.copyOf(bArr, i3); dataInputStream.readFully(bArr, i2, min); min = Math.min(readInt2 - i3, INCREMENTAL_METADATA_READ_LENGTH); i2 = i3; } hashMap.put(readUTF, bArr); } return new DefaultContentMetadata(hashMap); } /* JADX INFO: Access modifiers changed from: private */ public static void writeContentMetadata(DefaultContentMetadata defaultContentMetadata, DataOutputStream dataOutputStream) throws IOException { Set> entrySet = defaultContentMetadata.entrySet(); dataOutputStream.writeInt(entrySet.size()); for (Map.Entry entry : entrySet) { dataOutputStream.writeUTF(entry.getKey()); byte[] value = entry.getValue(); dataOutputStream.writeInt(value.length); dataOutputStream.write(value); } } /* loaded from: classes2.dex */ private static class LegacyStorage implements Storage { private static final int FLAG_ENCRYPTED_INDEX = 1; private static final int VERSION = 2; private static final int VERSION_METADATA_INTRODUCED = 2; private final AtomicFile atomicFile; private ReusableBufferedOutputStream bufferedOutputStream; private boolean changed; private final Cipher cipher; private final boolean encrypt; private final SecureRandom random; private final SecretKeySpec secretKeySpec; @Override // androidx.media3.datasource.cache.CachedContentIndex.Storage public void initialize(long j) { } @Override // androidx.media3.datasource.cache.CachedContentIndex.Storage public void onRemove(CachedContent cachedContent, boolean z) { this.changed = true; } @Override // androidx.media3.datasource.cache.CachedContentIndex.Storage public void onUpdate(CachedContent cachedContent) { this.changed = true; } public LegacyStorage(File file, byte[] bArr, boolean z) { Cipher cipher; SecretKeySpec secretKeySpec; Assertions.checkState((bArr == null && z) ? false : true); if (bArr != null) { Assertions.checkArgument(bArr.length == 16); try { cipher = CachedContentIndex.access$000(); secretKeySpec = new SecretKeySpec(bArr, "AES"); } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { throw new IllegalStateException(e); } } else { Assertions.checkArgument(!z); cipher = null; secretKeySpec = null; } this.encrypt = z; this.cipher = cipher; this.secretKeySpec = secretKeySpec; this.random = z ? new SecureRandom() : null; this.atomicFile = new AtomicFile(file); } @Override // androidx.media3.datasource.cache.CachedContentIndex.Storage public boolean exists() { return this.atomicFile.exists(); } @Override // androidx.media3.datasource.cache.CachedContentIndex.Storage public void delete() { this.atomicFile.delete(); } @Override // androidx.media3.datasource.cache.CachedContentIndex.Storage public void load(HashMap hashMap, SparseArray sparseArray) { Assertions.checkState(!this.changed); if (readFile(hashMap, sparseArray)) { return; } hashMap.clear(); sparseArray.clear(); this.atomicFile.delete(); } @Override // androidx.media3.datasource.cache.CachedContentIndex.Storage public void storeFully(HashMap hashMap) throws IOException { writeFile(hashMap); this.changed = false; } @Override // androidx.media3.datasource.cache.CachedContentIndex.Storage public void storeIncremental(HashMap hashMap) throws IOException { if (this.changed) { storeFully(hashMap); } } private boolean readFile(HashMap hashMap, SparseArray sparseArray) { BufferedInputStream bufferedInputStream; DataInputStream dataInputStream; if (!this.atomicFile.exists()) { return true; } DataInputStream dataInputStream2 = null; try { bufferedInputStream = new BufferedInputStream(this.atomicFile.openRead()); dataInputStream = new DataInputStream(bufferedInputStream); } catch (IOException unused) { } catch (Throwable th) { th = th; } try { int readInt = dataInputStream.readInt(); if (readInt >= 0 && readInt <= 2) { if ((dataInputStream.readInt() & 1) != 0) { if (this.cipher != null) { byte[] bArr = new byte[16]; dataInputStream.readFully(bArr); try { this.cipher.init(2, (Key) Util.castNonNull(this.secretKeySpec), new IvParameterSpec(bArr)); dataInputStream = new DataInputStream(new CipherInputStream(bufferedInputStream, this.cipher)); } catch (InvalidAlgorithmParameterException | InvalidKeyException e) { throw new IllegalStateException(e); } } else { Util.closeQuietly(dataInputStream); return false; } } else if (this.encrypt) { this.changed = true; } int readInt2 = dataInputStream.readInt(); int i = 0; for (int i2 = 0; i2 < readInt2; i2++) { CachedContent readCachedContent = readCachedContent(readInt, dataInputStream); hashMap.put(readCachedContent.key, readCachedContent); sparseArray.put(readCachedContent.id, readCachedContent.key); i += hashCachedContent(readCachedContent, readInt); } int readInt3 = dataInputStream.readInt(); boolean z = dataInputStream.read() == -1; if (readInt3 == i && z) { Util.closeQuietly(dataInputStream); return true; } Util.closeQuietly(dataInputStream); return false; } Util.closeQuietly(dataInputStream); return false; } catch (IOException unused2) { dataInputStream2 = dataInputStream; if (dataInputStream2 != null) { Util.closeQuietly(dataInputStream2); } return false; } catch (Throwable th2) { th = th2; dataInputStream2 = dataInputStream; if (dataInputStream2 != null) { Util.closeQuietly(dataInputStream2); } throw th; } } private void writeFile(HashMap hashMap) throws IOException { ReusableBufferedOutputStream reusableBufferedOutputStream; DataOutputStream dataOutputStream; Closeable closeable = null; try { OutputStream startWrite = this.atomicFile.startWrite(); ReusableBufferedOutputStream reusableBufferedOutputStream2 = this.bufferedOutputStream; if (reusableBufferedOutputStream2 == null) { this.bufferedOutputStream = new ReusableBufferedOutputStream(startWrite); } else { reusableBufferedOutputStream2.reset(startWrite); } reusableBufferedOutputStream = this.bufferedOutputStream; dataOutputStream = new DataOutputStream(reusableBufferedOutputStream); } catch (Throwable th) { th = th; } try { dataOutputStream.writeInt(2); int i = 0; dataOutputStream.writeInt(this.encrypt ? 1 : 0); if (this.encrypt) { byte[] bArr = new byte[16]; ((SecureRandom) Util.castNonNull(this.random)).nextBytes(bArr); dataOutputStream.write(bArr); try { ((Cipher) Util.castNonNull(this.cipher)).init(1, (Key) Util.castNonNull(this.secretKeySpec), new IvParameterSpec(bArr)); dataOutputStream.flush(); dataOutputStream = new DataOutputStream(new CipherOutputStream(reusableBufferedOutputStream, this.cipher)); } catch (InvalidAlgorithmParameterException | InvalidKeyException e) { throw new IllegalStateException(e); } } dataOutputStream.writeInt(hashMap.size()); for (CachedContent cachedContent : hashMap.values()) { writeCachedContent(cachedContent, dataOutputStream); i += hashCachedContent(cachedContent, 2); } dataOutputStream.writeInt(i); this.atomicFile.endWrite(dataOutputStream); Util.closeQuietly(null); } catch (Throwable th2) { th = th2; closeable = dataOutputStream; Util.closeQuietly(closeable); throw th; } } private int hashCachedContent(CachedContent cachedContent, int i) { int i2; int hashCode; int hashCode2 = (cachedContent.id * 31) + cachedContent.key.hashCode(); if (i < 2) { long contentLength = ContentMetadata.getContentLength(cachedContent.getMetadata()); i2 = hashCode2 * 31; hashCode = (int) (contentLength ^ (contentLength >>> 32)); } else { i2 = hashCode2 * 31; hashCode = cachedContent.getMetadata().hashCode(); } return i2 + hashCode; } private CachedContent readCachedContent(int i, DataInputStream dataInputStream) throws IOException { DefaultContentMetadata readContentMetadata; int readInt = dataInputStream.readInt(); String readUTF = dataInputStream.readUTF(); if (i >= 2) { readContentMetadata = CachedContentIndex.readContentMetadata(dataInputStream); } else { long readLong = dataInputStream.readLong(); ContentMetadataMutations contentMetadataMutations = new ContentMetadataMutations(); ContentMetadataMutations.setContentLength(contentMetadataMutations, readLong); readContentMetadata = DefaultContentMetadata.EMPTY.copyWithMutationsApplied(contentMetadataMutations); } return new CachedContent(readInt, readUTF, readContentMetadata); } private void writeCachedContent(CachedContent cachedContent, DataOutputStream dataOutputStream) throws IOException { dataOutputStream.writeInt(cachedContent.id); dataOutputStream.writeUTF(cachedContent.key); CachedContentIndex.writeContentMetadata(cachedContent.getMetadata(), dataOutputStream); } } /* loaded from: classes2.dex */ private static final class DatabaseStorage implements Storage { private static final String COLUMN_ID = "id"; private static final int COLUMN_INDEX_ID = 0; private static final int COLUMN_INDEX_KEY = 1; private static final int COLUMN_INDEX_METADATA = 2; private static final String COLUMN_METADATA = "metadata"; private static final String TABLE_PREFIX = "ExoPlayerCacheIndex"; private static final String TABLE_SCHEMA = "(id INTEGER PRIMARY KEY NOT NULL,key TEXT NOT NULL,metadata BLOB NOT NULL)"; private static final int TABLE_VERSION = 1; private static final String WHERE_ID_EQUALS = "id = ?"; private final DatabaseProvider databaseProvider; private String hexUid; private final SparseArray pendingUpdates = new SparseArray<>(); private String tableName; private static final String COLUMN_KEY = "key"; private static final String[] COLUMNS = {"id", COLUMN_KEY, "metadata"}; public static void delete(DatabaseProvider databaseProvider, long j) throws DatabaseIOException { delete(databaseProvider, Long.toHexString(j)); } public DatabaseStorage(DatabaseProvider databaseProvider) { this.databaseProvider = databaseProvider; } @Override // androidx.media3.datasource.cache.CachedContentIndex.Storage public void initialize(long j) { String hexString = Long.toHexString(j); this.hexUid = hexString; this.tableName = getTableName(hexString); } @Override // androidx.media3.datasource.cache.CachedContentIndex.Storage public boolean exists() throws DatabaseIOException { try { return VersionTable.getVersion(this.databaseProvider.getReadableDatabase(), 1, (String) Assertions.checkNotNull(this.hexUid)) != -1; } catch (SQLException e) { throw new DatabaseIOException(e); } } @Override // androidx.media3.datasource.cache.CachedContentIndex.Storage public void delete() throws DatabaseIOException { delete(this.databaseProvider, (String) Assertions.checkNotNull(this.hexUid)); } @Override // androidx.media3.datasource.cache.CachedContentIndex.Storage public void load(HashMap hashMap, SparseArray sparseArray) throws IOException { Assertions.checkState(this.pendingUpdates.size() == 0); try { if (VersionTable.getVersion(this.databaseProvider.getReadableDatabase(), 1, (String) Assertions.checkNotNull(this.hexUid)) != 1) { SQLiteDatabase writableDatabase = this.databaseProvider.getWritableDatabase(); writableDatabase.beginTransactionNonExclusive(); try { initializeTable(writableDatabase); writableDatabase.setTransactionSuccessful(); writableDatabase.endTransaction(); } catch (Throwable th) { writableDatabase.endTransaction(); throw th; } } Cursor cursor = getCursor(); while (cursor.moveToNext()) { try { CachedContent cachedContent = new CachedContent(cursor.getInt(0), (String) Assertions.checkNotNull(cursor.getString(1)), CachedContentIndex.readContentMetadata(new DataInputStream(new ByteArrayInputStream(cursor.getBlob(2))))); hashMap.put(cachedContent.key, cachedContent); sparseArray.put(cachedContent.id, cachedContent.key); } finally { } } if (cursor != null) { cursor.close(); } } catch (SQLiteException e) { hashMap.clear(); sparseArray.clear(); throw new DatabaseIOException(e); } } @Override // androidx.media3.datasource.cache.CachedContentIndex.Storage public void storeFully(HashMap hashMap) throws IOException { try { SQLiteDatabase writableDatabase = this.databaseProvider.getWritableDatabase(); writableDatabase.beginTransactionNonExclusive(); try { initializeTable(writableDatabase); Iterator it = hashMap.values().iterator(); while (it.hasNext()) { addOrUpdateRow(writableDatabase, it.next()); } writableDatabase.setTransactionSuccessful(); this.pendingUpdates.clear(); } finally { writableDatabase.endTransaction(); } } catch (SQLException e) { throw new DatabaseIOException(e); } } @Override // androidx.media3.datasource.cache.CachedContentIndex.Storage public void storeIncremental(HashMap hashMap) throws IOException { if (this.pendingUpdates.size() == 0) { return; } try { SQLiteDatabase writableDatabase = this.databaseProvider.getWritableDatabase(); writableDatabase.beginTransactionNonExclusive(); for (int i = 0; i < this.pendingUpdates.size(); i++) { try { CachedContent valueAt = this.pendingUpdates.valueAt(i); if (valueAt == null) { deleteRow(writableDatabase, this.pendingUpdates.keyAt(i)); } else { addOrUpdateRow(writableDatabase, valueAt); } } finally { writableDatabase.endTransaction(); } } writableDatabase.setTransactionSuccessful(); this.pendingUpdates.clear(); } catch (SQLException e) { throw new DatabaseIOException(e); } } @Override // androidx.media3.datasource.cache.CachedContentIndex.Storage public void onUpdate(CachedContent cachedContent) { this.pendingUpdates.put(cachedContent.id, cachedContent); } @Override // androidx.media3.datasource.cache.CachedContentIndex.Storage public void onRemove(CachedContent cachedContent, boolean z) { if (z) { this.pendingUpdates.delete(cachedContent.id); } else { this.pendingUpdates.put(cachedContent.id, null); } } private Cursor getCursor() { return this.databaseProvider.getReadableDatabase().query((String) Assertions.checkNotNull(this.tableName), COLUMNS, null, null, null, null, null); } private void initializeTable(SQLiteDatabase sQLiteDatabase) throws DatabaseIOException { VersionTable.setVersion(sQLiteDatabase, 1, (String) Assertions.checkNotNull(this.hexUid), 1); dropTable(sQLiteDatabase, (String) Assertions.checkNotNull(this.tableName)); sQLiteDatabase.execSQL("CREATE TABLE " + this.tableName + " (id INTEGER PRIMARY KEY NOT NULL,key TEXT NOT NULL,metadata BLOB NOT NULL)"); } private void deleteRow(SQLiteDatabase sQLiteDatabase, int i) { sQLiteDatabase.delete((String) Assertions.checkNotNull(this.tableName), WHERE_ID_EQUALS, new String[]{Integer.toString(i)}); } private void addOrUpdateRow(SQLiteDatabase sQLiteDatabase, CachedContent cachedContent) throws IOException { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); CachedContentIndex.writeContentMetadata(cachedContent.getMetadata(), new DataOutputStream(byteArrayOutputStream)); byte[] byteArray = byteArrayOutputStream.toByteArray(); ContentValues contentValues = new ContentValues(); contentValues.put("id", Integer.valueOf(cachedContent.id)); contentValues.put(COLUMN_KEY, cachedContent.key); contentValues.put("metadata", byteArray); sQLiteDatabase.replaceOrThrow((String) Assertions.checkNotNull(this.tableName), null, contentValues); } private static void delete(DatabaseProvider databaseProvider, String str) throws DatabaseIOException { try { String tableName = getTableName(str); SQLiteDatabase writableDatabase = databaseProvider.getWritableDatabase(); writableDatabase.beginTransactionNonExclusive(); try { VersionTable.removeVersion(writableDatabase, 1, str); dropTable(writableDatabase, tableName); writableDatabase.setTransactionSuccessful(); } finally { writableDatabase.endTransaction(); } } catch (SQLException e) { throw new DatabaseIOException(e); } } private static void dropTable(SQLiteDatabase sQLiteDatabase, String str) { sQLiteDatabase.execSQL("DROP TABLE IF EXISTS " + str); } private static String getTableName(String str) { return TABLE_PREFIX + str; } } }