Bug 926746 - Part 2: nsContentPermissionHelper set grant information to GonkPermission. r=jesup
authorSteven Lee <slee@mozilla.com>
Thu, 05 Dec 2013 09:29:07 -0500
changeset 174681 6a829a0de92deb5a7b9263b1a48cde6ee6820c6f
parent 174680 a481c9adc411b506a747575d1ff67f30a21fb935
child 174682 e88d34a3c8d58ebc564f4e8a827faa75749dceff
push id445
push userffxbld
push dateMon, 10 Mar 2014 22:05:19 +0000
treeherdermozilla-release@dc38b741b04e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjesup
bugs926746
milestone28.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 926746 - Part 2: nsContentPermissionHelper set grant information to GonkPermission. r=jesup
content/media/webrtc/MediaEngineWebRTCAudio.cpp
dom/base/nsContentPermissionHelper.cpp
dom/media/MediaManager.cpp
dom/media/MediaManager.h
--- a/content/media/webrtc/MediaEngineWebRTCAudio.cpp
+++ b/content/media/webrtc/MediaEngineWebRTCAudio.cpp
@@ -279,23 +279,26 @@ MediaEngineWebRTCAudioSource::Init()
 
   // Check for availability.
   webrtc::VoEHardware* ptrVoEHw = webrtc::VoEHardware::GetInterface(mVoiceEngine);
   if (ptrVoEHw->SetRecordingDevice(mCapIndex)) {
     ptrVoEHw->Release();
     return;
   }
 
+#ifndef MOZ_B2G
+  // Because of the permission mechanism of B2G, we need to skip the status
+  // check here.
   bool avail = false;
   ptrVoEHw->GetRecordingDeviceStatus(avail);
   ptrVoEHw->Release();
   if (!avail) {
     return;
   }
-
+#endif // MOZ_B2G
   // Set "codec" to PCM, 32kHz on 1 channel
   webrtc::VoECodec* ptrVoECodec;
   webrtc::CodecInst codec;
   ptrVoECodec = webrtc::VoECodec::GetInterface(mVoiceEngine);
   if (!ptrVoECodec) {
     return;
   }
 
--- a/dom/base/nsContentPermissionHelper.cpp
+++ b/dom/base/nsContentPermissionHelper.cpp
@@ -1,24 +1,29 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#ifdef MOZ_WIDGET_GONK
+#include "GonkPermission.h"
+#include "mozilla/dom/ContentParent.h"
+#endif // MOZ_WIDGET_GONK
 #include "nsContentPermissionHelper.h"
 #include "nsIContentPermissionPrompt.h"
 #include "nsCOMPtr.h"
 #include "nsIDOMElement.h"
 #include "nsIPrincipal.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/TabParent.h"
 #include "mozilla/unused.h"
 #include "nsComponentManagerUtils.h"
 
 using mozilla::unused;          // <snicker>
 using namespace mozilla::dom;
+using namespace mozilla;
 
 nsContentPermissionRequestProxy::nsContentPermissionRequestProxy()
 {
   MOZ_COUNT_CTOR(nsContentPermissionRequestProxy);
 }
 
 nsContentPermissionRequestProxy::~nsContentPermissionRequestProxy()
 {
@@ -125,16 +130,24 @@ nsContentPermissionRequestProxy::Allow()
   }
 
   // Don't send out the delete message when the managing protocol (PBrowser) is
   // being destroyed and PContentPermissionRequest will soon be.
   if (mParent->IsBeingDestroyed()) {
     return NS_ERROR_FAILURE;
   }
 
+#ifdef MOZ_WIDGET_GONK
+  if (mType.Equals("audio-capture")) {
+    GonkPermissionService::GetInstance()->addGrantInfo(
+      "android.permission.RECORD_AUDIO",
+      static_cast<TabParent*>(mParent->Manager())->Manager()->Pid());
+  }
+#endif
+
   unused << ContentPermissionRequestParent::Send__delete__(mParent, true);
   mParent = nullptr;
   return NS_OK;
 }
 
 namespace mozilla {
 namespace dom {
 
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -136,59 +136,44 @@ static nsresult ValidateTrackConstraints
     nsresult rv = CompareDictionaries(aCx, track.mMandatory.Value(),
                                       aNormalized.mMandatory,
                                       aOutUnknownConstraint);
     NS_ENSURE_SUCCESS(rv, rv);
   }
   return NS_OK;
 }
 
-/**
- * Send an error back to content. The error is the form a string.
- * Do this only on the main thread. The success callback is also passed here
- * so it can be released correctly.
- */
-class ErrorCallbackRunnable : public nsRunnable
+ErrorCallbackRunnable::ErrorCallbackRunnable(
+  already_AddRefed<nsIDOMGetUserMediaSuccessCallback> aSuccess,
+  already_AddRefed<nsIDOMGetUserMediaErrorCallback> aError,
+  const nsAString& aErrorMsg, uint64_t aWindowID)
+  : mSuccess(aSuccess)
+  , mError(aError)
+  , mErrorMsg(aErrorMsg)
+  , mWindowID(aWindowID)
+  , mManager(MediaManager::GetInstance()) {
+  }
+
+NS_IMETHODIMP
+ErrorCallbackRunnable::Run()
 {
-public:
-  ErrorCallbackRunnable(
-    already_AddRefed<nsIDOMGetUserMediaSuccessCallback> aSuccess,
-    already_AddRefed<nsIDOMGetUserMediaErrorCallback> aError,
-    const nsAString& aErrorMsg, uint64_t aWindowID)
-    : mSuccess(aSuccess)
-    , mError(aError)
-    , mErrorMsg(aErrorMsg)
-    , mWindowID(aWindowID)
-    , mManager(MediaManager::GetInstance()) {}
+  // Only run if the window is still active.
+  NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
 
-  NS_IMETHOD
-  Run()
-  {
-    // Only run if the window is still active.
-    NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
+  nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> success(mSuccess);
+  nsCOMPtr<nsIDOMGetUserMediaErrorCallback> error(mError);
 
-    nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> success(mSuccess);
-    nsCOMPtr<nsIDOMGetUserMediaErrorCallback> error(mError);
-
-    if (!(mManager->IsWindowStillActive(mWindowID))) {
-      return NS_OK;
-    }
-    // This is safe since we're on main-thread, and the windowlist can only
-    // be invalidated from the main-thread (see OnNavigation)
-    error->OnError(mErrorMsg);
+  if (!(mManager->IsWindowStillActive(mWindowID))) {
     return NS_OK;
   }
-
-private:
-  already_AddRefed<nsIDOMGetUserMediaSuccessCallback> mSuccess;
-  already_AddRefed<nsIDOMGetUserMediaErrorCallback> mError;
-  const nsString mErrorMsg;
-  uint64_t mWindowID;
-  nsRefPtr<MediaManager> mManager; // get ref to this when creating the runnable
-};
+  // This is safe since we're on main-thread, and the windowlist can only
+  // be invalidated from the main-thread (see OnNavigation)
+  error->OnError(mErrorMsg);
+  return NS_OK;
+}
 
 /**
  * Invoke the "onSuccess" callback in content. The callback will take a
  * DOMBlob in the case of {picture:true}, and a MediaStream in the case of
  * {audio:true} or {video:true}. There is a constructor available for each
  * form. Do this only on the main thread.
  */
 class SuccessCallbackRunnable : public nsRunnable
@@ -588,17 +573,18 @@ public:
     // Dispatch to the media thread to ask it to start the sources,
     // because that can take a while.
     // Pass ownership of trackunion to the MediaOperationRunnable
     // to ensure it's kept alive until the MediaOperationRunnable runs (at least).
     nsIThread *mediaThread = MediaManager::GetThread();
     nsRefPtr<MediaOperationRunnable> runnable(
       new MediaOperationRunnable(MEDIA_START, mListener, trackunion,
                                  tracksAvailableCallback,
-                                 mAudioSource, mVideoSource, false, mWindowID));
+                                 mAudioSource, mVideoSource, false, mWindowID,
+                                 mError.forget()));
     mediaThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
 
 #ifdef MOZ_WEBRTC
     // Right now these configs are only of use if webrtc is available
     nsresult rv;
     nsCOMPtr<nsIPrefService> prefs = do_GetService("@mozilla.org/preferences-service;1", &rv);
     if (NS_SUCCEEDED(rv)) {
       nsCOMPtr<nsIPrefBranch> branch = do_QueryInterface(prefs);
@@ -1798,17 +1784,17 @@ GetUserMediaCallbackMediaStreamListener:
   nsRefPtr<MediaOperationRunnable> runnable;
   // We can't take a chance on blocking here, so proxy this to another
   // thread.
   // Pass a ref to us (which is threadsafe) so it can query us for the
   // source stream info.
   runnable = new MediaOperationRunnable(MEDIA_STOP,
                                         this, nullptr, nullptr,
                                         mAudioSource, mVideoSource,
-                                        mFinished, mWindowID);
+                                        mFinished, mWindowID, nullptr);
   mMediaThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
 }
 
 // Called from the MediaStreamGraph thread
 void
 GetUserMediaCallbackMediaStreamListener::NotifyFinished(MediaStreamGraph* aGraph)
 {
   mFinished = true;
--- a/dom/media/MediaManager.h
+++ b/dom/media/MediaManager.h
@@ -207,71 +207,125 @@ class GetUserMediaNotificationEvent: pub
                                   GetUserMediaStatus aStatus,
                                   bool aIsAudio, bool aIsVideo, uint64_t aWindowID)
     : mListener(aListener) , mStatus(aStatus) , mIsAudio(aIsAudio)
     , mIsVideo(aIsVideo), mWindowID(aWindowID) {}
 
     GetUserMediaNotificationEvent(GetUserMediaStatus aStatus,
                                   already_AddRefed<DOMMediaStream> aStream,
                                   DOMMediaStream::OnTracksAvailableCallback* aOnTracksAvailableCallback,
-                                  bool aIsAudio, bool aIsVideo, uint64_t aWindowID)
+                                  bool aIsAudio, bool aIsVideo, uint64_t aWindowID,
+                                  already_AddRefed<nsIDOMGetUserMediaErrorCallback> aError)
     : mStream(aStream), mOnTracksAvailableCallback(aOnTracksAvailableCallback),
-      mStatus(aStatus), mIsAudio(aIsAudio), mIsVideo(aIsVideo), mWindowID(aWindowID) {}
+      mStatus(aStatus), mIsAudio(aIsAudio), mIsVideo(aIsVideo), mWindowID(aWindowID),
+      mError(aError) {}
     virtual ~GetUserMediaNotificationEvent()
     {
 
     }
 
     NS_IMETHOD Run() MOZ_OVERRIDE;
 
   protected:
     nsRefPtr<GetUserMediaCallbackMediaStreamListener> mListener; // threadsafe
     nsRefPtr<DOMMediaStream> mStream;
     nsAutoPtr<DOMMediaStream::OnTracksAvailableCallback> mOnTracksAvailableCallback;
     GetUserMediaStatus mStatus;
     bool mIsAudio;
     bool mIsVideo;
     uint64_t mWindowID;
+    nsRefPtr<nsIDOMGetUserMediaErrorCallback> mError;
 };
 
 typedef enum {
   MEDIA_START,
   MEDIA_STOP
 } MediaOperation;
 
+class MediaManager;
+
+/**
+ * Send an error back to content. The error is the form a string.
+ * Do this only on the main thread. The success callback is also passed here
+ * so it can be released correctly.
+ */
+class ErrorCallbackRunnable : public nsRunnable
+{
+public:
+  ErrorCallbackRunnable(
+    already_AddRefed<nsIDOMGetUserMediaSuccessCallback> aSuccess,
+    already_AddRefed<nsIDOMGetUserMediaErrorCallback> aError,
+    const nsAString& aErrorMsg, uint64_t aWindowID);
+  NS_IMETHOD Run();
+private:
+  already_AddRefed<nsIDOMGetUserMediaSuccessCallback> mSuccess;
+  already_AddRefed<nsIDOMGetUserMediaErrorCallback> mError;
+  const nsString mErrorMsg;
+  uint64_t mWindowID;
+  nsRefPtr<MediaManager> mManager; // get ref to this when creating the runnable
+};
+
+class ReleaseMediaOperationResource : public nsRunnable
+{
+public:
+  ReleaseMediaOperationResource(already_AddRefed<DOMMediaStream> aStream,
+    DOMMediaStream::OnTracksAvailableCallback* aOnTracksAvailableCallback):
+    mStream(aStream),
+    mOnTracksAvailableCallback(aOnTracksAvailableCallback) {}
+  NS_IMETHOD Run() MOZ_OVERRIDE {return NS_OK;}
+private:
+  nsRefPtr<DOMMediaStream> mStream;
+  nsAutoPtr<DOMMediaStream::OnTracksAvailableCallback> mOnTracksAvailableCallback;
+};
+
 // Generic class for running long media operations like Start off the main
 // thread, and then (because nsDOMMediaStreams aren't threadsafe),
 // ProxyReleases mStream since it's cycle collected.
 class MediaOperationRunnable : public nsRunnable
 {
 public:
   // so we can send Stop without AddRef()ing from the MSG thread
   MediaOperationRunnable(MediaOperation aType,
     GetUserMediaCallbackMediaStreamListener* aListener,
     DOMMediaStream* aStream,
     DOMMediaStream::OnTracksAvailableCallback* aOnTracksAvailableCallback,
     MediaEngineSource* aAudioSource,
     MediaEngineSource* aVideoSource,
     bool aNeedsFinish,
-    uint64_t aWindowID)
+    uint64_t aWindowID,
+    already_AddRefed<nsIDOMGetUserMediaErrorCallback> aError)
     : mType(aType)
     , mStream(aStream)
     , mOnTracksAvailableCallback(aOnTracksAvailableCallback)
     , mAudioSource(aAudioSource)
     , mVideoSource(aVideoSource)
     , mListener(aListener)
     , mFinish(aNeedsFinish)
     , mWindowID(aWindowID)
-    {}
+    , mError(aError)
+  {}
 
   ~MediaOperationRunnable()
   {
     // MediaStreams can be released on any thread.
   }
 
+  nsresult returnAndCallbackError(nsresult rv, const char* errorLog)
+  {
+    MM_LOG(("%s , rv=%d", errorLog, rv));
+    NS_DispatchToMainThread(new ReleaseMediaOperationResource(mStream.forget(),
+          mOnTracksAvailableCallback.forget()));
+    nsString log;
+
+    log.AssignASCII(errorLog, strlen(errorLog));
+    NS_DispatchToMainThread(new ErrorCallbackRunnable(nullptr, mError.forget(),
+      log, mWindowID));
+    return NS_OK;
+  }
+
   NS_IMETHOD
   Run() MOZ_OVERRIDE
   {
     SourceMediaStream *source = mListener->GetSourceStream();
     // No locking between these is required as all the callbacks for the
     // same MediaStream will occur on the same thread.
     if (!source) // means the stream was never Activated()
       return NS_OK;
@@ -285,41 +339,41 @@ public:
           source->SetPullEnabled(true);
 
           DOMMediaStream::TrackTypeHints expectedTracks = 0;
           if (mAudioSource) {
             rv = mAudioSource->Start(source, kAudioTrack);
             if (NS_SUCCEEDED(rv)) {
               expectedTracks |= DOMMediaStream::HINT_CONTENTS_AUDIO;
             } else {
-              MM_LOG(("Starting audio failed, rv=%d",rv));
+              return returnAndCallbackError(rv, "Starting audio failed");
             }
           }
           if (mVideoSource) {
             rv = mVideoSource->Start(source, kVideoTrack);
             if (NS_SUCCEEDED(rv)) {
               expectedTracks |= DOMMediaStream::HINT_CONTENTS_VIDEO;
             } else {
-              MM_LOG(("Starting video failed, rv=%d",rv));
+              return returnAndCallbackError(rv, "Starting video failed");
             }
           }
 
           mOnTracksAvailableCallback->SetExpectedTracks(expectedTracks);
 
           MM_LOG(("started all sources"));
           // Forward mOnTracksAvailableCallback to GetUserMediaNotificationEvent,
           // because mOnTracksAvailableCallback needs to be added to mStream
           // on the main thread.
           nsRefPtr<GetUserMediaNotificationEvent> event =
             new GetUserMediaNotificationEvent(GetUserMediaNotificationEvent::STARTING,
                                               mStream.forget(),
                                               mOnTracksAvailableCallback.forget(),
                                               mAudioSource != nullptr,
                                               mVideoSource != nullptr,
-                                              mWindowID);
+                                              mWindowID, mError.forget());
           NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
         }
         break;
 
       case MEDIA_STOP:
         {
           NS_ASSERTION(!NS_IsMainThread(), "Never call on main thread");
           if (mAudioSource) {
@@ -356,16 +410,17 @@ private:
   MediaOperation mType;
   nsRefPtr<DOMMediaStream> mStream;
   nsAutoPtr<DOMMediaStream::OnTracksAvailableCallback> mOnTracksAvailableCallback;
   nsRefPtr<MediaEngineSource> mAudioSource; // threadsafe
   nsRefPtr<MediaEngineSource> mVideoSource; // threadsafe
   nsRefPtr<GetUserMediaCallbackMediaStreamListener> mListener; // threadsafe
   bool mFinish;
   uint64_t mWindowID;
+  nsRefPtr<nsIDOMGetUserMediaErrorCallback> mError;
 };
 
 typedef nsTArray<nsRefPtr<GetUserMediaCallbackMediaStreamListener> > StreamListeners;
 typedef nsClassHashtable<nsUint64HashKey, StreamListeners> WindowTable;
 
 class MediaDevice : public nsIMediaDevice
 {
 public: