Fixed
Status Update
Comments
ch...@google.com <ch...@google.com>
ch...@google.com <ch...@google.com> #2
Project: platform/frameworks/support
Branch: androidx-main
commit 57ca221882695bd6a52549f4d9ea3b812e6fe87c
Author: Simon Schiller <simonschiller@users.noreply.github.com>
Date: Mon Mar 22 16:09:30 2021
[GH] [FragmentStrictMode] Detect <fragment> tag usage
## Proposed Changes
- Detect `<fragment>` tag usage inside XML layouts
## Testing
Test: See `FragmentStrictModeTest#detectFragmentTagUsage`
## Issues Fixed
Fixes: 153738235
This is an imported pull request fromhttps://github.com/androidx/androidx/pull/141 .
Resolves #141
Github-Pr-Head-Sha: 4ea052596e4341b9f11bcf335e2bc38045a91f19
GitOrigin-RevId: 62e7487aa4874eef6bb556490e193717cf937251
Change-Id: Iae48578e85e4e4897f806d7ade2e2a660adf9479
M fragment/fragment/api/public_plus_experimental_current.txt
M fragment/fragment/api/restricted_current.txt
M fragment/fragment/src/androidTest/java/androidx/fragment/app/strictmode/FragmentStrictModeTest.kt
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentLayoutInflaterFactory.java
M fragment/fragment/src/main/java/androidx/fragment/app/strictmode/FragmentStrictMode.java
A fragment/fragment/src/main/java/androidx/fragment/app/strictmode/FragmentTagUsageViolation.java
https://android-review.googlesource.com/1649748
Branch: androidx-main
commit 57ca221882695bd6a52549f4d9ea3b812e6fe87c
Author: Simon Schiller <simonschiller@users.noreply.github.com>
Date: Mon Mar 22 16:09:30 2021
[GH] [FragmentStrictMode] Detect <fragment> tag usage
## Proposed Changes
- Detect `<fragment>` tag usage inside XML layouts
## Testing
Test: See `FragmentStrictModeTest#detectFragmentTagUsage`
## Issues Fixed
Fixes: 153738235
This is an imported pull request from
Resolves #141
Github-Pr-Head-Sha: 4ea052596e4341b9f11bcf335e2bc38045a91f19
GitOrigin-RevId: 62e7487aa4874eef6bb556490e193717cf937251
Change-Id: Iae48578e85e4e4897f806d7ade2e2a660adf9479
M fragment/fragment/api/public_plus_experimental_current.txt
M fragment/fragment/api/restricted_current.txt
M fragment/fragment/src/androidTest/java/androidx/fragment/app/strictmode/FragmentStrictModeTest.kt
M fragment/fragment/src/main/java/androidx/fragment/app/FragmentLayoutInflaterFactory.java
M fragment/fragment/src/main/java/androidx/fragment/app/strictmode/FragmentStrictMode.java
A fragment/fragment/src/main/java/androidx/fragment/app/strictmode/FragmentTagUsageViolation.java
yq...@gmail.com <yq...@gmail.com> #3
I've attached reproduction project.
Please check it, thanks!
Please check it, thanks!
ch...@google.com <ch...@google.com> #4
Thanks for the quick response!
This is actually intended behavior when you are running R8 in full mode. Note that, if you do not explicitly enable full mode using `android.enableR8.fullMode=true` then everything works as intended.
The problem in full mode is that SavedStateRegistry#runOnNextRecreation() reflectively instantiates the class that it receives as an argument.
https://developer.android.com/reference/androidx/savedstate/SavedStateRegistry.html#runOnNextRecreation(java.lang.Class%3C?%2520extends%2520androidx.savedstate.SavedStateRegistry.AutoRecreated%3E)
For this reason. it is necessary to specify that androidx.lifecycle.AbstractSavedStateVMFactory$OnRecreation should be kept. This can be done with the following Proguard configuration rule:
-keep class androidx.lifecycle.AbstractSavedStateVMFactory$OnRecreation { <init>(); }
Another possibility would be to use the following slightly more general rule, since runOnNextRecreation() reflectively instantiates types that are a subtype of androidx.savedstate.SavedStateRegistry$AutoRecreated:
-keep class * extends androidx.savedstate.SavedStateRegistry$AutoRecreated
(Note that the reason why this works without full mode is that R8 and Proguard simply decides to keep the default constructor for all classes that are referenced in a `X.class` expression. That has the undesirable effect that many default constructors that are never used for anything may be kept.)
This is actually intended behavior when you are running R8 in full mode. Note that, if you do not explicitly enable full mode using `android.enableR8.fullMode=true` then everything works as intended.
The problem in full mode is that SavedStateRegistry#runOnNextRecreation() reflectively instantiates the class that it receives as an argument.
For this reason. it is necessary to specify that androidx.lifecycle.AbstractSavedStateVMFactory$OnRecreation should be kept. This can be done with the following Proguard configuration rule:
-keep class androidx.lifecycle.AbstractSavedStateVMFactory$OnRecreation { <init>(); }
Another possibility would be to use the following slightly more general rule, since runOnNextRecreation() reflectively instantiates types that are a subtype of androidx.savedstate.SavedStateRegistry$AutoRecreated:
-keep class * extends androidx.savedstate.SavedStateRegistry$AutoRecreated
(Note that the reason why this works without full mode is that R8 and Proguard simply decides to keep the default constructor for all classes that are referenced in a `X.class` expression. That has the undesirable effect that many default constructors that are never used for anything may be kept.)
yq...@gmail.com <yq...@gmail.com> #5
Thanks for the detailed response.
Do I need to add the above rule in my proguard file?
I thought the above rule should be added to proguard file in the android platform module.
I've searched platform source code, and found the following rule placed in savedstate module.
https://android.googlesource.com/platform/frameworks/support/+/refs/heads/androidx-master-dev/savedstate/proguard-rules.pro
I think
"SavedStateRegistry.AutoRecreated"
should be changed to
"SavedStateRegistry$AutoRecreated".
Please correct me if I'm wrong, thanks!
Do I need to add the above rule in my proguard file?
I thought the above rule should be added to proguard file in the android platform module.
I've searched platform source code, and found the following rule placed in savedstate module.
I think
"SavedStateRegistry.AutoRecreated"
should be changed to
"SavedStateRegistry$AutoRecreated".
Please correct me if I'm wrong, thanks!
ch...@google.com <ch...@google.com> #6
Yes, it should. We will make sure that the keep rule in androidx gets updated (I will keep this issue open until the rules have been fixed there).
I also filed a feature request b/132860232 to ensure that R8 will actually raise a warning when a type name in the Proguard configuration is using '.' for the inner class name separator instead of '$'.
I also filed a feature request
ch...@google.com <ch...@google.com> #7
Sergey, could you help make the appropriate changes to the keep rule mentioned in comment #5 ?
sg...@google.com <sg...@google.com> #8
I did some digging into the androidx.lifecycle:lifecycle-viewmodel-savedstate:1.0.0-alpha01 library, and it turns out that they already supply this keep rule from the library:
-keepclassmembers,allowobfuscation class * extends androidx.savedstate.SavedStateRegistry.AutoRecreated {
<init>();
}
However, that is using the fully qualified and not the binary name of the AutoRecreated inner class.
I will create a CL, so that going forward using androidx.lifecycle:lifecycle-viewmodel-savedstate should not require additional keep rules.
-keepclassmembers,allowobfuscation class * extends androidx.savedstate.SavedStateRegistry.AutoRecreated {
<init>();
}
However, that is using the fully qualified and not the binary name of the AutoRecreated inner class.
I will create a CL, so that going forward using androidx.lifecycle:lifecycle-viewmodel-savedstate should not require additional keep rules.
sg...@google.com <sg...@google.com> #9
ar...@gmail.com <ar...@gmail.com> #10
Gg
Description
androidx.lifecycle: 2.2.0-alpha01
<Steps to reproduce>
1. Based on new empty activity project, add following ViewModel class.
```
class MainViewModel(
private val savedStateHandle: SavedStateHandle
): ViewModel()
```
2. Modify MainActivity as followings.
```
class MainActivity : AppCompatActivity() {
private lateinit var viewModel: MainViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewModel = ViewModelProviders.of(
this,
SavedStateVMFactory(this)
).get(MainViewModel::class.java)
}
}
```
3. Add a keep rule for MainViewModel.
-keep class com.example.savedstateviewmodelsample.MainViewModel { *; }
4. Enable r8 fullMode and run app, then the app crash with the following error.
com.example.savedstateviewmodelsample E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.savedstateviewmodelsample, PID: 15365
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.savedstateviewmodelsample/com.example.savedstateviewmodelsample.MainActivity}: java.lang.IllegalArgumentException: ClassOnRecreation must have default constructor in order to be automatically recreated
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2913)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Caused by: java.lang.IllegalArgumentException: ClassOnRecreation must have default constructor in order to be automatically recreated
at androidx.savedstate.SavedStateRegistry.runOnNextRecreation(:177)
at androidx.lifecycle.AbstractSavedStateVMFactory.create(:71)
at androidx.lifecycle.ViewModelProvider.get(:162)
at androidx.lifecycle.ViewModelProvider.get(:130)
at com.example.savedstateviewmodelsample.MainActivity.onCreate(:20)
at android.app.Activity.performCreate(Activity.java:7136)
at android.app.Activity.performCreate(Activity.java:7127)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2893)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Caused by: java.lang.NoSuchMethodException: <init> []
at java.lang.Class.getConstructor0(Class.java:2327)
at java.lang.Class.getDeclaredConstructor(Class.java:2166)
at androidx.savedstate.SavedStateRegistry.runOnNextRecreation(:175)
at androidx.lifecycle.AbstractSavedStateVMFactory.create(:71)
at androidx.lifecycle.ViewModelProvider.get(:162)
at androidx.lifecycle.ViewModelProvider.get(:130)
at com.example.savedstateviewmodelsample.MainActivity.onCreate(:20)
at android.app.Activity.performCreate(Activity.java:7136)
at android.app.Activity.performCreate(Activity.java:7127)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2893)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)