【问题标题】:How to strip android.Log.d?如何剥离android.Log.d?
【发布时间】:2012-10-20 13:48:49
【问题描述】:

一般假设

所以我发现了很多关于使用 proguard 从代码中剥离日志语句的信息。基本上所有人都说 -assumenosideeffects 与使用 ${sdk.dir}/tools/proguard/proguard-android-optimize.txt 配置一起可以解决问题。我的理解是得到相当于做一些的字节码

if(Consts.DEBUG) Log.d("","");

我假设从我的 apk 中消除了对 doSomeExpensiveStuff() 的调用:

android.util.Log.d("Hello","World"+(new Foo().doSomeExpensiveStuff()));

我的代码

public class MainActivity extends Activity {
    private class Slooow {
        @Override
        public String toString() {
            // being slow
            try {
               Thread.sleep(5000);
            } catch(InterruptedException e) {
            }
            return "bla";
        }
    }
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d("tag", "onCreate: " + (new Slooow().toString()));
    }
}

proguard-project.txt:

-repackageclasses ''
-optimizationpasses 5
-dontobfuscate
-assumenosideeffects class android.util.Log { public * ; }

反编译的dex文件

.method public onCreate(Landroid/os/Bundle;)V
.limit registers 5
; this: v3 (Lcom/example/test/MainActivity;)
; parameter[0] : v4 (Landroid/os/Bundle;)
.line 18
    invoke-super    {v3,v4},android/app/Activity/onCreate   ; onCreate(Landroid/os/Bundle;)V
.line 19
    const/high16    v0,32515
    invoke-virtual  {v3,v0},com/example/test/MainActivity/setContentView    ; setContentView(I)V
.line 20
    new-instance    v0,java/lang/StringBuilder
    const-string    v1,"onCreate: "
    invoke-direct   {v0,v1},java/lang/StringBuilder/<init>  ; <init>(Ljava/lang/String;)V
    new-instance    v1,com/example/test/MainActivity$Slooow
    const/4 v2,0
    invoke-direct   {v1,v2},com/example/test/MainActivity$Slooow/<init> ; <init>(B)V
    invoke-virtual  {v1},com/example/test/MainActivity$Slooow/toString  ; toString()Ljava/lang/String;
    move-result-object  v1
    invoke-virtual  {v0,v1},java/lang/StringBuilder/append  ; append(Ljava/lang/String;)Ljava/lang/StringBuilder;
.line 21
    return-void 
.end method

问题

现在,如果我将它部署到我的设备上,我不会得到任何日志输出,但仍然是 5 秒睡眠(或任何其他不应该打扰我的用户的代码延迟或崩溃)。 我做错了什么?

进一步调查

Log.d("t", "h" + "w");                           // would get stripped just fine.
if(DEBUG)
  Log.d("t", "h: " + (new Slooow().toString())); // would get optimized away, too.
Log.d("t", "h" + bundle.toString());             // has just the same problem as described above.

【问题讨论】:

  • 在我使用被ant release 命令混淆的apk 时遇到同样的问题应用程序崩溃
  • @juned 这个问题与应用程序崩溃没有任何关系;)

标签: android ant proguard dex


【解决方案1】:

看起来 proguard 仍然认为创建新的 Slooow 实例是/有副作用。在 proguard 工作的字节码级别,两者之间基本上没有区别:

Log.d("tag", "onCreate: " + (new Slooow().toString()));

String temp = new Sloooow().toString();
Log.d("tag", "onCreate: " + temp);

所以 proguard 看到 Log.d 并将其删除,但它并没有删除新 Sloooow 实例的创建,因为它没有被告知没有副作用。

我想不出任何好的方法来通用地去除 Sloooow() 的创建,而没有明确告诉 proguard 它没有副作用。 (我不知道对于构造函数是否可行)

【讨论】:

  • 听起来很有道理。我需要一些睡眠,并希望得到一个更有希望的答案,它实际上可以安全地解决我的问题,但不知何故,考虑到我以 proguard 为中心的问题,我觉得没什么可补充的 :)
  • 没错。 ProGuard 不知道构造函数和 toString 方法没有副作用。例如,明确告诉 ProGuard 可能会产生不良影响,因为它(当前)将适用于所有 toString() 实现。而且 StringBuilder 方法确实有副作用,即使它们只是内部的。可能的解决方案:如果您可以创建自己的包含所有额外代码的日志记录方法,则可以在其上指定 -assumenosideeffects。
【解决方案2】:

虽然我不知道答案,但我相信拥有final static boolean DEBUG = false 将导致if(D) { Log.d(...) } 被编译器完全剥离

【讨论】:

  • 感谢 Alex 的快速回复。不幸的是,这种“开销”是不可取的,尽管它是除了丑陋的 sed 脚本之外的唯一解决方法,我现在可以想出。 (我也想明白,如果我打印一个常量字符串或在 Log(,) 调用中启动一个虚拟框,当它被明确告知认为它没有任何副作用时,为什么 proguard 会关心它。)
  • 啊,我以为你只是想剥离 logcat 输出,抱歉
猜你喜欢
  • 1970-01-01
  • 2011-12-16
  • 1970-01-01
  • 2018-01-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-25
  • 2017-04-25
相关资源
最近更新 更多