Merge mozilla-inbound to mozilla-central. a=merge
authorDorel Luca <dluca@mozilla.com>
Wed, 07 Feb 2018 17:05:03 +0200
changeset 402722 65133e49fbfd5306632301f74be7cd15890bdf9f
parent 402712 f19dd1127198806c903f1b29f9690af8411c84d3 (current diff)
parent 402721 b8a6c14ad2804b410fe11a341360f13652649629 (diff)
child 402750 02cab40d67e2cd099f1a9b93a1638e2915b2192c
child 402780 f138690ccafddacd0de5c207f9c8f66be51001aa
push id33400
push userdluca@mozilla.com
push dateWed, 07 Feb 2018 15:05:16 +0000
treeherdermozilla-central@65133e49fbfd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone60.0a1
first release with
nightly linux32
65133e49fbfd / 60.0a1 / 20180207220120 / files
nightly mac
65133e49fbfd / 60.0a1 / 20180207220120 / files
nightly win32
65133e49fbfd / 60.0a1 / 20180207220120 / files
nightly win64
65133e49fbfd / 60.0a1 / 20180207220120 / files
nightly linux64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly mac
nightly win32
nightly win64
Merge mozilla-inbound to mozilla-central. a=merge
--- a/accessible/ipc/win/HandlerProvider.h
+++ b/accessible/ipc/win/HandlerProvider.h
@@ -10,16 +10,17 @@
 #include "mozilla/a11y/AccessibleHandler.h"
 #include "mozilla/AlreadyAddRefed.h"
 #include "mozilla/Atomics.h"
 #include "mozilla/mscom/IHandlerProvider.h"
 #include "mozilla/mscom/Ptr.h"
 #include "mozilla/mscom/StructStream.h"
 #include "mozilla/Mutex.h"
 #include "mozilla/UniquePtr.h"
+#include "HandlerData.h"
 
 struct NEWEST_IA2_INTERFACE;
 
 namespace mozilla {
 
 namespace mscom {
 
 class StructToStream;
--- a/devtools/client/themes/rules.css
+++ b/devtools/client/themes/rules.css
@@ -397,17 +397,16 @@
 }
 
 .ruleview-rule .ruleview-expander.theme-twisty:dir(rtl) {
   /* for preventing .theme-twisty's wrong direction in rtl; Bug 1296648 */
   transform: none;
 }
 
 .ruleview-newproperty {
-  /* (enable checkbox width: 12px) + (expander width: 15px) */
   margin-inline-start: -10px;
 }
 
 .ruleview-namecontainer,
 .ruleview-propertyvaluecontainer,
 .ruleview-propertyname,
 .ruleview-propertyvalue {
   text-decoration: inherit;
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -2380,16 +2380,27 @@ ContentParent::InitInternal(ProcessPrior
 
     for (StyleSheet* sheet : *sheetService->AuthorStyleSheets(backendType)) {
       URIParams uri;
       SerializeURI(sheet->GetSheetURI(), uri);
       Unused << SendLoadAndRegisterSheet(uri, nsIStyleSheetService::AUTHOR_SHEET);
     }
   }
 
+#if defined(XP_WIN)
+  // Send the info needed to join the browser process's audio session.
+  nsID id;
+  nsString sessionName;
+  nsString iconPath;
+  if (NS_SUCCEEDED(mozilla::widget::GetAudioSessionData(id, sessionName,
+                                                        iconPath))) {
+    Unused << SendSetAudioSessionData(id, sessionName, iconPath);
+  }
+#endif
+
 #ifdef MOZ_CONTENT_SANDBOX
   bool shouldSandbox = true;
   MaybeFileDesc brokerFd = void_t();
   // XXX: Checking the pref here makes it possible to enable/disable sandboxing
   // during an active session. Currently the pref is only used for testing
   // purpose. If the decision is made to permanently rely on the pref, this
   // should be changed so that it is required to restart firefox for the change
   // of value to take effect.
@@ -2411,26 +2422,16 @@ ContentParent::InitInternal(ProcessPrior
       MOZ_ASSERT(static_cast<const FileDescriptor&>(brokerFd).IsValid());
     }
   }
 #endif
   if (shouldSandbox && !SendSetProcessSandbox(brokerFd)) {
     KillHard("SandboxInitFailed");
   }
 #endif
-#if defined(XP_WIN)
-  // Send the info needed to join the browser process's audio session.
-  nsID id;
-  nsString sessionName;
-  nsString iconPath;
-  if (NS_SUCCEEDED(mozilla::widget::GetAudioSessionData(id, sessionName,
-                                                        iconPath))) {
-    Unused << SendSetAudioSessionData(id, sessionName, iconPath);
-  }
-#endif
 
   {
     RefPtr<ServiceWorkerRegistrar> swr = ServiceWorkerRegistrar::Get();
     MOZ_ASSERT(swr);
 
     nsTArray<ServiceWorkerRegistrationData> registrations;
     swr->GetRegistrations(registrations);
 
--- a/testing/geckodriver/CHANGES.md
+++ b/testing/geckodriver/CHANGES.md
@@ -3,19 +3,22 @@ Change log
 
 All notable changes to this program is documented in this file.
 
 Unreleased
 ----------
 
 ### Added
 
+- New `--jsdebugger` flag to open the Browser Toolbox when Firefox
+  launches.  This is useful for debugging Marionette internals.
+
 - Introduced the temporary, boolean capability
-  `moz:useNonSpecCompliantPointerOrigin` to
-  disable the WebDriver conforming behavior of calculating the Pointer Origin.
+  `moz:useNonSpecCompliantPointerOrigin` to disable the WebDriver
+  conforming behavior of calculating the Pointer Origin.
 
 ### Changed
 
 - HTTP status code for the [`StaleElementReference`] error changed
   from 400 (Bad Request) to 404 (Not Found)
 
 - Backtraces from geckodriver no longer substitute for missing
   Marionette stacktraces
--- a/testing/geckodriver/README.md
+++ b/testing/geckodriver/README.md
@@ -565,16 +565,23 @@ it will pick a free port assigned by the
 #### <code>-p <var>PORT</var></code>/<code>--port <var>PORT</var></code>
 
 Port to use for the WebDriver server.  Defaults to 4444.
 
 A helpful trick is that it is possible to bind to 0 to get the system
 to atomically assign a free port.
 
 
+#### <code>--jsdebugger</code>
+
+Attach [browser toolbox] debugger when Firefox starts.  This is
+useful for debugging [Marionette] internals.
+
+[browser toolbox]: https://developer.mozilla.org/en-US/docs/Tools/Browser_Toolbox
+
 #### <code>-v<var>[v]</var></code>
 
 Increases the logging verbosity by to debug level when passing a single
 `-v`, or to trace level if `-vv` is passed.  This is analogous to passing
 `--log debug` and `--log trace`, respectively.
 
 
 Building
--- a/testing/geckodriver/src/main.rs
+++ b/testing/geckodriver/src/main.rs
@@ -118,16 +118,20 @@ fn app<'a, 'b>() -> App<'a, 'b> {
             .long("marionette-port")
             .value_name("PORT")
             .help("Port to use to connect to Gecko (default: random free port)")
             .takes_value(true))
         .arg(Arg::with_name("connect_existing")
             .long("connect-existing")
             .requires("marionette_port")
             .help("Connect to an existing Firefox instance"))
+        .arg(Arg::with_name("jsdebugger")
+            .long("jsdebugger")
+            .takes_value(false)
+            .help("Attach browser toolbox debugger for Firefox"))
         .arg(Arg::with_name("verbosity")
             .short("v")
             .multiple(true)
             .conflicts_with("log_level")
             .help("Log level verbosity (-v for debug and -vv for trace level)"))
         .arg(Arg::with_name("log_level")
             .long("log")
             .takes_value(true)
@@ -185,19 +189,20 @@ fn run() -> ProgramResult {
         }
     };
     logging::init(&log_level);
 
     info!("geckodriver {}", BuildInfo);
 
     let settings = MarionetteSettings {
         port: marionette_port,
-        binary: binary,
+        binary,
+        log_level,
         connect_existing: matches.is_present("connect_existing"),
-        log_level: log_level,
+        jsdebugger: matches.is_present("jsdebugger"),
     };
     let handler = MarionetteHandler::new(settings);
     let listening = webdriver::server::start(addr, handler, &extension_routes()[..])
         .map_err(|err| (ExitCode::Unavailable, err.to_string()))?;
     info!("Listening on {}", listening.socket);
 
     Ok(())
 }
--- a/testing/geckodriver/src/marionette.rs
+++ b/testing/geckodriver/src/marionette.rs
@@ -377,16 +377,20 @@ pub struct LogOptions {
 }
 
 #[derive(Default)]
 pub struct MarionetteSettings {
     pub port: Option<u16>,
     pub binary: Option<PathBuf>,
     pub connect_existing: bool,
 
+    /// Brings up the Browser Toolbox when starting Firefox,
+    /// letting you debug internals.
+    pub jsdebugger: bool,
+
     /// Optionally increase Marionette's verbosity by providing a log
     /// level. The Gecko default is LogLevel::Info for optimised
     /// builds and LogLevel::Debug for debug builds.
     pub log_level: Option<LogLevel>,
 }
 
 pub struct MarionetteHandler {
     connection: Mutex<Option<MarionetteConnection>>,
@@ -457,27 +461,30 @@ impl MarionetteHandler {
             .map_err(|e| {
                 WebDriverError::new(ErrorStatus::SessionNotCreated,
                                     format!("Failed to set preferences: {}", e))
             })?;
 
 
         let mut runner = FirefoxRunner::new(&binary, profile);
 
+        // https://developer.mozilla.org/docs/Environment_variables_affecting_crash_reporting
         runner
-             // double-dashed flags are not accepted on Windows systems
-            .arg("-marionette")
-             // https://developer.mozilla.org/docs/Environment_variables_affecting_crash_reporting
             .env("MOZ_CRASHREPORTER", "1")
             .env("MOZ_CRASHREPORTER_NO_REPORT", "1")
             .env("MOZ_CRASHREPORTER_SHUTDOWN", "1");
 
+        // double-dashed flags are not accepted on Windows systems
+        runner.arg("-marionette");
+        if self.settings.jsdebugger {
+            runner.arg("-jsdebugger");
+        }
         if let Some(args) = options.args.as_ref() {
             runner.args(args);
-        };
+        }
 
         let browser_proc = runner.start()
             .map_err(|e| {
                 WebDriverError::new(ErrorStatus::SessionNotCreated,
                                     format!("Failed to start browser {}: {}",
                                             binary.display(), e))
             })?;
         self.browser = Some(browser_proc);
@@ -495,16 +502,24 @@ impl MarionetteHandler {
         for &(ref name, ref value) in prefs::DEFAULT.iter() {
             if !custom_profile || !prefs.contains_key(name) {
                 prefs.insert((*name).clone(), (*value).clone());
             }
         }
 
         prefs.insert_slice(&extra_prefs[..]);
 
+        if self.settings.jsdebugger {
+            prefs.insert("devtools.browsertoolbox.panel", Pref::new("jsdebugger".to_owned()));
+            prefs.insert("devtools.debugger.remote-enabled", Pref::new(true));
+            prefs.insert("devtools.chrome.enabled", Pref::new(true));
+            prefs.insert("devtools.debugger.prompt-connection", Pref::new(false));
+            prefs.insert("marionette.debugging.clicktostart", Pref::new(true));
+        }
+
         if let Some(ref level) = self.current_log_level {
             prefs.insert("marionette.log.level", Pref::new(level.to_string()));
         };
         prefs.insert("marionette.port", Pref::new(port as i64));
 
         prefs.write().map_err(|_| WebDriverError::new(ErrorStatus::UnknownError,
                                                       "Unable to write Firefox profile"))
     }
--- a/widget/windows/AudioSession.cpp
+++ b/widget/windows/AudioSession.cpp
@@ -15,16 +15,17 @@
 
 //#include "AudioSession.h"
 #include "nsCOMPtr.h"
 #include "nsServiceManagerUtils.h"
 #include "nsString.h"
 #include "nsThreadUtils.h"
 #include "nsXULAppAPI.h"
 #include "mozilla/Attributes.h"
+#include "mozilla/Mutex.h"
 
 #include <objbase.h>
 
 namespace mozilla {
 namespace widget {
 
 /*
  * To take advantage of what Vista+ have to offer with respect to audio,
@@ -49,16 +50,18 @@ public:
                                       DWORD aChangedChannel,
                                       LPCGUID aContext);
   STDMETHODIMP OnDisplayNameChanged(LPCWSTR aDisplayName, LPCGUID aContext);
   STDMETHODIMP OnGroupingParamChanged(LPCGUID aGroupingParam, LPCGUID aContext);
   STDMETHODIMP OnIconPathChanged(LPCWSTR aIconPath, LPCGUID aContext);
   STDMETHODIMP OnSessionDisconnected(AudioSessionDisconnectReason aReason);
 private:
   nsresult OnSessionDisconnectedInternal();
+  nsresult CommitAudioSessionData();
+
 public:
   STDMETHODIMP OnSimpleVolumeChanged(float aVolume,
                                      BOOL aMute,
                                      LPCGUID aContext);
   STDMETHODIMP OnStateChanged(AudioSessionState aState);
 
   nsresult Start();
   nsresult Stop();
@@ -81,16 +84,18 @@ public:
     AUDIO_SESSION_DISCONNECTED // Audio session disconnected
   };
 protected:
   RefPtr<IAudioSessionControl> mAudioSessionControl;
   nsString mDisplayName;
   nsString mIconPath;
   nsID mSessionGroupingParameter;
   SessionState mState;
+  // Guards the IAudioSessionControl
+  mozilla::Mutex mMutex;
 
   ThreadSafeAutoRefCnt mRefCnt;
   NS_DECL_OWNINGTHREAD
 
   static AudioSession* sService;
 };
 
 nsresult
@@ -122,17 +127,18 @@ RecvAudioSessionData(const nsID& aID,
 {
   return AudioSession::GetSingleton()->SetSessionData(aID,
                                                       aSessionName,
                                                       aIconPath);
 }
 
 AudioSession* AudioSession::sService = nullptr;
 
-AudioSession::AudioSession()
+AudioSession::AudioSession() :
+  mMutex("AudioSessionControl")
 {
   mState = UNINITIALIZED;
 }
 
 AudioSession::~AudioSession()
 {
 
 }
@@ -249,58 +255,47 @@ AudioSession::Start()
   hr = device->Activate(IID_IAudioSessionManager,
                         CLSCTX_ALL,
                         nullptr,
                         getter_AddRefs(manager));
   if (FAILED(hr)) {
     return NS_ERROR_FAILURE;
   }
 
+  MutexAutoLock lock(mMutex);
   hr = manager->GetAudioSessionControl(&GUID_NULL,
                                        0,
                                        getter_AddRefs(mAudioSessionControl));
 
   if (FAILED(hr)) {
     return NS_ERROR_FAILURE;
   }
 
-  hr = mAudioSessionControl->SetGroupingParam((LPGUID)&mSessionGroupingParameter,
-                                              nullptr);
-  if (FAILED(hr)) {
-    StopInternal();
-    return NS_ERROR_FAILURE;
-  }
-
-  hr = mAudioSessionControl->SetDisplayName(mDisplayName.get(), nullptr);
-  if (FAILED(hr)) {
-    StopInternal();
-    return NS_ERROR_FAILURE;
-  }
-
-  hr = mAudioSessionControl->SetIconPath(mIconPath.get(), nullptr);
-  if (FAILED(hr)) {
-    StopInternal();
-    return NS_ERROR_FAILURE;
-  }
-
   // Increments refcount of 'this'.
   hr = mAudioSessionControl->RegisterAudioSessionNotification(this);
   if (FAILED(hr)) {
     StopInternal();
     return NS_ERROR_FAILURE;
   }
 
+  nsCOMPtr<nsIRunnable> runnable =
+    NewRunnableMethod("AudioSession::CommitAudioSessionData",
+                      this, &AudioSession::CommitAudioSessionData);
+  NS_DispatchToMainThread(runnable);
+
   mState = STARTED;
 
   return NS_OK;
 }
 
 void
 AudioSession::StopInternal()
 {
+  mMutex.AssertCurrentThreadOwns();
+
   if (mAudioSessionControl &&
       (mState == STARTED || mState == STOPPED)) {
     // Decrement refcount of 'this'
     mAudioSessionControl->UnregisterAudioSessionNotification(this);
   }
   mAudioSessionControl = nullptr;
 }
 
@@ -313,16 +308,17 @@ AudioSession::Stop()
              "State invariants violated");
   SessionState state = mState;
   mState = STOPPED;
 
   {
     RefPtr<AudioSession> kungFuDeathGrip;
     kungFuDeathGrip.swap(sService);
 
+    MutexAutoLock lock(mMutex);
     StopInternal();
   }
 
   if (state != UNINITIALIZED) {
     ::CoUninitialize();
   }
   return NS_OK;
 }
@@ -369,16 +365,49 @@ AudioSession::SetSessionData(const nsID&
   mState = CLONED;
 
   CopynsID(mSessionGroupingParameter, aID);
   mDisplayName = aSessionName;
   mIconPath = aIconPath;
   return NS_OK;
 }
 
+nsresult
+AudioSession::CommitAudioSessionData()
+{
+  MutexAutoLock lock(mMutex);
+
+  if (!mAudioSessionControl) {
+    // Stop() was called before we had a chance to do this.
+    return NS_OK;
+  }
+
+  HRESULT hr =
+    mAudioSessionControl->SetGroupingParam((LPGUID)&mSessionGroupingParameter,
+                                           nullptr);
+  if (FAILED(hr)) {
+    StopInternal();
+    return NS_ERROR_FAILURE;
+  }
+
+  hr = mAudioSessionControl->SetDisplayName(mDisplayName.get(), nullptr);
+  if (FAILED(hr)) {
+    StopInternal();
+    return NS_ERROR_FAILURE;
+  }
+
+  hr = mAudioSessionControl->SetIconPath(mIconPath.get(), nullptr);
+  if (FAILED(hr)) {
+    StopInternal();
+    return NS_ERROR_FAILURE;
+  }
+
+  return NS_OK;
+}
+
 STDMETHODIMP
 AudioSession::OnChannelVolumeChanged(DWORD aChannelCount,
                                      float aChannelVolumeArray[],
                                      DWORD aChangedChannel,
                                      LPCGUID aContext)
 {
   return S_OK; // NOOP
 }
@@ -414,25 +443,30 @@ AudioSession::OnSessionDisconnected(Audi
                       this, &AudioSession::OnSessionDisconnectedInternal);
   NS_DispatchToMainThread(runnable);
   return S_OK;
 }
 
 nsresult
 AudioSession::OnSessionDisconnectedInternal()
 {
-  if (!mAudioSessionControl)
-    return NS_OK;
+  {
+    // We need to release the mutex before we call Start().
+    MutexAutoLock lock(mMutex);
+
+    if (!mAudioSessionControl)
+      return NS_OK;
 
-  // When successful, UnregisterAudioSessionNotification will decrement the
-  // refcount of 'this'.  Start will re-increment it.  In the interim,
-  // we'll need to reference ourselves.
-  RefPtr<AudioSession> kungFuDeathGrip(this);
-  mAudioSessionControl->UnregisterAudioSessionNotification(this);
-  mAudioSessionControl = nullptr;
+    // When successful, UnregisterAudioSessionNotification will decrement the
+    // refcount of 'this'.  Start will re-increment it.  In the interim,
+    // we'll need to reference ourselves.
+    RefPtr<AudioSession> kungFuDeathGrip(this);
+    mAudioSessionControl->UnregisterAudioSessionNotification(this);
+    mAudioSessionControl = nullptr;
+  }
 
   mState = AUDIO_SESSION_DISCONNECTED;
   CoUninitialize();
   Start(); // If it fails there's not much we can do.
   return NS_OK;
 }
 
 STDMETHODIMP