R8BugTest

Project Url: lizhangqu/R8BugTest
Introduction: reproduce r8 bug
More: Author   ReportBugs   
Tags:
Brimobile1-

Environment

  • 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

Bug1

Reproduce code

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

Bad result

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 \ 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.

Bug2

Reproduce code

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

Bad result

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.

Apps
About Me
GitHub: Trinea
Facebook: Dev Tools