Status Update
Comments
cc...@google.com <cc...@google.com> #2
reemission of the same liveData is racy
fr...@disneystreaming.com <fr...@disneystreaming.com> #3
jo...@disneystreaming.com <jo...@disneystreaming.com> #4
cc...@google.com <cc...@google.com> #5
@Test
fun raceTest() {
val subLiveData = MutableLiveData(1)
val subject = liveData(testScope.coroutineContext) {
emitSource(subLiveData)
emitSource(subLiveData) //crashes
}
subject.addObserver().apply {
testScope.advanceUntilIdle()
}
}
ap...@google.com <ap...@google.com> #6
cc...@google.com <cc...@google.com>
fr...@disneystreaming.com <fr...@disneystreaming.com> #7
I actually have a WIP fix for it:
if your case is the one i found (emitting same LiveData multiple times, as shown in #5) you can work around it by adding a dummy transformation.
val subLiveData = MutableLiveData(1)
val subject = liveData(testScope.coroutineContext) {
emitSource(subLiveData.map {it })
emitSource(subLiveData.map {it} )
}
cc...@google.com <cc...@google.com> #8
Branch: androidx-master-dev
commit af12e75e6b4110f48e44ca121466943909de8f06
Author: Yigit Boyar <yboyar@google.com>
Date: Tue Sep 03 12:58:11 2019
Fix coroutine livedata race condition
This CL fixes a bug in liveData builder where emitting same
LiveData source twice would make it crash because the second
emission registry could possibly happen before first one is
removed as source.
We fix it by using a suspending dispose function. It does feel
a bit hacky but we cannot make DisposableHandle.dispose async
and we do not want to block there. This does not mean that there
is a problem if developer disposes it manually since our emit
functions take care of making sure it disposes (and there is
no other way to add source to the underlying MediatorLiveData)
Bug: 140249349
Test: BuildLiveDataTest#raceTest_*
Change-Id: I0b464c242a583da4669af195cf2504e2adc4de40
M lifecycle/lifecycle-livedata-ktx/api/2.2.0-alpha05.txt
M lifecycle/lifecycle-livedata-ktx/api/current.txt
M lifecycle/lifecycle-livedata-ktx/api/public_plus_experimental_2.2.0-alpha05.txt
M lifecycle/lifecycle-livedata-ktx/api/public_plus_experimental_current.txt
M lifecycle/lifecycle-livedata-ktx/api/restricted_2.2.0-alpha05.txt
M lifecycle/lifecycle-livedata-ktx/api/restricted_current.txt
M lifecycle/lifecycle-livedata-ktx/src/main/java/androidx/lifecycle/CoroutineLiveData.kt
M lifecycle/lifecycle-livedata-ktx/src/test/java/androidx/lifecycle/BuildLiveDataTest.kt
fr...@disneystreaming.com <fr...@disneystreaming.com> #9
Thanks for reopening!
Do you mean that even if you use testInstrumentationRunnerArguments["androidx.benchmark.killProcessDelayMillis"] = "10000" the problem still occurs? Jist want to confirm that's what you've tried.
That is correct. We tried that, didn't seem to work for these cases.
Does this reproduce for you with the sample project/app?
I wasn't able to repro it with the sample app. Seems to be specific to our app/tests. Although I noticed tests are pretty simple there, only pressHome
on setup for example... On our setup steps we need to login (only the first time) before proceeding to the actual benchmarking iterations.
That being said... We found a way of making it work (for now) by having the following:
jo...@disneystreaming.com <jo...@disneystreaming.com> #10
Something we also found is that sometimes it helps to force stop the app, wipe app data and caches, and uninstall manually in order to remove the error in the following run. We also found that even after we get the error, the process seems to stay alive somehow. If we run the command: `ps | grep com.disney.disneyplus` we can see that the process is still there, which might be related.
cc...@google.com <cc...@google.com> #11
Are you able to provide a standalone isolated repro project or steps that works with the your production application? Note that you can change the sample on github to specify your packagename - as long as the package is installed when the test runs, that should make it easier to isolate.
If I can reproduce locally, I can dig in further.
on...@gmail.com <on...@gmail.com> #12
Then, one of my coworkers tried restarting adb as root and the error disappeared.
I'd call it a workaround though, since running adb root is not always possible or convenient. What changed in 1.2.0+ that root is now required for Macrobenchmark to run properly?
cc...@google.com <cc...@google.com> #13
Macrobenchmark 1.1.1 didn't check if the process kill failed - it would just measure startup times incorrectly if the app process didn't die. The fix was to
As a workaround to mimic the old (incorrect!) measurement behavior, you could implement your own cold startup by passing startupMode = null
, and adding the following to your setup block to attempt a cold startup, but without the success check:
dropShaderCache()
killProcess()
dropKernelPageCache()
This will bypass the exception, but similar to 1.1.1, doesn't actually give you a correct measurement.
If you can consistently get an app into this state, please let me know if you find a way to workaround it (killing the app in some other way, waiting in some other way) would be happy to hear about it.
on...@gmail.com <on...@gmail.com> #14
One problem we found with killProcess()
is that it essentially calls killall $packageName
, which doesn't work if the process name is different than the package name (our case).
We ended up with a custom setupBlock { }
that calls am force-stop $packageName
, which reliably kills all processes of the given package at the start of each iteration:
Runtime.getRuntime().exec("am force-stop $packageName\n").waitFor()
It works like a charm, the tests are now reliable and consistent. However, it requires a couple of protected permissions: android.permission.FORCE_STOP_PACKAGES
and android.permission.INTERACT_ACROSS_USERS_FULL
, which is likely a deal breaker for many.
op...@gmail.com <op...@gmail.com> #15
I am using Firebase Test Lab to execute performance tests on device bluejay,version=32, lib version 1.4.0-alpha06, and face the same issue. Specifically, I attempted to mitigate this by using the following configuration: testInstrumentationRunnerArguments["androidx.benchmark.killProcessDelayMillis"] = "10000"
and noticed that I get a TestRunner exception in 50-100 ms after the process kill is initiated, but I expected it to happen in 10_000 ms.
- 13:57:15.732 26121 26140 D Benchmark: Killing process dif.tech.plata.perf
...
- 13:57:15.874 26121 26140 E TestRunner: java.lang.IllegalStateException: Package dif.tech.plata.perf must not be running prior to cold start!
Could the root cause of this issue be that the arguments weren't passed to this scope correctly, or that Thread.sleep
isn't functioning as expected?
p....@squaregps.com <p....@squaregps.com> #16
1.4.0-alpha07
For your information:
it helped to set pressHome(10_000)
in setupBlock
Description
Component used: androidx.benchmark.benchmark-macro-junit4
Version used:1.2.4
Devices/Android versions reproduced on:
AGP: 8.2.0
Android Studio: Iguana
Baseline Profile: androidx.baselineprofile -> 1.2.4
An error occurs when I create the Baseline Profile module using the Baseline Profile Generator template and then run the sample code below.
Is there a solution?