- Android Gradle Plugin 3.5.1
- Gradle 5.6.2
- R8 is enabled and minifyEnabled=true
- R8 version 1.5.68 (build fe9439236985bdb8b4d51a186f9dc0bd3a2fa669 from go/r8bot (luci-r8-ci-archive-0-xz51))
- applymapping is configured in proguard rule
The Java code
package com.sample.r8bugtest;
public interface TestClinit {
Throwable t = new Throwable();
//the <clinit> will be obfuscated when there is an applymapping rule in the proguard rule, but it should not be obfuscated actually.
//Excetion (Method(Lcom/sample/r8bugtest/TestClinit;.a) is marked constructor, but doesn't match name) will be thrown in runtime.
}
The proguard-rules.pro file content
-keep class com.sample.r8bugtest.TestClinit {*;}
-applymapping mapping.txt
The mapping.txt file is empty.
# nothing here
Now run ./gradlew :bug1:assembleRelease
The mapping file content generated by r8
# compiler: R8
# compiler_version: 1.5.68
# min_api: 16
# pg_map_id: 587a5bf
com.sample.r8bugtest.TestClinit -> com.sample.r8bugtest.TestClinit:
void <clinit>() -> a
The smali code
.class public interface abstract Lcom/sample/r8bugtest/TestClinit;
.super Ljava/lang/Object;
.source ""
# static fields
.field public static final t:Ljava/lang/Throwable;
# direct methods
.method static constructor a()V
.registers 1
new-instance v0, Ljava/lang/Throwable;
invoke-direct {v0}, Ljava/lang/Throwable;-><init>()V
sput-object v0, Lcom/sample/r8bugtest/TestClinit;->t:Ljava/lang/Throwable;
return-void
.end method
The <clinit> will be obfuscated when there is an applymapping rule in the proguard rule, but it should not be obfuscated actually. Excetion (Method(Lcom/sample/r8bugtest/TestClinit;.a) is marked constructor, but doesn't match name) will be thrown in runtime.
There are two compiled jars in runtime classpath in bug2/runtime dir called flutter.jar and video_plugin.jar. And There is a compiled jar in compileOnly classpath in bug2/compileOnly dir called palyer_sdk.jar
The gradle dependency is
dependencies {
implementation fileTree(dir: 'runtime', include: ['*.jar'])
compileOnly fileTree(dir: 'compileOnly', include: ['*.jar'])
}
The proguard-rules.pro file content
-keep class io.flutter.** {*;}
-keep class com.vdian.flutter.vd_video_player.VdVideoPlayerPlugin {*;}
-applymapping mapping.txt
The mapping.txt file content
com.vdian.android.lib.vdplayer.player.IMediaPlayer -> com.vdian.android.lib.vdplayer.player.IMediaPlayer:
com.vdian.android.lib.vdplayer.player.IMediaPlayer$OnBufferingUpdateListener -> com.vdian.android.lib.vdplayer.player.IMediaPlayer$OnBufferingUpdateListener:
Now run ./gradlew :bug2:assembleRelease
The constructor code in class com.vdian.flutter.vd_video_player.VideoPlayer
which is in video_plugin.jar file
import com.vdian.android.lib.vdplayer.player.IMediaPlayer;
import com.vdian.android.lib.vdplayer.player.VDMediaDataSource;
import com.vdian.android.lib.vdplayer.player.IMediaPlayer.OnBufferingUpdateListener;
import com.vdian.android.lib.vdplayer.player.IMediaPlayer.OnCompletionListener;
import com.vdian.android.lib.vdplayer.player.IMediaPlayer.OnErrorListener;
import com.vdian.android.lib.vdplayer.player.IMediaPlayer.OnPreparedListener;
public class VideoPlayer {
private final IMediaPlayer mediaPlayer;
private final EventChannel eventChannel;
private final SurfaceTextureEntry textureEntry;
private Surface surface;
private boolean isInitialized = false;
private QueuingEventSink eventSink = new QueuingEventSink();
public VideoPlayer(Context context, IMediaPlayer mediaPlayer, EventChannel eventChannel, SurfaceTextureEntry textureEntry, String dataSource, Result result) {
this.eventChannel = eventChannel;
this.mediaPlayer = mediaPlayer;
this.textureEntry = textureEntry;
Uri uri = Uri.parse(dataSource);
try {
mediaPlayer.setDataSource(context, new VDMediaDataSource(uri));
} catch (IOException var9) {
var9.printStackTrace();
}
this.setupVideoPlayer(eventChannel, result);
}
}
com.vdian.flutter.vd_video_player.VideoPlayer
reference a class com.vdian.android.lib.vdplayer.player.IMediaPlayer
which is in the play_sdk.jar in compileOnly classpath.
Actually com.vdian.android.lib.vdplayer.player.IMediaPlayer
should not be obfuscated because it's just be provided and it's configured with mapping rule com.vdian.android.lib.vdplayer.player.IMediaPlayer -> com.vdian.android.lib.vdplayer.player.IMediaPlayer
in the mapping.txt.
The mapping file content generated by r8(only part of it)
com.vdian.flutter.vd_video_player.VideoPlayer -> a.a.a.a.b:
com.vdian.android.lib.vdplayer.player.IMediaPlayer mediaPlayer -> a
com.vdian.flutter.vd_video_player.QueuingEventSink eventSink -> f
io.flutter.plugin.common.EventChannel eventChannel -> b
boolean isInitialized -> e
android.view.Surface surface -> d
io.flutter.view.TextureRegistry$SurfaceTextureEntry textureEntry -> c
com.vdian.flutter.vd_video_player.QueuingEventSink access$000(com.vdian.flutter.vd_video_player.VideoPlayer) -> a
boolean access$102(com.vdian.flutter.vd_video_player.VideoPlayer,boolean) -> a
void access$300(com.vdian.flutter.vd_video_player.VideoPlayer,int) -> a
void dispose() -> a
void seekTo(int) -> a
void setLooping(boolean) -> a
void setVolume(double) -> a
void setupVideoPlayer(io.flutter.plugin.common.EventChannel,io.flutter.plugin.common.MethodChannel$Result) -> a
boolean access$100(com.vdian.flutter.vd_video_player.VideoPlayer) -> b
long getPosition() -> b
void sendBufferingUpdate(int) -> b
void access$200(com.vdian.flutter.vd_video_player.VideoPlayer) -> c
boolean isPlaying() -> c
void pause() -> d
void play() -> e
void sendInitialized() -> f
We found the class com.vdian.flutter.vd_video_player.VideoPlayer
has been obfuscated to a.a.a.a.b
The class a.a.a.a.b
smali code generated by r8(only part of it)
.class public La/a/a/a/b;
.super Ljava/lang/Object;
.source ""
# direct methods
.method public constructor <init>(Landroid/content/Context;Lcom/vdian/android/lib/vdplayer/player/a;Lio/flutter/plugin/common/EventChannel;Lio/flutter/view/TextureRegistry$SurfaceTextureEntry;Ljava/lang/String;Lio/flutter/plugin/common/MethodChannel$Result;)V
.registers 8
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
const/4 v0, 0x0
iput-boolean v0, p0, La/a/a/a/b;->e:Z
new-instance v0, La/a/a/a/a;
invoke-direct {v0}, La/a/a/a/a;-><init>()V
iput-object v0, p0, La/a/a/a/b;->f:La/a/a/a/a;
iput-object p3, p0, La/a/a/a/b;->b:Lio/flutter/plugin/common/EventChannel;
iput-object p2, p0, La/a/a/a/b;->a:Lcom/vdian/android/lib/vdplayer/player/a;
iput-object p4, p0, La/a/a/a/b;->c:Lio/flutter/view/TextureRegistry$SurfaceTextureEntry;
invoke-static {p5}, Landroid/net/Uri;->parse(Ljava/lang/String;)Landroid/net/Uri;
move-result-object p4
:try_start_17
new-instance p5, Lcom/vdian/android/lib/vdplayer/player/VDMediaDataSource;
invoke-direct {p5, p4}, Lcom/vdian/android/lib/vdplayer/player/VDMediaDataSource;-><init>(Landroid/net/Uri;)V
invoke-interface {p2, p1, p5}, Lcom/vdian/android/lib/vdplayer/player/a;->setDataSource(Landroid/content/Context;Lcom/vdian/android/lib/vdplayer/player/VDMediaDataSource;)V
:try_end_1f
.catch Ljava/io/IOException; {:try_start_17 .. :try_end_1f} :catch_20
goto :goto_24
:catch_20
move-exception p1
invoke-virtual {p1}, Ljava/io/IOException;->printStackTrace()V
:goto_24
invoke-direct {p0, p3, p6}, La/a/a/a/b;->a(Lio/flutter/plugin/common/EventChannel;Lio/flutter/plugin/common/MethodChannel$Result;)V
return-void
.end method
com.vdian.android.lib.vdplayer.player.IMediaPlayer.setDataSource
is be obfuscated to com.vdian.android.lib.vdplayer.player.a.setDataSource
but there is a mapping rule in mapping file
com.vdian.android.lib.vdplayer.player.IMediaPlayer -> com.vdian.android.lib.vdplayer.player.IMediaPlayer
All of these bugs happened when applymapping is configured in proguard rule.