Enable nullness test for CachedContent/CachedContentIndex

PiperOrigin-RevId: 328551668
This commit is contained in:
bachinger 2020-08-26 17:57:29 +01:00 committed by Oliver Woodman
parent 94cff6ba50
commit feb4cce2b2
2 changed files with 44 additions and 27 deletions

View File

@ -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)) {
span.file.delete(); if (span.file != null) {
span.file.delete();
}
return true; return true;
} }
return false; return false;

View File

@ -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)