mirror of
https://github.com/androidx/media.git
synced 2025-05-15 19:49:50 +08:00
Enable nullness test for CachedContent/CachedContentIndex
PiperOrigin-RevId: 328551668
This commit is contained in:
parent
94cff6ba50
commit
feb4cce2b2
@ -16,6 +16,7 @@
|
|||||||
package com.google.android.exoplayer2.upstream.cache;
|
package com.google.android.exoplayer2.upstream.cache;
|
||||||
|
|
||||||
import static com.google.android.exoplayer2.util.Assertions.checkArgument;
|
import static com.google.android.exoplayer2.util.Assertions.checkArgument;
|
||||||
|
import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
|
||||||
import static com.google.android.exoplayer2.util.Assertions.checkState;
|
import static com.google.android.exoplayer2.util.Assertions.checkState;
|
||||||
import static java.lang.Math.max;
|
import static java.lang.Math.max;
|
||||||
import static java.lang.Math.min;
|
import static java.lang.Math.min;
|
||||||
@ -219,9 +220,9 @@ import java.util.TreeSet;
|
|||||||
public SimpleCacheSpan setLastTouchTimestamp(
|
public SimpleCacheSpan setLastTouchTimestamp(
|
||||||
SimpleCacheSpan cacheSpan, long lastTouchTimestamp, boolean updateFile) {
|
SimpleCacheSpan cacheSpan, long lastTouchTimestamp, boolean updateFile) {
|
||||||
checkState(cachedSpans.remove(cacheSpan));
|
checkState(cachedSpans.remove(cacheSpan));
|
||||||
File file = cacheSpan.file;
|
File file = checkNotNull(cacheSpan.file);
|
||||||
if (updateFile) {
|
if (updateFile) {
|
||||||
File directory = file.getParentFile();
|
File directory = checkNotNull(file.getParentFile());
|
||||||
long position = cacheSpan.position;
|
long position = cacheSpan.position;
|
||||||
File newFile = SimpleCacheSpan.getCacheFile(directory, id, position, lastTouchTimestamp);
|
File newFile = SimpleCacheSpan.getCacheFile(directory, id, position, lastTouchTimestamp);
|
||||||
if (file.renameTo(newFile)) {
|
if (file.renameTo(newFile)) {
|
||||||
@ -244,7 +245,9 @@ import java.util.TreeSet;
|
|||||||
/** Removes the given span from cache. */
|
/** Removes the given span from cache. */
|
||||||
public boolean removeSpan(CacheSpan span) {
|
public boolean removeSpan(CacheSpan span) {
|
||||||
if (cachedSpans.remove(span)) {
|
if (cachedSpans.remove(span)) {
|
||||||
|
if (span.file != null) {
|
||||||
span.file.delete();
|
span.file.delete();
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -15,6 +15,9 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer2.upstream.cache;
|
package com.google.android.exoplayer2.upstream.cache;
|
||||||
|
|
||||||
|
import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
|
||||||
|
import static com.google.android.exoplayer2.util.Assertions.checkState;
|
||||||
|
import static com.google.android.exoplayer2.util.Util.castNonNull;
|
||||||
import static java.lang.Math.min;
|
import static java.lang.Math.min;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
@ -61,6 +64,7 @@ import javax.crypto.NoSuchPaddingException;
|
|||||||
import javax.crypto.spec.IvParameterSpec;
|
import javax.crypto.spec.IvParameterSpec;
|
||||||
import javax.crypto.spec.SecretKeySpec;
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
import org.checkerframework.checker.nullness.compatqual.NullableType;
|
import org.checkerframework.checker.nullness.compatqual.NullableType;
|
||||||
|
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||||
|
|
||||||
/** Maintains the index of cached content. */
|
/** Maintains the index of cached content. */
|
||||||
/* package */ class CachedContentIndex {
|
/* package */ class CachedContentIndex {
|
||||||
@ -155,13 +159,15 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||||||
@Nullable byte[] legacyStorageSecretKey,
|
@Nullable byte[] legacyStorageSecretKey,
|
||||||
boolean legacyStorageEncrypt,
|
boolean legacyStorageEncrypt,
|
||||||
boolean preferLegacyStorage) {
|
boolean preferLegacyStorage) {
|
||||||
Assertions.checkState(databaseProvider != null || legacyStorageDir != null);
|
checkState(databaseProvider != null || legacyStorageDir != null);
|
||||||
keyToContent = new HashMap<>();
|
keyToContent = new HashMap<>();
|
||||||
idToKey = new SparseArray<>();
|
idToKey = new SparseArray<>();
|
||||||
removedIds = new SparseBooleanArray();
|
removedIds = new SparseBooleanArray();
|
||||||
newIds = new SparseBooleanArray();
|
newIds = new SparseBooleanArray();
|
||||||
|
@Nullable
|
||||||
Storage databaseStorage =
|
Storage databaseStorage =
|
||||||
databaseProvider != null ? new DatabaseStorage(databaseProvider) : null;
|
databaseProvider != null ? new DatabaseStorage(databaseProvider) : null;
|
||||||
|
@Nullable
|
||||||
Storage legacyStorage =
|
Storage legacyStorage =
|
||||||
legacyStorageDir != null
|
legacyStorageDir != null
|
||||||
? new LegacyStorage(
|
? new LegacyStorage(
|
||||||
@ -170,7 +176,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||||||
legacyStorageEncrypt)
|
legacyStorageEncrypt)
|
||||||
: null;
|
: null;
|
||||||
if (databaseStorage == null || (legacyStorage != null && preferLegacyStorage)) {
|
if (databaseStorage == null || (legacyStorage != null && preferLegacyStorage)) {
|
||||||
storage = legacyStorage;
|
storage = castNonNull(legacyStorage);
|
||||||
previousStorage = databaseStorage;
|
previousStorage = databaseStorage;
|
||||||
} else {
|
} else {
|
||||||
storage = databaseStorage;
|
storage = databaseStorage;
|
||||||
@ -325,7 +331,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||||||
|
|
||||||
/** Returns a {@link ContentMetadata} for the given key. */
|
/** Returns a {@link ContentMetadata} for the given key. */
|
||||||
public ContentMetadata getContentMetadata(String key) {
|
public ContentMetadata getContentMetadata(String key) {
|
||||||
CachedContent cachedContent = get(key);
|
@Nullable CachedContent cachedContent = get(key);
|
||||||
return cachedContent != null ? cachedContent.getMetadata() : DefaultContentMetadata.EMPTY;
|
return cachedContent != null ? cachedContent.getMetadata() : DefaultContentMetadata.EMPTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -358,7 +364,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||||||
* returns the smallest unused non-negative integer.
|
* returns the smallest unused non-negative integer.
|
||||||
*/
|
*/
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
/* package */ static int getNewId(SparseArray<String> idToKey) {
|
/* package */ static int getNewId(SparseArray<@NullableType String> idToKey) {
|
||||||
int size = idToKey.size();
|
int size = idToKey.size();
|
||||||
int id = size == 0 ? 0 : (idToKey.keyAt(size - 1) + 1);
|
int id = size == 0 ? 0 : (idToKey.keyAt(size - 1) + 1);
|
||||||
if (id < 0) { // In case if we pass max int value.
|
if (id < 0) { // In case if we pass max int value.
|
||||||
@ -512,8 +518,9 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||||||
@Nullable private ReusableBufferedOutputStream bufferedOutputStream;
|
@Nullable private ReusableBufferedOutputStream bufferedOutputStream;
|
||||||
|
|
||||||
public LegacyStorage(File file, @Nullable byte[] secretKey, boolean encrypt) {
|
public LegacyStorage(File file, @Nullable byte[] secretKey, boolean encrypt) {
|
||||||
Cipher cipher = null;
|
checkState(secretKey != null || !encrypt);
|
||||||
SecretKeySpec secretKeySpec = null;
|
@Nullable Cipher cipher = null;
|
||||||
|
@Nullable SecretKeySpec secretKeySpec = null;
|
||||||
if (secretKey != null) {
|
if (secretKey != null) {
|
||||||
Assertions.checkArgument(secretKey.length == 16);
|
Assertions.checkArgument(secretKey.length == 16);
|
||||||
try {
|
try {
|
||||||
@ -550,7 +557,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||||||
@Override
|
@Override
|
||||||
public void load(
|
public void load(
|
||||||
HashMap<String, CachedContent> content, SparseArray<@NullableType String> idToKey) {
|
HashMap<String, CachedContent> content, SparseArray<@NullableType String> idToKey) {
|
||||||
Assertions.checkState(!changed);
|
checkState(!changed);
|
||||||
if (!readFile(content, idToKey)) {
|
if (!readFile(content, idToKey)) {
|
||||||
content.clear();
|
content.clear();
|
||||||
idToKey.clear();
|
idToKey.clear();
|
||||||
@ -588,7 +595,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
DataInputStream input = null;
|
@Nullable DataInputStream input = null;
|
||||||
try {
|
try {
|
||||||
InputStream inputStream = new BufferedInputStream(atomicFile.openRead());
|
InputStream inputStream = new BufferedInputStream(atomicFile.openRead());
|
||||||
input = new DataInputStream(inputStream);
|
input = new DataInputStream(inputStream);
|
||||||
@ -606,7 +613,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||||||
input.readFully(initializationVector);
|
input.readFully(initializationVector);
|
||||||
IvParameterSpec ivParameterSpec = new IvParameterSpec(initializationVector);
|
IvParameterSpec ivParameterSpec = new IvParameterSpec(initializationVector);
|
||||||
try {
|
try {
|
||||||
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
|
cipher.init(Cipher.DECRYPT_MODE, castNonNull(secretKeySpec), ivParameterSpec);
|
||||||
} catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
|
} catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
|
||||||
throw new IllegalStateException(e);
|
throw new IllegalStateException(e);
|
||||||
}
|
}
|
||||||
@ -647,6 +654,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||||||
} else {
|
} else {
|
||||||
bufferedOutputStream.reset(outputStream);
|
bufferedOutputStream.reset(outputStream);
|
||||||
}
|
}
|
||||||
|
ReusableBufferedOutputStream bufferedOutputStream = this.bufferedOutputStream;
|
||||||
output = new DataOutputStream(bufferedOutputStream);
|
output = new DataOutputStream(bufferedOutputStream);
|
||||||
output.writeInt(VERSION);
|
output.writeInt(VERSION);
|
||||||
|
|
||||||
@ -655,11 +663,12 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||||||
|
|
||||||
if (encrypt) {
|
if (encrypt) {
|
||||||
byte[] initializationVector = new byte[16];
|
byte[] initializationVector = new byte[16];
|
||||||
random.nextBytes(initializationVector);
|
castNonNull(random).nextBytes(initializationVector);
|
||||||
output.write(initializationVector);
|
output.write(initializationVector);
|
||||||
IvParameterSpec ivParameterSpec = new IvParameterSpec(initializationVector);
|
IvParameterSpec ivParameterSpec = new IvParameterSpec(initializationVector);
|
||||||
try {
|
try {
|
||||||
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
|
castNonNull(cipher)
|
||||||
|
.init(Cipher.ENCRYPT_MODE, castNonNull(secretKeySpec), ivParameterSpec);
|
||||||
} catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
|
} catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
|
||||||
throw new IllegalStateException(e); // Should never happen.
|
throw new IllegalStateException(e); // Should never happen.
|
||||||
}
|
}
|
||||||
@ -762,16 +771,17 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||||||
+ " BLOB NOT NULL)";
|
+ " BLOB NOT NULL)";
|
||||||
|
|
||||||
private final DatabaseProvider databaseProvider;
|
private final DatabaseProvider databaseProvider;
|
||||||
private final SparseArray<CachedContent> pendingUpdates;
|
private final SparseArray<@NullableType CachedContent> pendingUpdates;
|
||||||
|
|
||||||
private String hexUid;
|
private @MonotonicNonNull String hexUid;
|
||||||
private String tableName;
|
private @MonotonicNonNull String tableName;
|
||||||
|
|
||||||
public static void delete(DatabaseProvider databaseProvider, long uid)
|
public static void delete(DatabaseProvider databaseProvider, long uid)
|
||||||
throws DatabaseIOException {
|
throws DatabaseIOException {
|
||||||
delete(databaseProvider, Long.toHexString(uid));
|
delete(databaseProvider, Long.toHexString(uid));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("nullness:initialization.fields.uninitialized")
|
||||||
public DatabaseStorage(DatabaseProvider databaseProvider) {
|
public DatabaseStorage(DatabaseProvider databaseProvider) {
|
||||||
this.databaseProvider = databaseProvider;
|
this.databaseProvider = databaseProvider;
|
||||||
pendingUpdates = new SparseArray<>();
|
pendingUpdates = new SparseArray<>();
|
||||||
@ -788,26 +798,26 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||||||
return VersionTable.getVersion(
|
return VersionTable.getVersion(
|
||||||
databaseProvider.getReadableDatabase(),
|
databaseProvider.getReadableDatabase(),
|
||||||
VersionTable.FEATURE_CACHE_CONTENT_METADATA,
|
VersionTable.FEATURE_CACHE_CONTENT_METADATA,
|
||||||
hexUid)
|
checkNotNull(hexUid))
|
||||||
!= VersionTable.VERSION_UNSET;
|
!= VersionTable.VERSION_UNSET;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void delete() throws DatabaseIOException {
|
public void delete() throws DatabaseIOException {
|
||||||
delete(databaseProvider, hexUid);
|
delete(databaseProvider, checkNotNull(hexUid));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void load(
|
public void load(
|
||||||
HashMap<String, CachedContent> content, SparseArray<@NullableType String> idToKey)
|
HashMap<String, CachedContent> content, SparseArray<@NullableType String> idToKey)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
Assertions.checkState(pendingUpdates.size() == 0);
|
checkState(pendingUpdates.size() == 0);
|
||||||
try {
|
try {
|
||||||
int version =
|
int version =
|
||||||
VersionTable.getVersion(
|
VersionTable.getVersion(
|
||||||
databaseProvider.getReadableDatabase(),
|
databaseProvider.getReadableDatabase(),
|
||||||
VersionTable.FEATURE_CACHE_CONTENT_METADATA,
|
VersionTable.FEATURE_CACHE_CONTENT_METADATA,
|
||||||
hexUid);
|
checkNotNull(hexUid));
|
||||||
if (version != TABLE_VERSION) {
|
if (version != TABLE_VERSION) {
|
||||||
SQLiteDatabase writableDatabase = databaseProvider.getWritableDatabase();
|
SQLiteDatabase writableDatabase = databaseProvider.getWritableDatabase();
|
||||||
writableDatabase.beginTransactionNonExclusive();
|
writableDatabase.beginTransactionNonExclusive();
|
||||||
@ -871,7 +881,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||||||
writableDatabase.beginTransactionNonExclusive();
|
writableDatabase.beginTransactionNonExclusive();
|
||||||
try {
|
try {
|
||||||
for (int i = 0; i < pendingUpdates.size(); i++) {
|
for (int i = 0; i < pendingUpdates.size(); i++) {
|
||||||
CachedContent cachedContent = pendingUpdates.valueAt(i);
|
@Nullable CachedContent cachedContent = pendingUpdates.valueAt(i);
|
||||||
if (cachedContent == null) {
|
if (cachedContent == null) {
|
||||||
deleteRow(writableDatabase, pendingUpdates.keyAt(i));
|
deleteRow(writableDatabase, pendingUpdates.keyAt(i));
|
||||||
} else {
|
} else {
|
||||||
@ -906,7 +916,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||||||
return databaseProvider
|
return databaseProvider
|
||||||
.getReadableDatabase()
|
.getReadableDatabase()
|
||||||
.query(
|
.query(
|
||||||
tableName,
|
checkNotNull(tableName),
|
||||||
COLUMNS,
|
COLUMNS,
|
||||||
/* selection= */ null,
|
/* selection= */ null,
|
||||||
/* selectionArgs= */ null,
|
/* selectionArgs= */ null,
|
||||||
@ -917,13 +927,17 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||||||
|
|
||||||
private void initializeTable(SQLiteDatabase writableDatabase) throws DatabaseIOException {
|
private void initializeTable(SQLiteDatabase writableDatabase) throws DatabaseIOException {
|
||||||
VersionTable.setVersion(
|
VersionTable.setVersion(
|
||||||
writableDatabase, VersionTable.FEATURE_CACHE_CONTENT_METADATA, hexUid, TABLE_VERSION);
|
writableDatabase,
|
||||||
dropTable(writableDatabase, tableName);
|
VersionTable.FEATURE_CACHE_CONTENT_METADATA,
|
||||||
|
checkNotNull(hexUid),
|
||||||
|
TABLE_VERSION);
|
||||||
|
dropTable(writableDatabase, checkNotNull(tableName));
|
||||||
writableDatabase.execSQL("CREATE TABLE " + tableName + " " + TABLE_SCHEMA);
|
writableDatabase.execSQL("CREATE TABLE " + tableName + " " + TABLE_SCHEMA);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void deleteRow(SQLiteDatabase writableDatabase, int key) {
|
private void deleteRow(SQLiteDatabase writableDatabase, int key) {
|
||||||
writableDatabase.delete(tableName, WHERE_ID_EQUALS, new String[] {Integer.toString(key)});
|
writableDatabase.delete(
|
||||||
|
checkNotNull(tableName), WHERE_ID_EQUALS, new String[] {Integer.toString(key)});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addOrUpdateRow(SQLiteDatabase writableDatabase, CachedContent cachedContent)
|
private void addOrUpdateRow(SQLiteDatabase writableDatabase, CachedContent cachedContent)
|
||||||
@ -936,7 +950,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||||||
values.put(COLUMN_ID, cachedContent.id);
|
values.put(COLUMN_ID, cachedContent.id);
|
||||||
values.put(COLUMN_KEY, cachedContent.key);
|
values.put(COLUMN_KEY, cachedContent.key);
|
||||||
values.put(COLUMN_METADATA, data);
|
values.put(COLUMN_METADATA, data);
|
||||||
writableDatabase.replaceOrThrow(tableName, /* nullColumnHack= */ null, values);
|
writableDatabase.replaceOrThrow(checkNotNull(tableName), /* nullColumnHack= */ null, values);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void delete(DatabaseProvider databaseProvider, String hexUid)
|
private static void delete(DatabaseProvider databaseProvider, String hexUid)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user