Redex: Issue with proguard

Created on 12 Aug 2019  Â·  6Comments  Â·  Source: facebook/redex

I use -P to specify a proguard rule to keep some classes. But When I only write a proguard rule with just single line
"-keep interface com.facebook.redex.examples.proguardexample.Greek" to test,
the result apk's size is reduce greatly, and run with crash. It's seems over-reduced。 when I leave proguard rule empty, it looks all right.

but some pass need to provide proguard rule or it not works. Is it any wrong when I do with proguard? the config I use following:

{
"redex" : {
"passes" : [
"ReBindRefsPass",
"BridgePass",
"ResultPropagationPass",
"SynthPass",
"FinalInlinePass",
"DelSuperPass",
"MethodInlinePass",
"PeepholePass",
"ConstantPropagationPass",
"LocalDcePass",
"RemoveUnreachablePass",
"RemoveGotosPass",
"DedupBlocksPass",
"UpCodeMotionPass",
"ReorderInterfacesPass",
"RemoveEmptyClassesPass",
"InterDexPass",
"ShortenSrcStringsPass",
"RegAllocPass",
"CopyPropagationPass",
"LocalDcePass",
"ReduceGotosPass"
]
},
"FinalInlinePass" : {
"propagate_static_finals": true,
"replace_encodable_clinits": true
},
"MethodInlinePass": {
"throws": true,
"multiple_callers": true,
"black_list": []
},
"ConstantPropagationPassV3" : {
"blacklist": [],
"replace_moves_with_consts": true,
"fold_arithmetic": true
},
"RegAllocPass" : {
"live_range_splitting": false
},
"CopyPropagationPass" : {
"eliminate_const_literals": false,
"full_method_analysis": true
},
"PeepholePass" : {
"disabled_peepholes": [
"Replace_PutGet",
"Replace_PutGetWide",
"Replace_PutGetObject",
"Replace_PutGetShort",
"Replace_PutGetChar",
"Replace_PutGetByte",
"Replace_PutGetBoolean"
]
},
"keep_packages": [
"Lcom/fasterxml/jackson/",
"Lcom/google/dexmaker/mockito/"
],
"keep_annotations": [
"Lcom/google/common/annotations/VisibleForTesting;"
],
"debug_info_kind": "no_custom_symbolication",
"method_move_map" : "redex-moved-methods-map.txt",
"string_sort_mode" : "class_order",
"bytecode_sort_mode" : "class_order",
"ir_type_checker": {
"run_after_each_pass" : false,
"verify_moves" : false
},
"proguard_map":"/Users/loganzhou/Downloads/proguard_mapping_release.txt",
"coldstart_classes" : "list_of_classes.txt"
}

question

Most helpful comment

In addition what @ssj933 said: Two passes on your list might do "unsafe" things, and you might want to try running Redex without them to narrow down the issue: FinalInlinePass and RemoveUnreachablePass.

All 6 comments

Could you run with TRACE=1 for both cases? I suspect it is not enough proguard rule provided when you just add that line. The reason why things may look right when proguard rule is empty may be that most optimization passes returned when they found out no proguard rule is provided like this:
https://github.com/facebook/redex/blob/master/opt/remove-unreachable/RemoveUnreachable.cpp#L28-L34
Then when you add the line they think proguard rule is provided and proceed, and treated the interface "com.facebook.redex.examples.proguardexample.Greek" as the only root. That's what I suspect.

In addition what @ssj933 said: Two passes on your list might do "unsafe" things, and you might want to try running Redex without them to narrow down the issue: FinalInlinePass and RemoveUnreachablePass.

But When I only write a proguard rule with just single line
"-keep interface com.facebook.redex.examples.proguardexample.Greek" to test,
the result apk's size is reduce greatly, and run with crash.

This isn't too surprising. When you don't supply any proguard rules, Redex assumes that it can't see the whole program and doesn't do some of it's more aggressive optimizations (such as FinalInline and RemoveUnreachable, as Nikolai mentioned).

When any proguard configs are provided (no matter how small), redex will assume it has a whole program view. Which means it will delete classes/methods/fields that it can't see a reference to. Redex can only see java -> java, non-reflective entry-points. It can't see reflection, JNI, or other "weird" entry points to the java part of the app.

You need to use proguard rules to tell redex about any other entry point to your program (such as JNI to native code) and any "invisible" method calls (such as reflection). In practice, you can build up the necessary proguard rules by looking at adb logcat when your app crashes and adding a keep rule for whatever classes/methods/fields were erroneously removed.

Hi @justinjhendrick , you mean I should provide a whole proguard rule for my app, any class not in proguard rule should be delete. That's the reason why app will crash.
Do I understand this correctly?

any class not in proguard rule should be delete

Not really, for those classes that are not in proguard rule, if they are reachable by the classes kept in proguard rule, they should not be deleted as well.
But yes, a more thorough proguard rule need to be provided.

Closing this issue as there is no recent activity, feel free to re-open if you still have doubt!

Was this page helpful?
0 / 5 - 0 ratings