PixelFlasher icon indicating copy to clipboard operation
PixelFlasher copied to clipboard

Don't run flashing commands on UI thread

Open Tiebe opened this issue 1 year ago • 4 comments
trafficstars

You shouldn't run the fastboot flashing comamnds on the UI thread, since this causes the application to hang (unable to resize or move window, etc) while flashing.

Instead, run this on a background thread, and keep the main thread for the UI, while forwarding the logs to the this thread.

Tiebe avatar Jul 02 '24 15:07 Tiebe

Agreed 100% in principal, however aside from the fact that it adds complexity, one needs to worry about each and every background process function and accordingly manage the UI by disabling features that shouldn't be executed while the background process is still running. Forwarding logs from background thread process to UI console in real time rather than after completion is yet another non-trivial challenge. Another concern is, if you let the user interact with the UI while running a background process that produces logs, (by design PixelFlasher is highly verbose to help users with troubleshooting) you end up with interlaced logs, which makes it quite difficult to troubleshoot and trace down problems.

I spend a lot of time helping users (on xda forums and here) with their support files troubleshooting problems, the last thing I want when tracing events is interlaced events and logs, I understand I could create log categories and group them and what not, but I have no intentions on refactoring a lot of the code just so that the UI is not blocked while flashing, incidentally it is not totally blocked, there are Yield operations almost everywhere.

I have implemented thread based running background shell process, you can see here and it is used for certain invocations, however using it for flashing proved to be highly unreliable and problematic.

As stated in the readme, this was my first wxpyton project, and when I started coding this, I didn't know much about it, although I learned a lot along the way, by no means I consider myself an expert in the subject matter, and in fact I would welcome pull requests that make the project better and simpler.

badabing2005 avatar Jul 02 '24 21:07 badabing2005

Ahh, very understandable. I'll see if I have some time on my hands sometime soon to check it out.

Tiebe avatar Jul 02 '24 21:07 Tiebe

Using an API like https://wiki.wxpython.org/CallAfter looks very promising.

The idea is:

  • Run command via background thread, pass it a callback to update ui/on complete/whatever
  • UI receives the callback and locks/unlocks/updates etc (this can be implemented for logging too, you'd have to make the logger also run callbacks on a new log entry)

It does require a fair bit of work to implement (talking from experience with similar situations in kotlin) but isn't usually too difficult for the better UX you get as a result

androidacy-user avatar Sep 03 '24 19:09 androidacy-user

Using an API like https://wiki.wxpython.org/CallAfter looks very promising.

The idea is:

* Run command via background thread, pass it a callback to update ui/on complete/whatever

* UI receives the callback and locks/unlocks/updates etc (this can be implemented for logging too, you'd have to make the logger also run callbacks on a new log entry)

It does require a fair bit of work to implement (talking from experience with similar situations in kotlin) but isn't usually too difficult for the better UX you get as a result

This is already being used in PF. See here, here, and few other places in PIF manager. However this does not address the points I raised above.

If I have to wait for the completion callback, it's the same as locking, which by the way currently it doesn't totally lock, it yields at many points to allow the UI to refresh, but not necessarily interact with, which is the objective. If we allow interaction, then I'd have to handle every UI case, which is not something I would want to do.

Thanks for the suggestion. Sorry I missed your response here and this sat unanswered.

badabing2005 avatar Sep 10 '24 00:09 badabing2005

I used to use wxpython on the main thread along with worker threads that were thread-safe accessing GUI. But your code needs to be heavily modified to do that. I can create a pseudo code as an example for you if you're interested.

sinancetinkaya avatar Mar 27 '25 21:03 sinancetinkaya

it's not just about being thread safe, it's handling how to manage the UI why an operation is in progress. Allow / not allowing certain interaction based on context requires a lot logic code. Not only that, it make the code complex and more difficult to maintain. As you can see from my posts above,

badabing2005 avatar Mar 31 '25 11:03 badabing2005

Callbacks, callbacks, callbacks

I worked on the team that rewrote the entire networking stack for our apps so they didn't freeze when doing network calls. yes, it was a bit of a pain, but not as much pain as watching the app freeze and stutter every time a blocking operation froze the UI. same goes for PF, unfortunately even moreso because sometimes when it "freezes" would be a very bad, not good time to try to kill the "unresponsive" program

Example (psuedo code)

onLockUI = {
    allowClicksOnBUttons = false
}
onUnlockUI = {
      allowClicksOnBUttons = true
}
onMessage = {
  // show message/log/whatever
}

// user clicks
if (!allowClicksOnBUttons) {
showToast("Operation in progress, please wait")
} else {
  // ... do things ...
}

// when operation starts...
onLockUI()

// very important thing to tell the user
showLog("never gonna give you up")

// when done...
onUnlockUI()

my example is not a fully proper callback approach but its the easiest to implement in an async app that was previously doing the same things sync

androidacy-user avatar Jun 09 '25 23:06 androidacy-user

@androidacy-user I welcome pull requests that does all the right things without breaking anything.

badabing2005 avatar Jun 10 '25 00:06 badabing2005