Inquiry on Java Bytecode Optimization Issues in Chromium Project

4 views
Skip to first unread message

hanszhli(李泽瀚)

unread,
Aug 15, 2024, 7:28:42 AM8/15/24
to java
Dear Chromium Java Team,

I hope this email finds you well.

We are currently working on a project that involves secondary development based on Chromium, and I am focusing on reducing the APK package size. By enabling proguard_enabled=true, I have achieved significant Java code optimization. However, I have encountered two issues during this process. I have resolved one issue but would like to seek advice on a potentially better solution. The other issue remains unresolved, and I hope to get your assistance.

Issue 1: I discovered that methods generated by jni_registration_generator.py in gen/.../generated_java/input_srcjars/J/N.java are being optimized away by R8 if they are not used, causing runtime crashes due to missing JNI methods. 
I compared this with chrome_public_apk and system_webview_apk, and found that they do not have this issue. 
I suspect that it is because our project enables manual_jni_registration=true, which uses dynamic JNI registration.
I added the following line to my proguard.txt:-keep class J.N {*;}. After adding this line, the issue was resolved.

 I would like to confirm two points:
1. Is the issue indeed caused by the unused JNI methods being deleted due to them not being referenced in the Java layer?
2. Is there a better way to resolve this issue other than using -keep class J.N {*;}?

Issue 2: I noticed that when a Java crash occurs, the source code line number is not displayed correctly. The stack trace shows as follows:
at org.chromium.base.task.PostTask.runOrPostTask(chromium-my.apk-default-1:11)
Here is a snippet of my current configuration:
android_apk("my_apk") {
  deps = [
    ...
  ]
  ...
  apk_name = "my"
  version_name = "1.0-dev"
  version_code = "1"
  min_sdk_version = 21
  if (!is_java_debug) {
    print("enable proguard.")
    proguard_enabled = true
    proguard_configs = [ "//my/proguard.txt" ]
  }
}

I have a few observations but am unsure if they are correct:
1. If I want to retain source file and line number information, I should add -keepattributes SourceFile,LineNumberTable to proguard.txt. However, this did not seem to work.
2. I noticed that base/android/proguard/chromium_apk.flags already includes -keepattributes SourceFile,LineNumberTable along with other necessary rules, so theoretically, I should not need to add this rule to my own proguard.txt.

I am not sure where the issue lies. Could you please provide some suggestions?

Thank you very much for your time and assistance.

Best regards

Hans


Sam Maier

unread,
Aug 15, 2024, 9:31:02 AM8/15/24
to hanszhli(李泽瀚), java
1) Not totally. I believe the issue (without seeing your crash) was that descriptor classes were being renamed, which would mess up the JNI resolution.

1) You are keeping source file and line number info, but R8 is optimizing and thus line numbers/function names will not line up. You will need to use the generated .mapping file to deobfuscate the java.
2) Yes as long as that file is included.


--
You received this message because you are subscribed to the Google Groups "java" group.
To unsubscribe from this group and stop receiving emails from it, send an email to java+uns...@chromium.org.
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/java/tencent_5144C6A43A0CC07778854AA0%40qq.com.

hanszhli(李泽瀚)

unread,
Aug 16, 2024, 5:00:33 AM8/16/24
to Sam Maier, java

Sam Maier,

Thank you for being willing to provide help and for replying to my email. In my first email, I mentioned two issues. Let's discuss the first issue first.

In the first issue, I did not provide a detailed crash stack, which may have led you to think that my assumption was incorrect. Therefore, I have created a demo and uploaded it to GitHub, where I have detailed my reproduction steps and log information: 

Please take a look at this demo and help me investigate further.

Thank you again for your assistance.


Sam Maier

unread,
Aug 16, 2024, 9:25:29 AM8/16/24
to hanszhli(李泽瀚), java
Yep, it looks like my answers were correct. The rule I linked is required if using jni_zero.

hanszhli(李泽瀚)

unread,
Aug 18, 2024, 11:13:23 PM8/18/24
to Sam Maier, java

Thank you for your reply. I am not sure if I misunderstood you. I am aware that JNI methods are renamed to HASH names, but here it seems to be not just a renaming issue but rather that the unused jni methods are being deleted, which is causing the problem. Additionally, I also followed your suggestion to check the jni_zero/proguard.flag.

1. (Not sure if this is what you want me to try?) I directly copied all the rules from jni_zero/proguard.flag into my own proguard.txt, but the crash in case2 from the GitHub demo still occurs. My proguard.txt is modified as follows:
-keep class com.demo.** {*;}
-keep class androidx.** { *;}
# Keeps for method level annotations.
-keepclasseswithmembers,allowaccessmodification class ** {
  @org.jni_zero.AccessedByNative <fields>;
}
-keepclasseswithmembers,includedescriptorclasses,allowaccessmodification class ** {
  @org.jni_zero.CalledByNative <methods>;
}
-keepclasseswithmembers,includedescriptorclasses,allowaccessmodification class ** {
  @org.jni_zero.CalledByNativeUnchecked <methods>;
}
# Allow unused native methods to be removed, but prevent renaming on those that
# are kept.
-keepclasseswithmembernames,includedescriptorclasses,allowaccessmodification class ** {
  native <methods>;
}
# Used when multiplexing. We don't package our own @UsedByReflection, so using this instead.
-keepclasseswithmembers class !cr_allowunused,**J.N {
  public long *_HASH;
}
2. I checked the jni_zero/proguard.flag file and found that it is already included in out/apk_demo/gen/apk_demo/apk_demo.build_config.json (as shown in the image below). In theory, I should not need to include it again in my proguard.txt, right?

My English isn't very good, and the translation software may have caused some misunderstanding. If you can clearly tell me what I need to add to fix this issue, that would be best. I can then analyze further based on the code you provide and understand your intentions. Thank you very much!

Sorry to bother you again, and thank you for your support and help.


AC3E24EC@3847CD2B.3EB8C26600000000.png

Sam Maier

unread,
Aug 19, 2024, 9:13:42 AM8/19/24
to hanszhli(李泽瀚), java
So, what's happening is you have a genuinely unused method that R8 is eliding. I believe that if you used normal (ie. not-manual) registration, it wouldn't complain, but since you're using manual registration, every single function must exist in J/N. So, if you aren't actually using these methods, you're going to have to switch the key line in proguard.flags from "-keepclasseswithmembernames" to "-keepclasseswithmembers"

hanszhli(李泽瀚)

unread,
Aug 19, 2024, 12:38:08 PM8/19/24
to Sam Maier, java
Yes, as you said, there are some differences in usage caused by manual_jni_registration=true. I understand it this time and know how to solve it. Thanks for your reply!  

----------回复的邮件信息----------
Sam Maier <sma...@chromium.org> 在 Mon,Aug 19,2024 9:13 PM写道:
A154AD0E@5376ED68.DA74C36600000000
Reply all
Reply to author
Forward
0 new messages