From e4e743a35f001ebfae6eef69de08a66432a0da10 Mon Sep 17 00:00:00 2001 From: tonihei Date: Wed, 1 Jul 2020 09:44:49 +0100 Subject: [PATCH] Fix remaining common module nullness issues. PiperOrigin-RevId: 319183621 --- .../exoplayer2/ext/opus/OpusDecoder.java | 34 ++++++++---- .../exoplayer2/ext/vp9/VpxDecoder.java | 23 +++++--- .../com/google/android/exoplayer2/Format.java | 3 +- .../exoplayer2/decoder/CryptoInfo.java | 14 ++--- .../exoplayer2/util/CopyOnWriteMultiset.java | 4 +- .../android/exoplayer2/util/NalUnitUtil.java | 54 +++++++++---------- .../google/android/exoplayer2/util/Util.java | 5 ++ .../exoplayer2/util/NalUnitUtilTest.java | 10 ++-- .../AsynchronousMediaCodecBufferEnqueuer.java | 15 +++--- 9 files changed, 100 insertions(+), 62 deletions(-) diff --git a/extensions/opus/src/main/java/com/google/android/exoplayer2/ext/opus/OpusDecoder.java b/extensions/opus/src/main/java/com/google/android/exoplayer2/ext/opus/OpusDecoder.java index c82636ca5a..e082ab46b1 100644 --- a/extensions/opus/src/main/java/com/google/android/exoplayer2/ext/opus/OpusDecoder.java +++ b/extensions/opus/src/main/java/com/google/android/exoplayer2/ext/opus/OpusDecoder.java @@ -23,6 +23,7 @@ import com.google.android.exoplayer2.decoder.SimpleDecoder; import com.google.android.exoplayer2.decoder.SimpleOutputBuffer; import com.google.android.exoplayer2.drm.DecryptionException; import com.google.android.exoplayer2.drm.ExoMediaCrypto; +import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Util; import java.nio.ByteBuffer; import java.nio.ByteOrder; @@ -166,13 +167,28 @@ import java.util.List; } ByteBuffer inputData = Util.castNonNull(inputBuffer.data); CryptoInfo cryptoInfo = inputBuffer.cryptoInfo; - int result = inputBuffer.isEncrypted() - ? opusSecureDecode(nativeDecoderContext, inputBuffer.timeUs, inputData, inputData.limit(), - outputBuffer, SAMPLE_RATE, exoMediaCrypto, cryptoInfo.mode, - cryptoInfo.key, cryptoInfo.iv, cryptoInfo.numSubSamples, - cryptoInfo.numBytesOfClearData, cryptoInfo.numBytesOfEncryptedData) - : opusDecode(nativeDecoderContext, inputBuffer.timeUs, inputData, inputData.limit(), - outputBuffer); + int result = + inputBuffer.isEncrypted() + ? opusSecureDecode( + nativeDecoderContext, + inputBuffer.timeUs, + inputData, + inputData.limit(), + outputBuffer, + SAMPLE_RATE, + exoMediaCrypto, + cryptoInfo.mode, + Assertions.checkNotNull(cryptoInfo.key), + Assertions.checkNotNull(cryptoInfo.iv), + cryptoInfo.numSubSamples, + cryptoInfo.numBytesOfClearData, + cryptoInfo.numBytesOfEncryptedData) + : opusDecode( + nativeDecoderContext, + inputBuffer.timeUs, + inputData, + inputData.limit(), + outputBuffer); if (result < 0) { if (result == DRM_ERROR) { String message = "Drm error: " + opusGetErrorMessage(nativeDecoderContext); @@ -253,8 +269,8 @@ import java.util.List; byte[] key, byte[] iv, int numSubSamples, - int[] numBytesOfClearData, - int[] numBytesOfEncryptedData); + @Nullable int[] numBytesOfClearData, + @Nullable int[] numBytesOfEncryptedData); private native void opusClose(long decoder); private native void opusReset(long decoder); diff --git a/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/VpxDecoder.java b/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/VpxDecoder.java index 22086cd74d..ce0873ad40 100644 --- a/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/VpxDecoder.java +++ b/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/VpxDecoder.java @@ -124,11 +124,20 @@ import java.nio.ByteBuffer; ByteBuffer inputData = Util.castNonNull(inputBuffer.data); int inputSize = inputData.limit(); CryptoInfo cryptoInfo = inputBuffer.cryptoInfo; - final long result = inputBuffer.isEncrypted() - ? vpxSecureDecode(vpxDecContext, inputData, inputSize, exoMediaCrypto, - cryptoInfo.mode, cryptoInfo.key, cryptoInfo.iv, cryptoInfo.numSubSamples, - cryptoInfo.numBytesOfClearData, cryptoInfo.numBytesOfEncryptedData) - : vpxDecode(vpxDecContext, inputData, inputSize); + final long result = + inputBuffer.isEncrypted() + ? vpxSecureDecode( + vpxDecContext, + inputData, + inputSize, + exoMediaCrypto, + cryptoInfo.mode, + Assertions.checkNotNull(cryptoInfo.key), + Assertions.checkNotNull(cryptoInfo.iv), + cryptoInfo.numSubSamples, + cryptoInfo.numBytesOfClearData, + cryptoInfo.numBytesOfEncryptedData) + : vpxDecode(vpxDecContext, inputData, inputSize); if (result != NO_ERROR) { if (result == DRM_ERROR) { String message = "Drm error: " + vpxGetErrorMessage(vpxDecContext); @@ -207,8 +216,8 @@ import java.nio.ByteBuffer; byte[] key, byte[] iv, int numSubSamples, - int[] numBytesOfClearData, - int[] numBytesOfEncryptedData); + @Nullable int[] numBytesOfClearData, + @Nullable int[] numBytesOfEncryptedData); private native int vpxGetFrame(long context, VideoDecoderOutputBuffer outputBuffer); diff --git a/library/common/src/main/java/com/google/android/exoplayer2/Format.java b/library/common/src/main/java/com/google/android/exoplayer2/Format.java index 6ff41d0c72..6053dbf77e 100644 --- a/library/common/src/main/java/com/google/android/exoplayer2/Format.java +++ b/library/common/src/main/java/com/google/android/exoplayer2/Format.java @@ -21,6 +21,7 @@ import androidx.annotation.Nullable; import com.google.android.exoplayer2.drm.DrmInitData; import com.google.android.exoplayer2.drm.ExoMediaCrypto; import com.google.android.exoplayer2.metadata.Metadata; +import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.video.ColorInfo; @@ -1309,7 +1310,7 @@ public final class Format implements Parcelable { int initializationDataSize = in.readInt(); initializationData = new ArrayList<>(initializationDataSize); for (int i = 0; i < initializationDataSize; i++) { - initializationData.add(in.createByteArray()); + initializationData.add(Assertions.checkNotNull(in.createByteArray())); } drmInitData = in.readParcelable(DrmInitData.class.getClassLoader()); subsampleOffsetUs = in.readLong(); diff --git a/library/common/src/main/java/com/google/android/exoplayer2/decoder/CryptoInfo.java b/library/common/src/main/java/com/google/android/exoplayer2/decoder/CryptoInfo.java index 1c52abc476..7eaab6ae1d 100644 --- a/library/common/src/main/java/com/google/android/exoplayer2/decoder/CryptoInfo.java +++ b/library/common/src/main/java/com/google/android/exoplayer2/decoder/CryptoInfo.java @@ -15,8 +15,10 @@ */ package com.google.android.exoplayer2.decoder; +import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Util; /** @@ -30,13 +32,13 @@ public final class CryptoInfo { * * @see android.media.MediaCodec.CryptoInfo#iv */ - public byte[] iv; + @Nullable public byte[] iv; /** * The 16 byte key id. * * @see android.media.MediaCodec.CryptoInfo#key */ - public byte[] key; + @Nullable public byte[] key; /** * The type of encryption that has been applied. Must be one of the {@link C.CryptoMode} values. * @@ -49,14 +51,14 @@ public final class CryptoInfo { * * @see android.media.MediaCodec.CryptoInfo#numBytesOfClearData */ - public int[] numBytesOfClearData; + @Nullable public int[] numBytesOfClearData; /** * The number of trailing encrypted bytes in each sub-sample. If null, all bytes are treated as * clear and {@link #numBytesOfClearData} must be specified. * * @see android.media.MediaCodec.CryptoInfo#numBytesOfEncryptedData */ - public int[] numBytesOfEncryptedData; + @Nullable public int[] numBytesOfEncryptedData; /** * The number of subSamples that make up the buffer's contents. * @@ -73,7 +75,7 @@ public final class CryptoInfo { public int clearBlocks; private final android.media.MediaCodec.CryptoInfo frameworkCryptoInfo; - private final PatternHolderV24 patternHolder; + @Nullable private final PatternHolderV24 patternHolder; public CryptoInfo() { frameworkCryptoInfo = new android.media.MediaCodec.CryptoInfo(); @@ -102,7 +104,7 @@ public final class CryptoInfo { frameworkCryptoInfo.iv = iv; frameworkCryptoInfo.mode = mode; if (Util.SDK_INT >= 24) { - patternHolder.set(encryptedBlocks, clearBlocks); + Assertions.checkNotNull(patternHolder).set(encryptedBlocks, clearBlocks); } } diff --git a/library/common/src/main/java/com/google/android/exoplayer2/util/CopyOnWriteMultiset.java b/library/common/src/main/java/com/google/android/exoplayer2/util/CopyOnWriteMultiset.java index e8eb0d0df9..505ff55cbe 100644 --- a/library/common/src/main/java/com/google/android/exoplayer2/util/CopyOnWriteMultiset.java +++ b/library/common/src/main/java/com/google/android/exoplayer2/util/CopyOnWriteMultiset.java @@ -41,7 +41,9 @@ import java.util.Set; * * @param The type of element being stored. */ -public final class CopyOnWriteMultiset implements Iterable { +// Intentionally extending @NonNull-by-default Object to disallow @Nullable E types. +@SuppressWarnings("TypeParameterExplicitlyExtendsObject") +public final class CopyOnWriteMultiset implements Iterable { private final Object lock; diff --git a/library/common/src/main/java/com/google/android/exoplayer2/util/NalUnitUtil.java b/library/common/src/main/java/com/google/android/exoplayer2/util/NalUnitUtil.java index 05585d5301..6edbecf1ea 100644 --- a/library/common/src/main/java/com/google/android/exoplayer2/util/NalUnitUtil.java +++ b/library/common/src/main/java/com/google/android/exoplayer2/util/NalUnitUtil.java @@ -431,18 +431,18 @@ public final class NalUnitUtil { return endOffset; } - if (prefixFlags != null) { - if (prefixFlags[0]) { - clearPrefixFlags(prefixFlags); - return startOffset - 3; - } else if (length > 1 && prefixFlags[1] && data[startOffset] == 1) { - clearPrefixFlags(prefixFlags); - return startOffset - 2; - } else if (length > 2 && prefixFlags[2] && data[startOffset] == 0 - && data[startOffset + 1] == 1) { - clearPrefixFlags(prefixFlags); - return startOffset - 1; - } + if (prefixFlags[0]) { + clearPrefixFlags(prefixFlags); + return startOffset - 3; + } else if (length > 1 && prefixFlags[1] && data[startOffset] == 1) { + clearPrefixFlags(prefixFlags); + return startOffset - 2; + } else if (length > 2 + && prefixFlags[2] + && data[startOffset] == 0 + && data[startOffset + 1] == 1) { + clearPrefixFlags(prefixFlags); + return startOffset - 1; } int limit = endOffset - 1; @@ -453,9 +453,7 @@ public final class NalUnitUtil { // There isn't a NAL prefix here, or at the next two positions. Do nothing and let the // loop advance the index by three. } else if (data[i - 2] == 0 && data[i - 1] == 0 && data[i] == 1) { - if (prefixFlags != null) { - clearPrefixFlags(prefixFlags); - } + clearPrefixFlags(prefixFlags); return i - 2; } else { // There isn't a NAL prefix here, but there might be at the next position. We should @@ -464,18 +462,20 @@ public final class NalUnitUtil { } } - if (prefixFlags != null) { - // True if the last three bytes in the data seen so far are {0,0,1}. - prefixFlags[0] = length > 2 - ? (data[endOffset - 3] == 0 && data[endOffset - 2] == 0 && data[endOffset - 1] == 1) - : length == 2 ? (prefixFlags[2] && data[endOffset - 2] == 0 && data[endOffset - 1] == 1) - : (prefixFlags[1] && data[endOffset - 1] == 1); - // True if the last two bytes in the data seen so far are {0,0}. - prefixFlags[1] = length > 1 ? data[endOffset - 2] == 0 && data[endOffset - 1] == 0 - : prefixFlags[2] && data[endOffset - 1] == 0; - // True if the last byte in the data seen so far is {0}. - prefixFlags[2] = data[endOffset - 1] == 0; - } + // True if the last three bytes in the data seen so far are {0,0,1}. + prefixFlags[0] = + length > 2 + ? (data[endOffset - 3] == 0 && data[endOffset - 2] == 0 && data[endOffset - 1] == 1) + : length == 2 + ? (prefixFlags[2] && data[endOffset - 2] == 0 && data[endOffset - 1] == 1) + : (prefixFlags[1] && data[endOffset - 1] == 1); + // True if the last two bytes in the data seen so far are {0,0}. + prefixFlags[1] = + length > 1 + ? data[endOffset - 2] == 0 && data[endOffset - 1] == 0 + : prefixFlags[2] && data[endOffset - 1] == 0; + // True if the last byte in the data seen so far is {0}. + prefixFlags[2] = data[endOffset - 1] == 0; return endOffset; } diff --git a/library/common/src/main/java/com/google/android/exoplayer2/util/Util.java b/library/common/src/main/java/com/google/android/exoplayer2/util/Util.java index b9e3f86096..0afeaffdaf 100644 --- a/library/common/src/main/java/com/google/android/exoplayer2/util/Util.java +++ b/library/common/src/main/java/com/google/android/exoplayer2/util/Util.java @@ -1937,6 +1937,8 @@ public final class Util { * @param context A context to access the connectivity manager. * @return The {@link C.NetworkType} of the current network connection. */ + // Intentional null check to guard against user input. + @SuppressWarnings("known.nonnull") @C.NetworkType public static int getNetworkType(Context context) { if (context == null) { @@ -1944,6 +1946,7 @@ public final class Util { return C.NETWORK_TYPE_UNKNOWN; } NetworkInfo networkInfo; + @Nullable ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); if (connectivityManager == null) { @@ -1983,6 +1986,7 @@ public final class Util { */ public static String getCountryCode(@Nullable Context context) { if (context != null) { + @Nullable TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); if (telephonyManager != null) { @@ -2062,6 +2066,7 @@ public final class Util { */ public static boolean isTv(Context context) { // See https://developer.android.com/training/tv/start/hardware.html#runtime-check. + @Nullable UiModeManager uiModeManager = (UiModeManager) context.getApplicationContext().getSystemService(UI_MODE_SERVICE); return uiModeManager != null diff --git a/library/common/src/test/java/com/google/android/exoplayer2/util/NalUnitUtilTest.java b/library/common/src/test/java/com/google/android/exoplayer2/util/NalUnitUtilTest.java index 365cff8aff..5226a42c76 100644 --- a/library/common/src/test/java/com/google/android/exoplayer2/util/NalUnitUtilTest.java +++ b/library/common/src/test/java/com/google/android/exoplayer2/util/NalUnitUtilTest.java @@ -40,19 +40,19 @@ public final class NalUnitUtilTest { byte[] data = buildTestData(); // Should find NAL unit. - int result = NalUnitUtil.findNalUnit(data, 0, data.length, null); + int result = NalUnitUtil.findNalUnit(data, 0, data.length, new boolean[3]); assertThat(result).isEqualTo(TEST_NAL_POSITION); // Should find NAL unit whose prefix ends one byte before the limit. - result = NalUnitUtil.findNalUnit(data, 0, TEST_NAL_POSITION + 4, null); + result = NalUnitUtil.findNalUnit(data, 0, TEST_NAL_POSITION + 4, new boolean[3]); assertThat(result).isEqualTo(TEST_NAL_POSITION); // Shouldn't find NAL unit whose prefix ends at the limit (since the limit is exclusive). - result = NalUnitUtil.findNalUnit(data, 0, TEST_NAL_POSITION + 3, null); + result = NalUnitUtil.findNalUnit(data, 0, TEST_NAL_POSITION + 3, new boolean[3]); assertThat(result).isEqualTo(TEST_NAL_POSITION + 3); // Should find NAL unit whose prefix starts at the offset. - result = NalUnitUtil.findNalUnit(data, TEST_NAL_POSITION, data.length, null); + result = NalUnitUtil.findNalUnit(data, TEST_NAL_POSITION, data.length, new boolean[3]); assertThat(result).isEqualTo(TEST_NAL_POSITION); // Shouldn't find NAL unit whose prefix starts one byte past the offset. - result = NalUnitUtil.findNalUnit(data, TEST_NAL_POSITION + 1, data.length, null); + result = NalUnitUtil.findNalUnit(data, TEST_NAL_POSITION + 1, data.length, new boolean[3]); assertThat(result).isEqualTo(data.length); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/AsynchronousMediaCodecBufferEnqueuer.java b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/AsynchronousMediaCodecBufferEnqueuer.java index 42590eed8a..dd9a086446 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/AsynchronousMediaCodecBufferEnqueuer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/AsynchronousMediaCodecBufferEnqueuer.java @@ -16,11 +16,14 @@ package com.google.android.exoplayer2.mediacodec; +import static com.google.android.exoplayer2.util.Assertions.checkNotNull; + import android.media.MediaCodec; import android.os.Handler; import android.os.HandlerThread; import android.os.Message; import androidx.annotation.GuardedBy; +import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; import androidx.annotation.VisibleForTesting; import com.google.android.exoplayer2.C; @@ -292,8 +295,6 @@ class AsynchronousMediaCodecBufferEnqueuer implements MediaCodecInputBufferEnque } /** Performs a deep copy of {@code cryptoInfo} to {@code frameworkCryptoInfo}. */ - // TODO: Remove suppression [internal b/78934030]. - @SuppressWarnings("nullness:argument.type.incompatible") private static void copy( CryptoInfo cryptoInfo, android.media.MediaCodec.CryptoInfo frameworkCryptoInfo) { // Update frameworkCryptoInfo fields directly because CryptoInfo.set performs an unnecessary @@ -303,8 +304,8 @@ class AsynchronousMediaCodecBufferEnqueuer implements MediaCodecInputBufferEnque copy(cryptoInfo.numBytesOfClearData, frameworkCryptoInfo.numBytesOfClearData); frameworkCryptoInfo.numBytesOfEncryptedData = copy(cryptoInfo.numBytesOfEncryptedData, frameworkCryptoInfo.numBytesOfEncryptedData); - frameworkCryptoInfo.key = copy(cryptoInfo.key, frameworkCryptoInfo.key); - frameworkCryptoInfo.iv = copy(cryptoInfo.iv, frameworkCryptoInfo.iv); + frameworkCryptoInfo.key = checkNotNull(copy(cryptoInfo.key, frameworkCryptoInfo.key)); + frameworkCryptoInfo.iv = checkNotNull(copy(cryptoInfo.iv, frameworkCryptoInfo.iv)); frameworkCryptoInfo.mode = cryptoInfo.mode; if (Util.SDK_INT >= 24) { android.media.MediaCodec.CryptoInfo.Pattern pattern = @@ -321,7 +322,8 @@ class AsynchronousMediaCodecBufferEnqueuer implements MediaCodecInputBufferEnque * @param dst The destination array, which will be reused if it's at least as long as {@code src}. * @return The copy, which may be {@code dst} if it was reused. */ - private static int[] copy(int[] src, int[] dst) { + @Nullable + private static int[] copy(@Nullable int[] src, @Nullable int[] dst) { if (src == null) { return dst; } @@ -341,7 +343,8 @@ class AsynchronousMediaCodecBufferEnqueuer implements MediaCodecInputBufferEnque * @param dst The destination array, which will be reused if it's at least as long as {@code src}. * @return The copy, which may be {@code dst} if it was reused. */ - private static byte[] copy(byte[] src, byte[] dst) { + @Nullable + private static byte[] copy(@Nullable byte[] src, @Nullable byte[] dst) { if (src == null) { return dst; }