Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Strange assignment, TextView to Bundle, after decompiling, why?

I created a simple application, a counter app, that upon pressing a button increments a integer by one and updates a textview. The code can be seen below:

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));
            }
        });
    }
    ...
}

After decompiling the same app with dex2jar and jd-gui i received the following code back:

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));
            }
        });
    }
    ...
}

On the following line:

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

How is it possible for the system to set the textview to the paramBundle? And why is this happening? paramBundle is of type Bundle and TextView is not a subclass of Bundle, further more Bundle is final according to the decompiled version. Did something go wrong upon decompiling? Is the information from the decompiler wrong or why do we get this result?


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

I'm definitely no smali expert, only a novice. But i decoded the application using apktool as well and received the smali code above. From my understanding, the savedinstance (paramBundle) is loaded in to p1(=v3) and used in onCreate, and it is not used in any way in line 20 or 21. To me this point towards a decompling error? Keep in mind that apktool allows for building the application again and thus no data may be lost when decompiling.

like image 270
Rawa Avatar asked May 13 '15 23:05

Rawa


1 Answers

The cause is that the type of local variables has changed, but some decompilers fail to handle it correctly.

Here's your onCreate code decompiled with 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.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

Here aload_0 is local variable for MainActivity object, and aload_1 is local variable for Bundle object. The source of the problem occured at code #20, when it stores the reference of just-retrieved TextView object into local variable 1 (astore_1), which was previously storing the Bundle object!

This is done since the Bundle object is not used for the rest of the method, therefore it's more efficient to reuse its local variable instead of a new variable. However it also means that decompilers need to work extra hard to produce correct Java code.

like image 93
Kai Avatar answered Oct 24 '22 10:10

Kai