2015-05-13 3 views
17

Ich erstellte eine einfache Anwendung, eine Zähler-App, die auf Knopfdruck eine ganze Zahl um eins erhöht und eine Textansicht aktualisiert. Der Code kann unten gesehen werden:Seltsame Zuordnung, TextView zu Bundle, nach dem Dekompilieren, warum?

public class MainActivity extends Activity { 
    public static int count = 0; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     final TextView textView = (TextView) findViewById(R.id.count); 
     textView.setText(Integer.toString(count)); 
     final Button button = (Button) findViewById(R.id.button); 
     button.setOnClickListener(new View.OnClickListener() { 
      @Override 
      public void onClick(View v) { 
       count++; 
       textView.setText(Integer.toString(count)); 
      } 
     }); 
    } 
    ... 
} 

Nach decompiling der gleichen App mit dex2jar und jd-gui i den folgenden Code zurückerhalten:

public class MainActivity extends Activity { 
    public static int count = 0; 

    protected void onCreate(final Bundle paramBundle) { 
     super.onCreate(paramBundle); 
     setContentView(2130903040); 
     paramBundle = (TextView)findViewById(2131296257); 
     paramBundle.setText(Integer.toString(count)); 
     ((Button)findViewById(2131296256)).setOnClickListener(new View.OnClickListener() { 
      public void onClick(View paramAnonymousView) { 
       MainActivity.count += 1; 
       paramBundle.setText(Integer.toString(MainActivity.count)); 
      } 
     }); 
    } 
    ... 
} 

Auf der folgenden Zeile:

 paramBundle = (TextView)findViewById(2131296257); 
     paramBundle.setText(Integer.toString(count)); 

Wie kann das System den textview auf den paramBundle setzen? Und warum passiert das? paramBundle ist vom Typ Bundle und TextView ist keine Unterklasse von Bundle, weiter ist das Bundle gemäß der dekompilierten Version endgültig. Hat beim Dekompilieren etwas schief gelaufen? Sind die Informationen vom Decompiler falsch oder warum erhalten wir dieses Ergebnis?


Edit:

# virtual methods 
.method protected onCreate(Landroid/os/Bundle;)V 
    .locals 3 
    .param p1, "savedInstanceState" # Landroid/os/Bundle; 

    .prologue 
    .line 17 
    invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V 

    .line 18 
    const/high16 v2, 0x7f030000 

    invoke-virtual {p0, v2}, Lcom/example/rawa/helloworld/MainActivity;->setContentView(I)V 

    .line 20 
    const v2, 0x7f090001 

    invoke-virtual {p0, v2}, Lcom/example/rawa/helloworld/MainActivity;->findViewById(I)Landroid/view/View; 

    move-result-object v1 

    check-cast v1, Landroid/widget/TextView; 

    .line 21 
    .local v1, "textView":Landroid/widget/TextView; 
    sget v2, Lcom/example/rawa/helloworld/MainActivity;->count:I 

    invoke-static {v2}, Ljava/lang/Integer;->toString(I)Ljava/lang/String; 

    move-result-object v2 

    invoke-virtual {v1, v2}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V 

    .line 22 
    const/high16 v2, 0x7f090000 

    invoke-virtual {p0, v2}, Lcom/example/rawa/helloworld/MainActivity;->findViewById(I)Landroid/view/View; 

    move-result-object v0 

    check-cast v0, Landroid/widget/Button; 

    .line 23 
    .local v0, "button":Landroid/widget/Button; 
    new-instance v2, Lcom/example/rawa/helloworld/MainActivity$1; 

    invoke-direct {v2, p0, v1}, Lcom/example/rawa/helloworld/MainActivity$1;-><init>(Lcom/example/rawa/helloworld/MainActivity;Landroid/widget/TextView;)V 

    invoke-virtual {v0, v2}, Landroid/widget/Button;->setOnClickListener(Landroid/view/View$OnClickListener;)V 

    .line 30 
    return-void 
.end method 

Ich bin definitiv kein smali Experte, nur ein Anfänger. Aber ich habe die Anwendung auch mit apktool entschlüsselt und den obigen Code erhalten. Nach meinem Verständnis wird die gespeicherteInstanz (paramBundle) in p1 (= v3) geladen und in onCreate verwendet, und in Zeile 20 oder 21 wird sie in keiner Weise verwendet. Das deutet auf einen Dekompilierungsfehler hin? Beachten Sie, dass apktool es ermöglicht, die Anwendung erneut zu erstellen und somit beim Dekompilieren keine Daten verloren gehen können.

+3

Ich mag diese Frage –

+0

@ElJazouli Froh, dass Sie es interessant fanden, bitte stimmen Sie die Frage ab, damit es mehr Aufmerksamkeit bekommt. – Rawa

+0

können Sie einen Link zu Ihrem APK veröffentlichen ich werde versuchen und es zu dekompilieren und sehen, ob es ein Dekompilierungsproblem oder was auch immer ist, weil es wirklich seltsam ist –

Antwort

2

Die Ursache ist, dass der Typ der lokalen Variablen geändert hat, aber einige Decompiler nicht korrekt behandeln.

Hier ist Ihr onCreate Code mit dex2jar dekompilierten + javap:

protected void onCreate(android.os.Bundle); 
    Code: 
     0: aload_0 
     1: aload_1 
     2: invokespecial #20     // Method android/app/Activity.onCreate:(Landroid/os/Bundle;)V 
     5: aload_0 
     6: ldc   #21     // int 2130903040 
     8: invokevirtual #25     // Method setContentView:(I)V 
     11: aload_0 
     12: ldc   #26     // int 2131230720 
     14: invokevirtual #30     // Method findViewById:(I)Landroid/view/View; 
     17: checkcast  #32     // class android/widget/TextView 
     20: astore_1 
     21: aload_1 
     22: getstatic  #12     // Field count:I 
     25: invokestatic #38     // Method java/lang/Integer.toString:(I)Ljava/lang/String; 
     28: invokevirtual #42     // Method android/widget/TextView.setText:(Ljava/lang/CharSequence;)V 
     31: aload_0 
     32: ldc   #43     // int 2131230721 
     34: invokevirtual #30     // Method findViewById:(I)Landroid/view/View; 
     37: checkcast  #45     // class android/widget/Button 
     40: new   #6     // class com/example/test/MainActivity$1 
     43: dup 
     44: aload_0 
     45: aload_1 
     46: invokespecial #48     // Method com/example/test/MainActivity$1."<init>":(Lcom/example/test/MainActivity;Landroid/widget/TextView;)V 
     49: invokevirtual #52     // Method android/widget/Button.setOnClickListener:(Landroid/view/View$OnClickListener;)V 
     52: return 

Hier aload_0 ist lokaler Variable für MainActivity Objekt und aload_1 ist lokaler Variable für Bundle-Objekt. Die Quelle des Problems trat bei Code # 20 auf, wenn die Referenz des gerade abgerufenen TextView-Objekts in der lokalen Variablen 1 (astore_1) speichert, die zuvor das Bundle-Objekt gespeichert hatte!

Dies geschieht, da das Bundle-Objekt nicht für den Rest der Methode verwendet wird. Daher ist es effizienter, seine lokale Variable anstelle einer neuen Variablen zu verwenden. Es bedeutet jedoch auch, dass Decompiler besonders hart arbeiten müssen, um korrekten Java-Code zu erzeugen.

+0

Danke für die eingehende Erklärung. – Rawa

+0

Können wir übrigens sicher sein, dass Java Decompiler die Ursache dafür ist? Oder kann die Ausgabe von dex2jar die Fehlerquelle sein? Weil Apktool die gleiche Variable nicht wiederverwenden kann. – Rawa

+1

@Rawa Ich ging zurück und checke die gleiche Klasse von javac kompiliert, bevor es in Dex verarbeitet wurde. Ich habe festgestellt, dass Javac überhaupt keine Optimierung durchführt, daher werden 4 Variablen anstelle von 2 in der dekompilierten Version verwendet. Allerdings denke ich (kein Experte), dass Java-Bytecode-Locals-Variablen Daten verschiedener Typen speichern dürfen, weshalb einige Decompiler lokale Variablen wiederverwenden, während andere dies nicht tun. Nach allem, was für den Decompiler mehr Arbeit ist, um herauszufinden, dass einige Variablen wiederverwendet werden können, als einfach blind Variablen zu greifen, wie sie benötigt werden, würden sie es nicht tun, wenn es falsch ist. – Kai

0

Der von Ihnen angegebene Smali-Code sieht korrekt aus. Das Ausführen der App funktioniert auch mit dem ursprünglichen Quellcode. Der von jd-gui bereitgestellte Code kompiliert jedoch nicht einmal.

Ich wurde neugierig und dekompiliert Ihre App mit dex2jar. Ich habe die resultierende MainActivity.class auf this website hochgeladen.

Der interessante Teil: Einige decompilers (Procyon und Fernflower) erzeugt, um den richtigen Code und machte separaten Variablen sowohl für das Bundle und der Textview. JAD und CFR aber machte den gleichen Fehler wie jd-GUI. Beide verwendeten die Bundle-Variable für die TextView.


Es sieht aus wie Sie jd-gui für den Bug verantwortlich machen können. Leider kann ich dir nicht sagen, warum es passiert.

Verwandte Themen