fix_dont_delete_SerialPortManager_on_main_thread.patch 3.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
  2. From: John Kleinschmidt <[email protected]>
  3. Date: Wed, 5 Jan 2022 15:01:31 -0500
  4. Subject: fix: dont delete SerialPortManager on the main thread
  5. This patch is neccessary because of the changes made in
  6. https://chromium-review.googlesource.com/c/chromium/src/+/3283743.
  7. Several DCHECKs was firing because AddObserver runs in the WorkerThread but
  8. RemoveObserver runs in the UI thread. Ceasing to delete the
  9. `SerialPortManagerImpl` class on the main thread prevents this problem.
  10. A bit more of explanation from @deepak1556 as to why:
  11. SerialPortManagerImpl which is responsible for holding the mojo connection
  12. between the device service process and client has this following unique
  13. lifetime,
  14. // Threading notes:
  15. // 1. Created on the UI thread.
  16. // 2. Used on the UI thread runner (macOS only), otherwise on a blocking task
  17. // runner.
  18. // 3. Deleted on the same runner on which it is used *except* sometimes
  19. // during shutdown when the runner threadpool is already shutdown.
  20. // See crbug.com/1263149#c20 for details.
  21. An instance of this class is created when the device service is instantiated
  22. https://source.chromium.org/chromium/chromium/src/+/main:services/device/device_service.cc;l=122-135
  23. On windows and linux from the above code you can see that a blocking task
  24. runner is created to perform operations via this manager. DeviceService itself
  25. has a lifetime of being associated with the local storage of a sequence, in
  26. most cases this will be the main thread sequence of the application. Now when
  27. you establish a connection with the device service via
  28. SerialChooserContext::EnsurePortManagerConnection
  29. https://github.com/electron/electron/blob/dd4eae8a3b7f707bcd3d083d553988a29e332189/shell/browser/serial/serial_chooser_context.cc#L206-L207
  30. although the call is original made on the UI thread, it will be bound to the
  31. blocking task runner sequence for windows and linux in the device service end
  32. via https://source.chromium.org/chromium/chromium/src/+/main:services/device/device_service.cc;l=341-349
  33. when binding the receiver. Based on the stack trace of the crash, the
  34. port_manager_ receiver that is bound on a sequence is not destroyed on the same
  35. sequence during shutdown. But that would be weird given
  36. https://source.chromium.org/chromium/chromium/src/+/main:services/device/device_service.cc;l=155-156
  37. which ensures that SerialPortManagerImpl gets destroyed on the bound sequence.
  38. This is where https://chromium-review.googlesource.com/c/chromium/src/+/3283743
  39. gives clarity that the DeleteSoon task never completed because the threadpool
  40. instance was already shutdown by the time device service was being destroyed
  41. leading to a leak and now they instead just synchronously delete the instance
  42. on the main thread sequence which leads to the above DCHECK failure. So tl:dr,
  43. this is not a new bug it was always present due to the lifetime associated with
  44. this service, it just came to light because of the above CL. I am pretty sure
  45. upstream would also hit this DCHECK, so give it a try with content_shell or
  46. chrome and that would help reporting upstream crbug.
  47. diff --git a/services/device/device_service.cc b/services/device/device_service.cc
  48. index 11a7b2902490986ba2462f92c3b3e5ae1b1a127f..32d591621c7206affab50ef061aa565527d5952f 100644
  49. --- a/services/device/device_service.cc
  50. +++ b/services/device/device_service.cc
  51. @@ -159,7 +159,7 @@ DeviceService::~DeviceService() {
  52. // naturally sequenced after the last task on
  53. // |serial_port_manager_task_runner_| per ThreadPool shutdown semantics).
  54. // See crbug.com/1263149#c20 for details.
  55. - delete serial_port_manager;
  56. + // delete serial_port_manager;
  57. }
  58. #endif // defined(IS_SERIAL_ENABLED_PLATFORM)
  59. }