Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gradle: handle non-final res ids for AGP >8.0.0 #2362

Merged
merged 1 commit into from
Dec 11, 2024

Conversation

nitram84
Copy link
Contributor

The android gradle plugin for jadx gradle export can't be updated to newer versions > 8.0.0 due to several issues. One issue e.g. is a compiler error when android resource identifiers are uses as constant expressions.

Example:

Decompile an app with like this, export sources to gradle, update AGP version manually (> 8.0.0) and recompile it:

package` jadx.app.test;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface RequiresFinalResId {
    int value() default android.R.string.ok;
}
package jadx.app.test;

import android.app.Activity;

@RequiresFinalResId(value=R.string.app_name) // <-- error: constant expression required
public class MainActivity extends Activity {

    @RequiresFinalResId(value=R.string.app_name) // <-- error: constant expression required
    public class Test {
    }

    @RequiresFinalResId(value=R.string.app_name) // <-- error: constant expression required
    private int i;

    @RequiresFinalResId(value=R.string.app_name) // <-- error: constant expression required
    public int test(@RequiresFinalResId(value=R.string.app_name) int i) { // <-- error: constant expression required, error introduced with https://github.com/skylot/jadx/pull/2358
        @RequiresFinalResId(value=R.string.app_name) // <-- Jadx ignores runtime annotations with variable, no error until jadx can decompile this line
        int a = i + 1;
        this.i = i;
        switch (i) {
            case R.string.app_name: // <-- error: constant expression required
                break;
            case android.R.string.ok: // <-- ok, no error
                break;
        }
        return a;
    }
}

With the current gradle export using a AGP version < 8.0.0 this class could be recompiled without any issues.

The solution is to set a property android.nonFinalResIds=false in gradle.properties (see https://stackoverflow.com/questions/76430646/constant-expression-required-when-trying-to-create-a-switch-case-block).

I introduced a new pass to detect these cases. For the new visitor I introduced also a new package jadx.core.dex.visitors.gradle for visitors only required for gradle export. For a refactored visitor for #1927 I would use the same package.

Real world example:

See switch instruction in class de.sellfisch.android.wwr.a.k of https://apkpure.com/who-becomes-rich/de.sellfisch.android.wwr/download/1.15.1

@skylot
Copy link
Owner

skylot commented Dec 11, 2024

@nitram84 looks good, thanks!

for visitors only required for gradle export

We can improve performance a little for jadx-cli by disabling such passes if Gradle export not requested.
Unfortunately, in jadx-gui this can't be done because we don't know if gradle export will be executed.

Also, if everything in jadx-gui is loaded from code cache new flag will be not set, we need somehow save such info with code cache. One possible way is to implement persistent jadx attributes - mark attributes (implement interface) and save along with code cache and restore on cache loading (I will create new issue for this).

@skylot skylot merged commit 7eab3c8 into skylot:master Dec 11, 2024
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants