Bug 1585801 - Fixing crash when folder is not writable and refactored logic. r=jrmuizel
authorKris Taeleman <ktaeleman@mozilla.com>
Tue, 15 Oct 2019 17:03:22 +0000
changeset 497708 5506d1803e158df5504bc74a7818cb78dca6420c
parent 497707 f24ddb55b48bf6815a83b1e8ee4dc33b87b8411e
child 497709 b70dd8f559807fa7fa72f40595b088e140b16a25
push id114154
push userbtara@mozilla.com
push dateThu, 17 Oct 2019 09:58:40 +0000
treeherdermozilla-inbound@273c3db836e1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel
bugs1585801
milestone71.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1585801 - Fixing crash when folder is not writable and refactored logic. r=jrmuizel Differential Revision: https://phabricator.services.mozilla.com/D48999
dom/base/nsDOMWindowUtils.cpp
gfx/layers/ipc/PWebRenderBridge.ipdl
gfx/layers/wr/WebRenderBridgeChild.cpp
gfx/layers/wr/WebRenderBridgeChild.h
gfx/layers/wr/WebRenderBridgeParent.cpp
gfx/layers/wr/WebRenderBridgeParent.h
gfx/thebes/gfxPlatform.cpp
gfx/webrender_bindings/WebRenderAPI.cpp
gfx/webrender_bindings/WebRenderAPI.h
gfx/webrender_bindings/src/bindings.rs
gfx/wr/webrender/src/record.rs
gfx/wr/webrender/src/render_backend.rs
gfx/wr/webrender/src/renderer.rs
gfx/wr/webrender_api/src/api.rs
modules/libpref/init/all.js
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -4061,17 +4061,19 @@ nsDOMWindowUtils::SetCompositionRecordin
     }
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::SetTransactionLogging(bool aValue) {
-  Preferences::SetBool("gfx.webrender.debug.log-transactions", aValue);
+  if (WebRenderBridgeChild* wrbc = GetWebRenderBridge()) {
+    wrbc->SetTransactionLogging(aValue);
+  }
   return NS_OK;
 }
 
 void nsDOMWindowUtils::ReportErrorMessageForWindow(
     const nsAString& aErrorMessage, const char* aClassification,
     bool aFromChrome) {
   bool isPrivateWindow = false;
 
--- a/gfx/layers/ipc/PWebRenderBridge.ipdl
+++ b/gfx/layers/ipc/PWebRenderBridge.ipdl
@@ -68,16 +68,19 @@ parent:
   sync GetSnapshot(PTexture texture);
   async SetLayersObserverEpoch(LayersObserverEpoch childEpoch);
   async ClearCachedResources();
   // Schedule a composite if one isn't already scheduled.
   async ScheduleComposite();
   // Save the frame capture to disk
   async Capture();
 
+  // Enable/Disable transaction logging
+  async SetTransactionLogging(bool aValue);
+
   // Replacement for PCompositorBridge::SyncWithCompositor, but for WR. We need
   // it on PWebRenderBridge because it associated with a particular top-level
   // window, and PCompositorBridge doesn't allow doing that in a secure manner.
   sync SyncWithCompositor();
 
   // These correspond exactly to the equivalent APIs in PLayerTransaction -
   // see those for documentation.
   async SetConfirmedTargetAPZC(uint64_t aInputBlockId, SLGuidAndRenderRoot[] aTargets);
--- a/gfx/layers/wr/WebRenderBridgeChild.cpp
+++ b/gfx/layers/wr/WebRenderBridgeChild.cpp
@@ -628,10 +628,14 @@ void WebRenderBridgeChild::DeallocResour
   }
   MOZ_ASSERT(RefCountedShm::GetReferenceCount(aShm) == 0);
 
   RefCountedShm::Dealloc(this, aShm);
 }
 
 void WebRenderBridgeChild::Capture() { this->SendCapture(); }
 
+void WebRenderBridgeChild::SetTransactionLogging(bool aValue) {
+  this->SendSetTransactionLogging(aValue);
+}
+
 }  // namespace layers
 }  // namespace mozilla
--- a/gfx/layers/wr/WebRenderBridgeChild.h
+++ b/gfx/layers/wr/WebRenderBridgeChild.h
@@ -176,16 +176,17 @@ class WebRenderBridgeChild final : publi
   /// Do not use this for anything else.
   bool AllocResourceShmem(size_t aSize, RefCountedShmem& aShm);
   /// Dealloc shared memory that was allocated with AllocResourceShmem.
   ///
   /// Do not use this for anything else.
   void DeallocResourceShmem(RefCountedShmem& aShm);
 
   void Capture();
+  void SetTransactionLogging(bool aValue);
 
  private:
   friend class CompositorBridgeChild;
 
   ~WebRenderBridgeChild();
 
   wr::ExternalImageId GetNextExternalImageId();
 
--- a/gfx/layers/wr/WebRenderBridgeParent.cpp
+++ b/gfx/layers/wr/WebRenderBridgeParent.cpp
@@ -2014,16 +2014,24 @@ void WebRenderBridgeParent::ScheduleForc
 
 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvCapture() {
   if (!mDestroyed) {
     mApis[wr::RenderRoot::Default]->Capture();
   }
   return IPC_OK();
 }
 
+mozilla::ipc::IPCResult WebRenderBridgeParent::RecvSetTransactionLogging(
+  const bool& aValue) {
+  if (!mDestroyed) {
+    mApis[wr::RenderRoot::Default]->SetTransactionLogging(aValue);
+  }
+  return IPC_OK();
+}
+
 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvSyncWithCompositor() {
   FlushSceneBuilds();
   if (RefPtr<WebRenderBridgeParent> root = GetRootWebRenderBridgeParent()) {
     root->FlushFrameGeneration();
   }
   FlushFramePresentation();
   // Finally, we force the AsyncImagePipelineManager to handle all the
   // pipeline updates produced in the last step, so that it frees any
--- a/gfx/layers/wr/WebRenderBridgeParent.h
+++ b/gfx/layers/wr/WebRenderBridgeParent.h
@@ -146,16 +146,17 @@ class WebRenderBridgeParent final
   mozilla::ipc::IPCResult RecvGetSnapshot(PTextureParent* aTexture) override;
 
   mozilla::ipc::IPCResult RecvSetLayersObserverEpoch(
       const LayersObserverEpoch& aChildEpoch) override;
 
   mozilla::ipc::IPCResult RecvClearCachedResources() override;
   mozilla::ipc::IPCResult RecvScheduleComposite() override;
   mozilla::ipc::IPCResult RecvCapture() override;
+  mozilla::ipc::IPCResult RecvSetTransactionLogging(const bool&) override;
   mozilla::ipc::IPCResult RecvSyncWithCompositor() override;
 
   mozilla::ipc::IPCResult RecvSetConfirmedTargetAPZC(
       const uint64_t& aBlockId,
       nsTArray<SLGuidAndRenderRoot>&& aTargets) override;
 
   mozilla::ipc::IPCResult RecvSetTestSampleTime(
       const TimeStamp& aTime) override;
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -595,17 +595,16 @@ static void WebRenderDebugPrefChangeCall
   GFX_WEBRENDER_DEBUG(".disable-opaque-pass",
                       wr::DebugFlags_DISABLE_OPAQUE_PASS)
   GFX_WEBRENDER_DEBUG(".disable-alpha-pass", wr::DebugFlags_DISABLE_ALPHA_PASS)
   GFX_WEBRENDER_DEBUG(".disable-clip-masks", wr::DebugFlags_DISABLE_CLIP_MASKS)
   GFX_WEBRENDER_DEBUG(".disable-text-prims", wr::DebugFlags_DISABLE_TEXT_PRIMS)
   GFX_WEBRENDER_DEBUG(".disable-gradient-prims",
                       wr::DebugFlags_DISABLE_GRADIENT_PRIMS)
   GFX_WEBRENDER_DEBUG(".obscure-images", wr::DebugFlags_OBSCURE_IMAGES)
-  GFX_WEBRENDER_DEBUG(".log-transactions", wr::DebugFlags_LOG_TRANSACTIONS)
 #undef GFX_WEBRENDER_DEBUG
 
   gfx::gfxVars::SetWebRenderDebugFlags(flags.bits);
 }
 
 #if defined(USE_SKIA)
 static uint32_t GetSkiaGlyphCacheSize() {
   // Only increase font cache size on non-android to save memory.
--- a/gfx/webrender_bindings/WebRenderAPI.cpp
+++ b/gfx/webrender_bindings/WebRenderAPI.cpp
@@ -579,16 +579,20 @@ void WebRenderAPI::WaitFlushed() {
 }
 
 void WebRenderAPI::Capture() {
   uint8_t bits = 3;                 // TODO: get from JavaScript
   const char* path = "wr-capture";  // TODO: get from JavaScript
   wr_api_capture(mDocHandle, path, bits);
 }
 
+void WebRenderAPI::SetTransactionLogging(bool aValue) {
+  wr_api_set_transaction_logging(mDocHandle, aValue);
+}
+
 void WebRenderAPI::SetCompositionRecorder(
     UniquePtr<layers::WebRenderCompositionRecorder> aRecorder) {
   class SetCompositionRecorderEvent final : public RendererEvent {
    public:
     explicit SetCompositionRecorderEvent(
         UniquePtr<layers::WebRenderCompositionRecorder> aRecorder)
         : mRecorder(std::move(aRecorder)) {
       MOZ_COUNT_CTOR(SetCompositionRecorderEvent);
--- a/gfx/webrender_bindings/WebRenderAPI.h
+++ b/gfx/webrender_bindings/WebRenderAPI.h
@@ -259,16 +259,17 @@ class WebRenderAPI final {
   wr::RenderRoot GetRenderRoot() const { return mRenderRoot; }
   uint32_t GetMaxTextureSize() const { return mMaxTextureSize; }
   bool GetUseANGLE() const { return mUseANGLE; }
   bool GetUseDComp() const { return mUseDComp; }
   bool GetUseTripleBuffering() const { return mUseTripleBuffering; }
   layers::SyncHandle GetSyncHandle() const { return mSyncHandle; }
 
   void Capture();
+  void SetTransactionLogging(bool aValue);
 
   void SetCompositionRecorder(
       UniquePtr<layers::WebRenderCompositionRecorder> aRecorder);
 
   /**
    * Write the frames collected by the |WebRenderCompositionRecorder| to disk.
    *
    * If there is not currently a recorder, this is a no-op.
--- a/gfx/webrender_bindings/src/bindings.rs
+++ b/gfx/webrender_bindings/src/bindings.rs
@@ -1859,16 +1859,24 @@ pub extern "C" fn wr_api_capture(
             return
         }
     }
 
     let bits = CaptureBits::from_bits(bits_raw as _).unwrap();
     dh.api.save_capture(path, bits);
 }
 
+#[no_mangle]
+pub extern "C" fn wr_api_set_transaction_logging(
+    dh: &mut DocumentHandle,
+    aValue: bool
+) {
+    dh.api.send_debug_cmd(DebugCommand::SetTransactionLogging(aValue));
+}
+
 #[cfg(target_os = "windows")]
 fn read_font_descriptor(
     bytes: &mut WrVecU8,
     index: u32
 ) -> NativeFontHandle {
     let wchars = bytes.convert_into_vec::<u16>();
     NativeFontHandle {
         path: PathBuf::from(OsString::from_wide(&wchars)),
--- a/gfx/wr/webrender/src/record.rs
+++ b/gfx/wr/webrender/src/record.rs
@@ -62,19 +62,18 @@ impl ApiRecordingReceiver for BinaryReco
 }
 
 #[derive(Debug)]
 pub struct LogRecorder {
     file: File,
 }
 
 impl LogRecorder {
-    pub fn new(dest: &PathBuf) -> LogRecorder {
-        let file = File::create(dest).unwrap();
-        LogRecorder { file }
+    pub fn new(dest: &PathBuf) -> Option<Box<LogRecorder>> {
+        Some(Box::new(LogRecorder { file: File::create(dest).ok()? }))
     }
 }
 
 impl ApiRecordingReceiver for LogRecorder {
     fn write_msg(&mut self, _: u32, msg: &ApiMsg) {
         let current_time = time::now_utc();
         writeln!(self.file, "{}:{}ms - {:?}", current_time.rfc3339(), current_time.tm_nsec / 1000000, msg).unwrap();
         match *msg {
--- a/gfx/wr/webrender/src/render_backend.rs
+++ b/gfx/wr/webrender/src/render_backend.rs
@@ -696,17 +696,17 @@ pub struct RenderBackend {
     gpu_cache: GpuCache,
     resource_cache: ResourceCache,
 
     frame_config: FrameBuilderConfig,
     documents: FastHashMap<DocumentId, Document>,
 
     notifier: Box<dyn RenderNotifier>,
     recorder: Option<Box<dyn ApiRecordingReceiver>>,
-    logrecorder: Option<Box<dyn ApiRecordingReceiver>>,
+    logrecorder: Option<Box<LogRecorder>>,
     sampler: Option<Box<dyn AsyncPropertySampler + Send>>,
     size_of_ops: Option<MallocSizeOfOps>,
     debug_flags: DebugFlags,
     namespace_alloc_by_client: bool,
 
     recycler: Recycler,
 }
 
@@ -951,28 +951,16 @@ impl RenderBackend {
                     SceneBuilderResult::Stopped => {
                         panic!("We haven't sent a Stop yet, how did we get a Stopped back?");
                     }
                 }
             }
 
             status = match self.api_rx.recv() {
                 Ok(msg) => {
-                    if self.debug_flags.contains(DebugFlags::LOG_TRANSACTIONS) {
-                        if let None = self.logrecorder {
-                            let current_time = time::now_utc().to_local();
-                            let name = format!("wr-log-{}.log",
-                                current_time.strftime("%Y%m%d_%H%M%S").unwrap()
-                            );
-                            self.logrecorder = Some(Box::new(LogRecorder::new(&PathBuf::from(name))))
-                        }
-                    } else {
-                        self.logrecorder = None;
-                    }
-
                     if let Some(ref mut r) = self.logrecorder {
                         r.write_msg(frame_counter, &msg);
                     }
 
 
                     if let Some(ref mut r) = self.recorder {
                         r.write_msg(frame_counter, &msg);
                     }
@@ -1175,16 +1163,31 @@ impl RenderBackend {
                                 ));
                             }
                         }
 
                         // Note: we can't pass `LoadCapture` here since it needs to arrive
                         // before the `PublishDocument` messages sent by `load_capture`.
                         return RenderBackendStatus::Continue;
                     }
+                    DebugCommand::SetTransactionLogging(value) => {
+                        match (value, self.logrecorder.as_ref()) {
+                            (true, None) => {
+                                    let current_time = time::now_utc().to_local();
+                                    let name = format!("wr-log-{}.log",
+                                        current_time.strftime("%Y%m%d_%H%M%S").unwrap()
+                                    );
+                                    self.logrecorder = LogRecorder::new(&PathBuf::from(name));
+                            },
+                            (false, _) => self.logrecorder = None,
+                            _ => (),
+                        };
+
+                        return RenderBackendStatus::Continue;
+                    }
                     DebugCommand::ClearCaches(mask) => {
                         self.resource_cache.clear(mask);
                         return RenderBackendStatus::Continue;
                     }
                     DebugCommand::SimulateLongSceneBuild(time_ms) => {
                         self.scene_tx.send(SceneBuilderRequest::SimulateLongSceneBuild(time_ms)).unwrap();
                         return RenderBackendStatus::Continue;
                     }
--- a/gfx/wr/webrender/src/renderer.rs
+++ b/gfx/wr/webrender/src/renderer.rs
@@ -2786,17 +2786,18 @@ impl Renderer {
             debug_root.add(builder.build());
         }
 
         serde_json::to_string(&debug_root).unwrap()
     }
 
     fn handle_debug_command(&mut self, command: DebugCommand) {
         match command {
-            DebugCommand::EnableDualSourceBlending(_) => {
+            DebugCommand::EnableDualSourceBlending(_) |
+            DebugCommand::SetTransactionLogging(_) => {
                 panic!("Should be handled by render backend");
             }
             DebugCommand::FetchDocuments |
             DebugCommand::FetchClipScrollTree => {}
             DebugCommand::FetchRenderTasks => {
                 let json = self.get_render_tasks_for_debugger();
                 self.debug_server.send(json);
             }
--- a/gfx/wr/webrender_api/src/api.rs
+++ b/gfx/wr/webrender_api/src/api.rs
@@ -770,16 +770,18 @@ pub enum DebugCommand {
     /// Invalidate GPU cache, forcing the update from the CPU mirror.
     InvalidateGpuCache,
     /// Causes the scene builder to pause for a given amount of milliseconds each time it
     /// processes a transaction.
     SimulateLongSceneBuild(u32),
     /// Causes the low priority scene builder to pause for a given amount of milliseconds
     /// each time it processes a transaction.
     SimulateLongLowPrioritySceneBuild(u32),
+    // Logs transactions to a file for debugging purposes
+    SetTransactionLogging(bool),
 }
 
 #[derive(Clone, Deserialize, Serialize)]
 pub enum ApiMsg {
     /// Add/remove/update images and fonts.
     UpdateResources(Vec<ResourceUpdate>),
     /// Gets the glyph dimensions
     GetGlyphDimensions(
@@ -1135,17 +1137,16 @@ bitflags! {
         /// Disable various bits of the WebRender pipeline, to help narrow
         /// down where slowness might be coming from.
         const DISABLE_OPAQUE_PASS = 1 << 19;
         const DISABLE_ALPHA_PASS = 1 << 20;
         const DISABLE_CLIP_MASKS = 1 << 21;
         const DISABLE_TEXT_PRIMS = 1 << 22;
         const DISABLE_GRADIENT_PRIMS = 1 << 23;
         const OBSCURE_IMAGES = 1 << 24;
-        const LOG_TRANSACTIONS = 1 << 25;
     }
 }
 
 pub struct RenderApi {
     api_sender: MsgSender<ApiMsg>,
     payload_sender: PayloadSender,
     namespace_id: IdNamespace,
     next_id: Cell<ResourceId>,
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -670,17 +670,16 @@ pref("gfx.webrender.debug.echo-driver-me
 pref("gfx.webrender.debug.new-frame-indicator", false);
 pref("gfx.webrender.debug.new-scene-indicator", false);
 pref("gfx.webrender.debug.show-overdraw", false);
 pref("gfx.webrender.debug.slow-frame-indicator", false);
 pref("gfx.webrender.debug.picture-caching", false);
 pref("gfx.webrender.debug.primitives", false);
 pref("gfx.webrender.debug.small-screen", false);
 pref("gfx.webrender.debug.obscure-images", false);
-pref("gfx.webrender.debug.log-transactions", false);
 
 pref("accessibility.warn_on_browsewithcaret", true);
 
 pref("accessibility.browsewithcaret_shortcut.enabled", true);
 
 #ifndef XP_MACOSX
   // Tab focus model bit field:
   // 1 focuses text controls, 2 focuses other form elements, 4 adds links.