Affectation étrange, TextView à Bundle, après décompilation, pourquoi?

J’ai créé une application simple, une application de compteur, qui, en appuyant sur un bouton, incrémente un entier de un et met à jour une vue de texte. Le code peut être vu ci-dessous:

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.toSsortingng(count)); final Button button = (Button) findViewById(R.id.button); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { count++; textView.setText(Integer.toSsortingng(count)); } }); } ... } 

Après avoir décompilé la même application avec dex2jar et jd-gui, j’ai reçu le code suivant:

 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.toSsortingng(count)); ((Button)findViewById(2131296256)).setOnClickListener(new View.OnClickListener() { public void onClick(View paramAnonymousView) { MainActivity.count += 1; paramBundle.setText(Integer.toSsortingng(MainActivity.count)); } }); } ... } 

Sur la ligne suivante:

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

Comment est-il possible pour le système de définir la textview sur le paramBundle? Et pourquoi cela se passe-t-il? paramBundle est de type Bundle et TextView n’est pas une sous-classe de Bundle, plus Bundle est final selon la version décompilée. Est-ce que quelque chose s’est mal passé lors de la décompilation? L’information provenant du décompilateur est-elle erronée ou pourquoi avons-nous obtenu ce résultat?


Modifier:

 # virtual methods .method protected onCreate(Landroid/os/Bundle;)V .locals 3 .param p1, "savedInstanceState" # Landroid/os/Bundle; .prolog .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;->toSsortingng(I)Ljava/lang/Ssortingng; 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;->(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 

Je ne suis certainement pas un expert en smali, seulement un novice. Mais j’ai aussi décodé l’application en utilisant apktool et j’ai reçu le code smali ci-dessus. D’après ce que j’ai compris, la sauvegarde (paramBundle) est chargée dans p1 (= v3) et utilisée dans onCreate, et elle n’est pas utilisée de quelque façon que ce soit dans la ligne 20 ou 21. Cela m’amène à une erreur de déconnexion? N’oubliez pas qu’apktool permet de reconstruire l’application à nouveau et qu’aucune donnée ne peut être perdue lors de la décompilation.

La cause en est que le type des variables locales a changé, mais certains décompilateurs ne parviennent pas à le gérer correctement.

Voici votre code onCreate décompilé avec dex2jar + 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.toSsortingng:(I)Ljava/lang/Ssortingng; 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."":(Lcom/example/test/MainActivity;Landroid/widget/TextView;)V 49: invokevirtual #52 // Method android/widget/Button.setOnClickListener:(Landroid/view/View$OnClickListener;)V 52: return 

Ici, aload_0 est une variable locale pour l’object aload_1 et aload_1 est une variable locale pour l’object Bundle. La source du problème s’est produite au code # 20, quand il stocke la référence de l’object TextView que l’on vient de récupérer dans la variable locale 1 ( astore_1 ), qui stockait précédemment l’object Bundle!

Ceci est fait car l’object Bundle n’est pas utilisé pour le rest de la méthode, il est donc plus efficace de réutiliser sa variable locale au lieu d’une nouvelle variable. Cependant, cela signifie également que les décompilateurs doivent travailler plus dur pour produire du code Java correct.

Le code smali que vous avez fourni est correct. L’exécution de l’application fonctionne également avec le code source d’origine. Cependant, le code fourni par jd-gui ne comstack même pas .

Je suis curieux et j’ai décompilé votre application avec dex2jar. J’ai téléchargé le fichier MainActivity.class résultant sur ce site .

La partie intéressante: Certains décompilateurs ( Procyon et Fernflower ) ont généré le bon code et créé des variables distinctes pour le Bundle et le TextView. JAD et CFR ont cependant fait la même erreur que jd-gui. Ils ont tous deux utilisé la variable Bundle pour TextView.


On dirait que vous pouvez blâmer jd-gui pour le bogue. Malheureusement, je ne peux pas vous dire pourquoi cela se produit.