Status Update
Comments
ch...@google.com <ch...@google.com> #2
<transition xmlns:android="
<item android:drawable="@drawable/test_drawable_blue"/>
<item android:drawable="@drawable/test_drawable_green"/>
</transition>
where blue/green drawables look like this:
<shape
xmlns:android="
android:shape="rectangle">
<size
android:width="@dimen/drawable_large_size"
android:height="@dimen/drawable_small_size" />
<solid
android:color="@color/test_blue" />
</shape>
Then added this test:
@Test
public void testMutateTransitionDrawable() {
Drawable drawable = ResourcesCompat.getDrawable(mResources,
R.drawable.test_transition_drawable, null);
assertTrue(drawable instanceof TransitionDrawable);
Drawable mutated = drawable.mutate();
assertTrue(drawable instanceof TransitionDrawable);
assertTrue(mutated instanceof TransitionDrawable);
}
It passes on the device. Going to also try on other earlier devices a bit later in the day once they are charged.
zg...@gmail.com <zg...@gmail.com> #3
ch...@google.com <ch...@google.com> #4
zg...@gmail.com <zg...@gmail.com> #5
I just compared the code of the latest alpha02 version. It is the same as my online code. This problem still exists,which is a little puzzling
ch...@google.com <ch...@google.com> #6
What release(s) are you seeing this on? There are different code paths pre- and post-API 24, would be good to know which one you are seeing it on.
zg...@gmail.com <zg...@gmail.com> #7
I used alpha02 version,and Crashed in line 182 of jankstatsapi24impl.kt(android 12).
ch...@google.com <ch...@google.com> #8
ch...@google.com <ch...@google.com> #9
ch...@google.com <ch...@google.com> #10
- I sent the data directly on the internal thread that receives FrameMetrics info (instead of sending it through the executor, which is the case in alpha02)
- In the OnFrameListener code, I changed the value of isTrackingEnabled
This combination makes it possible to change the delegates list (as a result of isTrackingEnabled) while the list is being iterated (in the FrmaeMetrics listener, which is sending out the frame data to the listeners). Because they are happening on the same thread, the synchronization block doesn't prevent both of these from happening concurrently; it's just a nested synchronization on the same item in the same thread.
This case is pretty interesting because an upcoming change will remove the Executor from the JankStats constructor, moving to a model where data is sent directly on the internal thread, thus skipping the allocations that currently take place.
But this means anything that happens on that thread to change the delegators list (as above) will trip over this problem.
So I'll work on this. But in the meantime:
Does the above match what your app is doing?
For one thing, are you changing isTrackingEnabled in onFrameListener callback?
And what are you using for an Executor? Your version of the library still uses an Executor, but maybe you are setting it up in an unexpected way.
ch...@google.com <ch...@google.com> #11
Then it's just a matter of modifying the list of listeners in the listener callback. (again, I assume that is what you are doing?)
I am working on a fix (not sure yet what form it will take).
In the meantime, if you want to fix your app before the fix is available, avoid calling JankStats.isTrackingEnabled in your listener; that's the root of the problem, because it is modifying the listener list while that list is being processed.
(If any of my assumptions are not correct, please give me more details about what your app is actually doing; this is the only thing I can come up with so far which would cause this exception)
zg...@gmail.com <zg...@gmail.com> #12
Thank you for spending so much time on this issue。Let me talk about an operation path on my side,I create a jankstats in the onactivitystarted method of each activity(mJankStats = JankStats.createAndTrack(activity.window,executor,jankFrameListener)), and then set istrackingenabled = true in the onactivityresumed method; Set istrackingenabled = false in onactivitypaused method; In addition, istrackingenabled has not been operated in other places; And then I was at jankstats Onframelistener collects framedurationuinanos of each frame to record the time consumption of each frame, and then reports about 60 frames once.
ch...@google.com <ch...@google.com> #13
ch...@google.com <ch...@google.com> #14
I need to fix the other issue I found anyway, since changing tracking in a listener is definitely broken, but I can't tell what else could be happening besides that that is causing the problem with your app.
ch...@google.com <ch...@google.com> #15
- What kind of executor are you creating?
- What release(s) are you seeing the exception on?
- Do you see the exception every time you run the app? Is there anything in particular that triggers it (like going to the background or coming back to the foreground)?
zg...@gmail.com <zg...@gmail.com> #16
- Dispatchers.Default.asExecutor()
- alpha02 version
- It's an occasional crash. I didn't reproduce it, but users of the online version will appear. According to the analysis of the online crash log, it seems that some are in the background and some are in the foreground, which may happen in the front and back switching
zg...@gmail.com <zg...@gmail.com> #17
Is there any progress on this issue?
ap...@google.com <ap...@google.com> #18
Branch: androidx-main
commit f6e347fa7bbb4ea5a688d3a0af192b2595db2fae
Author: Chet Haase <chet@google.com>
Date: Fri Jul 01 10:11:09 2022
Fix ConcurrentModificationException bug
It is possible to add/remove items from the delegator list (in one code
path) while iterating through those items (in an unrelated code path). This
can lead to crashes.
The fix was to send all delegator lists through a single, common object.
Iteration and modifications only happen in a synchronized block on that object.
To prevent reentrant issues (where a callback on the thread doing the
iteration can add/remove items and thus succeed in both synchronized blocks),
adds/removed are gated to avoid having them happen during iteration, postponing
those operations until the outer iteration is complete.
Bug: 236612357
Test: Added test to JankStatsTest to verify bug and fix
RelNote: "Fixed ConcurrentModificationException bug where the list of
listener delegates was being modified while it was also being iterated through
to send per-frame data."
Change-Id: Ib769386f18e51dc6b58c935b42c5b8566c644abc
M metrics/metrics-performance/src/main/java/androidx/metrics/performance/JankStatsApi24Impl.kt
M metrics/metrics-performance/src/main/java/androidx/metrics/performance/JankStatsApi16Impl.kt
M metrics/metrics-performance/src/androidTest/java/androidx/metrics/performance/test/JankStatsTest.kt
ch...@google.com <ch...@google.com> #19
If you are still seeing the issue with the above change, please reopen. Anything you can tell me about the situation would help; I need to reproduce the problem to make any progress on it. (including, for example, the Android release(s) you are seeing the issue on; that's what I was asking for in #15. But mostly I need steps to reproduce).
Description
`androidx.metrics` version used: 1.0.0-alpha01
Devices/Android versions reproduced on: multiple android versions 11, 10, 12, 9
When you encountered this bug:
• Issue is reported on production. App is crashing with ConcurrentModificationException. We are initialising JankStat on
every fragment to measure the jank frames for that fragment.
This issue is already fixed:
When the new version of JankStats would be released with the fix. For now is there any workaround to suppress this crash?