-
Notifications
You must be signed in to change notification settings - Fork 11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Deadlock when executing request permission #25
Comments
Thanks for the detailed explanation and possible solution. I am looking into this. |
I tried to reproduce this with the included
And I got the result. No Deadlock |
Yeah I would expect that would happen. As I wasn't calling it from onCreate but later on after user had already closed another dialog it seemed obvious that its not just any call that would trigger the behaviour. I'm using kotlin 1.7.20, with coroutineVersion = "1.6.4", I've seen the behaviour completely (seemingly 100%) reproducible on OnePLus 7Pro+10Pro runningr android 11 and 12 respetively. I've seen this ANR from crashlytics from production which I have learned from my own tests was caused by this, and the ANR only started coming after releasing with the new peko version
I tried searching for info on above ANR, and didn't really get a solution. Though that was before I discovered the exact place that PEKO hung. Also it kind of looks like its not just peko but everything in my app. But that would fit if somehow we have introduced a deadlock in the main-thread. Though I cannot see how. Could be a kotlin bug, but I am always very cautious to blame the compiler. I could also show you via screen-share, if we could find the time, but I cannot give you the code. I would probably have to work some hours to strip everything else and send you a stripped down version. That does seem possible. I'll think about it. Hmmm, interesting. I just checked the devices from production. There were 8 user devices with this bug, and every single one of them were also a OnePlus. Naaah, I just tested on a samsung, its also stuck on the samsung. I tried reproducing in your sample, but to no avail. I'll have to strip down the codebase I already have to reproduce it. |
I managed to reproduce it now in a tiny sample. Insert this at the end of MainActivity.onCreate (or probably anywhere, but that's where I tested it) in your sample of Peko.
Interestingly its not a just question of switching to withContext(Dispatchers.IO). Because if I do a withContext(Dispatchers.Main) {} around the request, then it still works, even though I'm switching to main. So I'm pretty sure its the activityLifecycleScope.launchWhenResumed. I also had to use this lifeCycleScope in order to reproduce it, instead of a basic CoroutineScope. The withContext probably brings it out of it. You can also see my branch https://github.com/arberg/Peko/ I suspect we should report this to the kotlin guys and see what they have to say about it. AHHH, now I think I know the problem. It did seem a bit fishy to me to have the PekoActivity run code that was created in another activity, but I couldn't see why that actually should be a problem. I'm pretty sure the problem is that I use launchWhenResumed, I would strongly suggest if possible, that you also see if its possible to make the PekoActivity run the code. Like if it gets the permissions in a channel it creates, and then makes those results flood to the subscriber in the original activity / PermissionRequester. If you want to chat about it via voice that can probably be arranged. |
Yes, I can reproduce it. For some reason, multiple request calls (at the same time) are causing the hang. But with this latest example, if I wrap it in |
An easy fix would be to not allow multiple requests at the same time. As also the native request dialog can only be shown for one request at a time. Peko v2 worked like this. But not sure about it |
I think it is fixed in this branch https://github.com/deva666/Peko/tree/deadlock_fix |
Hi, It still dead-locks. I think the problem is that the channel in PekoPermissionRequester, is collected and thus runs in the scope defined by the client and the calling activity. I suggest moving these lines
To a channel collected in the PEKO activity, and that the peko activity channel then sends the results to the channel from above lines in PekoPermissionRequester. That way it should work save and sound. You have two channels, the PekoActivity controls the execution scope of the channel which does the actual requests of permission, and that fits perfectly in the android style. It then sends the results, to something which may or may not be running at the time we are requesting the permissions in PekoActivity, and then PekoActivity, when done, can finish itself. I don't understand the code well enough to change it. I think the '?: return' you have in PekoActivity.onCreate has a bug, I suspect you have to finish the activity, to pop this left over activity. I suspect this can happen when android rebuilds the process, and create a new activity, before you have Peko initiated. Probably you also need to finish the activity if channel is null (maybe for same reason?). I have merged your changes into my reproduced_deadlock branch, but I kept my own test-code. |
I missed this comment before:
I don't think I in my example makes multiple request at a time. However I agree that the framework has a problem with this, due to the static behaviour. One option might be to add an ID, that is bumped on each attempt, and invoke the pekoActivity with the id. Then you could have a static map from id to channel, or perhaps more sane, just a static 'lastId' plus the channel, and then quick-fail in the PekoActivity if the ID given in the intent, is not the ID registered in the static data as 'lastId'. These are just thoughts, it might not be useful. |
I've been playing with some solutions and it seems that your initial suggestion, wrapping getting the native requester with IO dispatcher seems like the easiest solution. I cannot test with your code, but I pushed this to branch https://github.com/deva666/Peko/tree/deadlock_fix_2 . Can you please tell me if this works with your code? |
PEKO 3.0.1
If I request permission on a fresh app startup where permissions has not been requested previously, then the app is stuck in a deadlock style ANR. It never proceeds. The same code I run works when I execute it via button press later
Debugging indicates that it hangs after executing PermissionRequester:75 which is this line
And the
PekoActivity
executesonPostCreate
(with non-null requesterDeferred) but neitherrequestPermissions
,onRequestPermissionsResult
norfinish
got executed on PekoActivity according to my breakpoints. Apparantly your maven upload included the source-code, so IntelliJ could debug it which was pretty cool.If I change the code so it performs the request on another thread, then it works
After changing to the above code, the coroutine proceeded past the PermissionRequester:75 await line, performed the permission-requests and then things ran along fine from there.
For some reason the main-thread code only hung when I executed during my startup work (but long after onCreate), but did not hang when executed from user button click. But then again, that just indicates deadlocks can be tricky.
Its quite unclear to me how it can be a deadlock, as your coroutines seem fine. They suspend and should allow the main to do its work.
I have no idea if you can make any sense of that. I'll probably roll back to v2 though that had a resume rare bug, but for now I'll skip requesting permission on startup and let the user trigger it.
if you changed your library to the following I suspect it would work:
Best Alex
The text was updated successfully, but these errors were encountered: