5

一般的な仮定

そのため、proguard を使用してログ ステートメントをコードから削除する方法について多くのことを発見しました。基本的に、すべて -assumenosideeffects と一緒に ${sdk.dir}/tools/proguard/proguard-android-optimize.txt 構成を使用すると、うまくいきます。私の理解では、いくつかのことを行うのと同じバイトコードを取得することでした

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

別名、doSomeExpensiveStuff() への呼び出しを apk から削除すると仮定しました。

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

2 に答える 2

1

プロガードは、新しいSlooowインスタンスの作成が副作用であると考えているようです。proguard が機能するバイトコード レベルでは、基本的に次の違いはありません。

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

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

したがって、proguard は を見てLog.d、それを取り除きますが、新しいSloooowインスタンスの作成を取り除くわけではありません。

プロガードに副作用がないことを具体的に伝えずに、 Sloooow() の作成を一般的に取り除く良い方法は考えられません。(それがコンストラクターでも可能かどうかはわかりません)

于 2012-10-31T07:14:26.567 に答える
0

答えはわかりませんが、コンパイラーによって完全に取り除かれることfinal static boolean DEBUG = falseになると思いますif(D) { Log.d(...) }

于 2012-10-31T06:21:34.790 に答える