Fix proguard configurations
1. When we try and load something via reflection and find the class, always throw rather than failing silently if we subsequently fail to instantiate an instance. This is indicative of a broken proguard setup, and failing silently makes it hard to spot. 2. Add library/core proguard configuration to ensure extension renderer constructors that we access via reflection are kept. 3. Add demos/main proguard configuration to ensure ImaAdsLoader constructor that we access via reflection is kept. 4. Added IMA proguard file to hopefully fix #3723, although I wasn't actually able to reproduce the issue. Issue: #3723 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=183648187
This commit is contained in:
parent
e26dc3990d
commit
1f6d161d4d
@ -27,7 +27,10 @@ android {
|
||||
release {
|
||||
shrinkResources true
|
||||
minifyEnabled true
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt')
|
||||
proguardFiles = [
|
||||
"proguard-rules.txt",
|
||||
getDefaultProguardFile('proguard-android.txt')
|
||||
]
|
||||
}
|
||||
debug {
|
||||
jniDebuggable = true
|
||||
|
6
demos/main/proguard-rules.txt
Normal file
6
demos/main/proguard-rules.txt
Normal file
@ -0,0 +1,6 @@
|
||||
# Proguard rules specific to the main demo app.
|
||||
|
||||
# Constructor accessed via reflection in PlayerActivity
|
||||
-keepclassmembers class com.google.android.exoplayer2.ext.ima.ImaAdsLoader {
|
||||
<init>(android.content.Context, android.net.Uri);
|
||||
}
|
@ -16,7 +16,6 @@
|
||||
package com.google.android.exoplayer2.demo;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
@ -76,6 +75,7 @@ import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
|
||||
import com.google.android.exoplayer2.upstream.HttpDataSource;
|
||||
import com.google.android.exoplayer2.util.EventLogger;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.net.CookieHandler;
|
||||
import java.net.CookieManager;
|
||||
import java.net.CookiePolicy;
|
||||
@ -353,9 +353,10 @@ public class PlayerActivity extends Activity
|
||||
releaseAdsLoader();
|
||||
loadedAdTagUri = adTagUri;
|
||||
}
|
||||
try {
|
||||
mediaSource = createAdsMediaSource(mediaSource, Uri.parse(adTagUriString));
|
||||
} catch (Exception e) {
|
||||
MediaSource adsMediaSource = createAdsMediaSource(mediaSource, Uri.parse(adTagUriString));
|
||||
if (adsMediaSource != null) {
|
||||
mediaSource = adsMediaSource;
|
||||
} else {
|
||||
showToast(R.string.ima_not_loaded);
|
||||
}
|
||||
} else {
|
||||
@ -463,39 +464,47 @@ public class PlayerActivity extends Activity
|
||||
.buildHttpDataSourceFactory(useBandwidthMeter ? BANDWIDTH_METER : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an ads media source, reusing the ads loader if one exists.
|
||||
*
|
||||
* @throws Exception Thrown if it was not possible to create an ads media source, for example, due
|
||||
* to a missing dependency.
|
||||
*/
|
||||
private MediaSource createAdsMediaSource(MediaSource mediaSource, Uri adTagUri) throws Exception {
|
||||
/** Returns an ads media source, reusing the ads loader if one exists. */
|
||||
private @Nullable MediaSource createAdsMediaSource(MediaSource mediaSource, Uri adTagUri) {
|
||||
// Load the extension source using reflection so the demo app doesn't have to depend on it.
|
||||
// The ads loader is reused for multiple playbacks, so that ad playback can resume.
|
||||
Class<?> loaderClass = Class.forName("com.google.android.exoplayer2.ext.ima.ImaAdsLoader");
|
||||
if (adsLoader == null) {
|
||||
adsLoader = (AdsLoader) loaderClass.getConstructor(Context.class, Uri.class)
|
||||
.newInstance(this, adTagUri);
|
||||
adUiViewGroup = new FrameLayout(this);
|
||||
// The demo app has a non-null overlay frame layout.
|
||||
playerView.getOverlayFrameLayout().addView(adUiViewGroup);
|
||||
}
|
||||
AdsMediaSource.MediaSourceFactory adMediaSourceFactory =
|
||||
new AdsMediaSource.MediaSourceFactory() {
|
||||
@Override
|
||||
public MediaSource createMediaSource(
|
||||
Uri uri, @Nullable Handler handler, @Nullable MediaSourceEventListener listener) {
|
||||
return PlayerActivity.this.buildMediaSource(
|
||||
uri, /* overrideExtension= */ null, handler, listener);
|
||||
}
|
||||
try {
|
||||
Class<?> loaderClass = Class.forName("com.google.android.exoplayer2.ext.ima.ImaAdsLoader");
|
||||
if (adsLoader == null) {
|
||||
// Full class names used so the LINT.IfChange rule triggers should any of the classes move.
|
||||
// LINT.IfChange
|
||||
Constructor<? extends AdsLoader> loaderConstructor =
|
||||
loaderClass
|
||||
.asSubclass(AdsLoader.class)
|
||||
.getConstructor(android.content.Context.class, android.net.Uri.class);
|
||||
// LINT.ThenChange(../../../../../../../../proguard-rules.txt)
|
||||
adsLoader = loaderConstructor.newInstance(this, adTagUri);
|
||||
adUiViewGroup = new FrameLayout(this);
|
||||
// The demo app has a non-null overlay frame layout.
|
||||
playerView.getOverlayFrameLayout().addView(adUiViewGroup);
|
||||
}
|
||||
AdsMediaSource.MediaSourceFactory adMediaSourceFactory =
|
||||
new AdsMediaSource.MediaSourceFactory() {
|
||||
@Override
|
||||
public MediaSource createMediaSource(
|
||||
Uri uri, @Nullable Handler handler, @Nullable MediaSourceEventListener listener) {
|
||||
return PlayerActivity.this.buildMediaSource(
|
||||
uri, /* overrideExtension= */ null, handler, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getSupportedTypes() {
|
||||
return new int[] {C.TYPE_DASH, C.TYPE_SS, C.TYPE_HLS, C.TYPE_OTHER};
|
||||
}
|
||||
};
|
||||
return new AdsMediaSource(
|
||||
mediaSource, adMediaSourceFactory, adsLoader, adUiViewGroup, mainHandler, eventLogger);
|
||||
@Override
|
||||
public int[] getSupportedTypes() {
|
||||
return new int[] {C.TYPE_DASH, C.TYPE_SS, C.TYPE_HLS, C.TYPE_OTHER};
|
||||
}
|
||||
};
|
||||
return new AdsMediaSource(
|
||||
mediaSource, adMediaSourceFactory, adsLoader, adUiViewGroup, mainHandler, eventLogger);
|
||||
} catch (ClassNotFoundException e) {
|
||||
// IMA extension not loaded.
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void releaseAdsLoader() {
|
||||
|
6
demos/main/src/main/proguard-rules.txt
Normal file
6
demos/main/src/main/proguard-rules.txt
Normal file
@ -0,0 +1,6 @@
|
||||
# Proguard rules specific to the main demo app.
|
||||
|
||||
# Constructor accessed via reflection in PlayerActivity
|
||||
-keepclassmembers class com.google.android.exoplayer2.ext.ima.ImaAdsLoader {
|
||||
<init>(android.content.Context, android.net.Uri);
|
||||
}
|
6
extensions/ima/proguard-rules.txt
Normal file
6
extensions/ima/proguard-rules.txt
Normal file
@ -0,0 +1,6 @@
|
||||
# Proguard rules specific to the IMA extension.
|
||||
|
||||
-keep class com.google.ads.interactivemedia.** { *; }
|
||||
-keep interface com.google.ads.interactivemedia.** { *; }
|
||||
-keep class com.google.obf.** { *; }
|
||||
-keep interface com.google.obf.** { *; }
|
6
extensions/ima/src/main/proguard-rules.txt
Normal file
6
extensions/ima/src/main/proguard-rules.txt
Normal file
@ -0,0 +1,6 @@
|
||||
# Proguard rules specific to the IMA extension.
|
||||
|
||||
-keep class com.google.ads.interactivemedia.** { *; }
|
||||
-keep interface com.google.ads.interactivemedia.** { *; }
|
||||
-keep class com.google.obf.** { *; }
|
||||
-keep interface com.google.obf.** { *; }
|
@ -21,6 +21,7 @@ android {
|
||||
defaultConfig {
|
||||
minSdkVersion project.ext.minSdkVersion
|
||||
targetSdkVersion project.ext.targetSdkVersion
|
||||
consumerProguardFiles 'proguard-rules.txt'
|
||||
}
|
||||
|
||||
// Workaround to prevent circular dependency on project :testutils.
|
||||
|
25
library/core/proguard-rules.txt
Normal file
25
library/core/proguard-rules.txt
Normal file
@ -0,0 +1,25 @@
|
||||
# Proguard rules specific to the core module.
|
||||
|
||||
# Constructors accessed via reflection in DefaultRenderersFactory
|
||||
-keepclassmembers class com.google.android.exoplayer2.ext.vp9.LibvpxVideoRenderer {
|
||||
<init>(boolean, long, android.os.Handler, com.google.android.exoplayer2.video.VideoRendererEventListener, int);
|
||||
}
|
||||
-keepclassmembers class com.google.android.exoplayer2.ext.opus.LibopusAudioRenderer {
|
||||
<init>(android.os.Handler, com.google.android.exoplayer2.audio.AudioRendererEventListener, com.google.android.exoplayer2.audio.AudioProcessor[]);
|
||||
}
|
||||
-keepclassmembers class com.google.android.exoplayer2.ext.flac.LibflacAudioRenderer {
|
||||
<init>(android.os.Handler, com.google.android.exoplayer2.audio.AudioRendererEventListener, com.google.android.exoplayer2.audio.AudioProcessor[]);
|
||||
}
|
||||
-keepclassmembers class com.google.android.exoplayer2.ext.ffmpeg.FfmpegAudioRenderer {
|
||||
<init>(android.os.Handler, com.google.android.exoplayer2.audio.AudioRendererEventListener, com.google.android.exoplayer2.audio.AudioProcessor[]);
|
||||
}
|
||||
|
||||
# Constructors accessed via reflection in DefaultExtractorsFactory
|
||||
-keepclassmembers class com.google.android.exoplayer2.ext.flac.FlacExtractor {
|
||||
<init>();
|
||||
}
|
||||
|
||||
# Constructors accessed via reflection in DefaultDataSource
|
||||
-keepclassmembers class com.google.android.exoplayer2.ext.rtmp.RtmpDataSource {
|
||||
<init>();
|
||||
}
|
@ -185,18 +185,32 @@ public class DefaultRenderersFactory implements RenderersFactory {
|
||||
}
|
||||
|
||||
try {
|
||||
Class<?> clazz =
|
||||
Class.forName("com.google.android.exoplayer2.ext.vp9.LibvpxVideoRenderer");
|
||||
Constructor<?> constructor = clazz.getConstructor(boolean.class, long.class, Handler.class,
|
||||
VideoRendererEventListener.class, int.class);
|
||||
Renderer renderer = (Renderer) constructor.newInstance(true, allowedVideoJoiningTimeMs,
|
||||
eventHandler, eventListener, MAX_DROPPED_VIDEO_FRAME_COUNT_TO_NOTIFY);
|
||||
// Full class names used for constructor args so the LINT rule triggers if any of them move.
|
||||
// LINT.IfChange
|
||||
Class<?> clazz = Class.forName("com.google.android.exoplayer2.ext.vp9.LibvpxVideoRenderer");
|
||||
Constructor<?> constructor =
|
||||
clazz.getConstructor(
|
||||
boolean.class,
|
||||
long.class,
|
||||
android.os.Handler.class,
|
||||
com.google.android.exoplayer2.video.VideoRendererEventListener.class,
|
||||
int.class);
|
||||
// LINT.ThenChange(../../../../../../../proguard-rules.txt)
|
||||
Renderer renderer =
|
||||
(Renderer)
|
||||
constructor.newInstance(
|
||||
true,
|
||||
allowedVideoJoiningTimeMs,
|
||||
eventHandler,
|
||||
eventListener,
|
||||
MAX_DROPPED_VIDEO_FRAME_COUNT_TO_NOTIFY);
|
||||
out.add(extensionRendererIndex++, renderer);
|
||||
Log.i(TAG, "Loaded LibvpxVideoRenderer.");
|
||||
} catch (ClassNotFoundException e) {
|
||||
// Expected if the app was built without the extension.
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
// The extension is present, but instantiation failed.
|
||||
throw new RuntimeException("Error instantiating VP9 extension", e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -230,48 +244,67 @@ public class DefaultRenderersFactory implements RenderersFactory {
|
||||
}
|
||||
|
||||
try {
|
||||
Class<?> clazz =
|
||||
Class.forName("com.google.android.exoplayer2.ext.opus.LibopusAudioRenderer");
|
||||
Constructor<?> constructor = clazz.getConstructor(Handler.class,
|
||||
AudioRendererEventListener.class, AudioProcessor[].class);
|
||||
Renderer renderer = (Renderer) constructor.newInstance(eventHandler, eventListener,
|
||||
audioProcessors);
|
||||
// Full class names used for constructor args so the LINT rule triggers if any of them move.
|
||||
// LINT.IfChange
|
||||
Class<?> clazz = Class.forName("com.google.android.exoplayer2.ext.opus.LibopusAudioRenderer");
|
||||
Constructor<?> constructor =
|
||||
clazz.getConstructor(
|
||||
android.os.Handler.class,
|
||||
com.google.android.exoplayer2.audio.AudioRendererEventListener.class,
|
||||
com.google.android.exoplayer2.audio.AudioProcessor[].class);
|
||||
// LINT.ThenChange(../../../../../../../proguard-rules.txt)
|
||||
Renderer renderer =
|
||||
(Renderer) constructor.newInstance(eventHandler, eventListener, audioProcessors);
|
||||
out.add(extensionRendererIndex++, renderer);
|
||||
Log.i(TAG, "Loaded LibopusAudioRenderer.");
|
||||
} catch (ClassNotFoundException e) {
|
||||
// Expected if the app was built without the extension.
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
// The extension is present, but instantiation failed.
|
||||
throw new RuntimeException("Error instantiating Opus extension", e);
|
||||
}
|
||||
|
||||
try {
|
||||
Class<?> clazz =
|
||||
Class.forName("com.google.android.exoplayer2.ext.flac.LibflacAudioRenderer");
|
||||
Constructor<?> constructor = clazz.getConstructor(Handler.class,
|
||||
AudioRendererEventListener.class, AudioProcessor[].class);
|
||||
Renderer renderer = (Renderer) constructor.newInstance(eventHandler, eventListener,
|
||||
audioProcessors);
|
||||
// Full class names used for constructor args so the LINT rule triggers if any of them move.
|
||||
// LINT.IfChange
|
||||
Class<?> clazz = Class.forName("com.google.android.exoplayer2.ext.flac.LibflacAudioRenderer");
|
||||
Constructor<?> constructor =
|
||||
clazz.getConstructor(
|
||||
android.os.Handler.class,
|
||||
com.google.android.exoplayer2.audio.AudioRendererEventListener.class,
|
||||
com.google.android.exoplayer2.audio.AudioProcessor[].class);
|
||||
// LINT.ThenChange(../../../../../../../proguard-rules.txt)
|
||||
Renderer renderer =
|
||||
(Renderer) constructor.newInstance(eventHandler, eventListener, audioProcessors);
|
||||
out.add(extensionRendererIndex++, renderer);
|
||||
Log.i(TAG, "Loaded LibflacAudioRenderer.");
|
||||
} catch (ClassNotFoundException e) {
|
||||
// Expected if the app was built without the extension.
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
// The extension is present, but instantiation failed.
|
||||
throw new RuntimeException("Error instantiating FLAC extension", e);
|
||||
}
|
||||
|
||||
try {
|
||||
// Full class names used for constructor args so the LINT rule triggers if any of them move.
|
||||
// LINT.IfChange
|
||||
Class<?> clazz =
|
||||
Class.forName("com.google.android.exoplayer2.ext.ffmpeg.FfmpegAudioRenderer");
|
||||
Constructor<?> constructor = clazz.getConstructor(Handler.class,
|
||||
AudioRendererEventListener.class, AudioProcessor[].class);
|
||||
Renderer renderer = (Renderer) constructor.newInstance(eventHandler, eventListener,
|
||||
audioProcessors);
|
||||
Constructor<?> constructor =
|
||||
clazz.getConstructor(
|
||||
android.os.Handler.class,
|
||||
com.google.android.exoplayer2.audio.AudioRendererEventListener.class,
|
||||
com.google.android.exoplayer2.audio.AudioProcessor[].class);
|
||||
// LINT.ThenChange(../../../../../../../proguard-rules.txt)
|
||||
Renderer renderer =
|
||||
(Renderer) constructor.newInstance(eventHandler, eventListener, audioProcessors);
|
||||
out.add(extensionRendererIndex++, renderer);
|
||||
Log.i(TAG, "Loaded FfmpegAudioRenderer.");
|
||||
} catch (ClassNotFoundException e) {
|
||||
// Expected if the app was built without the extension.
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
// The extension is present, but instantiation failed.
|
||||
throw new RuntimeException("Error instantiating FFmpeg extension", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -55,13 +55,17 @@ public final class DefaultExtractorsFactory implements ExtractorsFactory {
|
||||
static {
|
||||
Constructor<? extends Extractor> flacExtractorConstructor = null;
|
||||
try {
|
||||
// LINT.IfChange
|
||||
flacExtractorConstructor =
|
||||
Class.forName("com.google.android.exoplayer2.ext.flac.FlacExtractor")
|
||||
.asSubclass(Extractor.class).getConstructor();
|
||||
.asSubclass(Extractor.class)
|
||||
.getConstructor();
|
||||
// LINT.ThenChange(../../../../../../../../proguard-rules.txt)
|
||||
} catch (ClassNotFoundException e) {
|
||||
// Extractor not found.
|
||||
} catch (NoSuchMethodException e) {
|
||||
// Constructor not found.
|
||||
// Expected if the app was built without the FLAC extension.
|
||||
} catch (Exception e) {
|
||||
// The FLAC extension is present, but instantiation failed.
|
||||
throw new RuntimeException("Error instantiating FLAC extension", e);
|
||||
}
|
||||
FLAC_EXTRACTOR_CONSTRUCTOR = flacExtractorConstructor;
|
||||
}
|
||||
|
@ -21,7 +21,6 @@ import android.util.Log;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
/**
|
||||
* A {@link DataSource} that supports multiple URI schemes. The supported schemes are:
|
||||
@ -193,18 +192,16 @@ public final class DefaultDataSource implements DataSource {
|
||||
private DataSource getRtmpDataSource() {
|
||||
if (rtmpDataSource == null) {
|
||||
try {
|
||||
// LINT.IfChange
|
||||
Class<?> clazz = Class.forName("com.google.android.exoplayer2.ext.rtmp.RtmpDataSource");
|
||||
rtmpDataSource = (DataSource) clazz.getDeclaredConstructor().newInstance();
|
||||
rtmpDataSource = (DataSource) clazz.getConstructor().newInstance();
|
||||
// LINT.ThenChange(../../../../../../../../proguard-rules.txt)
|
||||
} catch (ClassNotFoundException e) {
|
||||
// Expected if the app was built without the RTMP extension.
|
||||
Log.w(TAG, "Attempting to play RTMP stream without depending on the RTMP extension");
|
||||
} catch (InstantiationException e) {
|
||||
Log.e(TAG, "Error instantiating RtmpDataSource", e);
|
||||
} catch (IllegalAccessException e) {
|
||||
Log.e(TAG, "Error instantiating RtmpDataSource", e);
|
||||
} catch (NoSuchMethodException e) {
|
||||
Log.e(TAG, "Error instantiating RtmpDataSource", e);
|
||||
} catch (InvocationTargetException e) {
|
||||
Log.e(TAG, "Error instantiating RtmpDataSource", e);
|
||||
} catch (Exception e) {
|
||||
// The RTMP extension is present, but instantiation failed.
|
||||
throw new RuntimeException("Error instantiating RTMP extension", e);
|
||||
}
|
||||
if (rtmpDataSource == null) {
|
||||
rtmpDataSource = baseDataSource;
|
||||
|
Loading…
x
Reference in New Issue
Block a user