1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "DOMCameraManager.h"
9 #include "nsPIDOMWindow.h"
10 #include "mozilla/Services.h"
11 #include "nsContentPermissionHelper.h"
12 #include "nsIContentPermissionPrompt.h"
13 #include "nsIObserverService.h"
14 #include "nsIPermissionManager.h"
15 #include "nsIScriptObjectPrincipal.h"
16 #include "DOMCameraControl.h"
17 #include "nsDOMClassInfo.h"
18 #include "CameraCommon.h"
19 #include "mozilla/dom/BindingUtils.h"
20 #include "mozilla/dom/CameraManagerBinding.h"
21 #include "mozilla/dom/PermissionMessageUtils.h"
23 using namespace mozilla
;
24 using namespace mozilla::dom
;
26 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsDOMCameraManager
, mWindow
)
28 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMCameraManager
)
29 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
30 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIObserver
)
31 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference
)
32 NS_INTERFACE_MAP_ENTRY(nsIObserver
)
35 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMCameraManager
)
36 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMCameraManager
)
39 * Global camera logging object
41 * Set the NSPR_LOG_MODULES environment variable to enable logging
42 * in a debug build, e.g. NSPR_LOG_MODULES=Camera:5
47 static PRLogModuleInfo
*sLog
;
49 sLog
= PR_NewLogModule("Camera");
54 ::WindowTable
* nsDOMCameraManager::sActiveWindows
= nullptr;
56 nsDOMCameraManager::nsDOMCameraManager(nsPIDOMWindow
* aWindow
)
57 : mWindowId(aWindow
->WindowID())
58 , mPermission(nsIPermissionManager::DENY_ACTION
)
61 /* member initializers and constructor code */
62 DOM_CAMERA_LOGT("%s:%d : this=%p, windowId=%" PRIx64
"\n", __func__
, __LINE__
, this, mWindowId
);
63 MOZ_COUNT_CTOR(nsDOMCameraManager
);
66 nsDOMCameraManager::~nsDOMCameraManager()
69 MOZ_COUNT_DTOR(nsDOMCameraManager
);
70 DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__
, __LINE__
, this);
75 nsDOMCameraManager::GetListOfCameras(nsTArray
<nsString
>& aList
, ErrorResult
& aRv
)
77 aRv
= ICameraControl::GetListOfCameras(aList
);
82 nsDOMCameraManager::HasSupport(JSContext
* aCx
, JSObject
* aGlobal
)
84 return Navigator::HasCameraSupport(aCx
, aGlobal
);
89 nsDOMCameraManager::CheckPermission(nsPIDOMWindow
* aWindow
)
91 nsCOMPtr
<nsIPermissionManager
> permMgr
=
92 services::GetPermissionManager();
93 NS_ENSURE_TRUE(permMgr
, false);
95 uint32_t permission
= nsIPermissionManager::DENY_ACTION
;
96 permMgr
->TestPermissionFromWindow(aWindow
, "camera", &permission
);
97 if (permission
!= nsIPermissionManager::ALLOW_ACTION
&&
98 permission
!= nsIPermissionManager::PROMPT_ACTION
) {
106 already_AddRefed
<nsDOMCameraManager
>
107 nsDOMCameraManager::CreateInstance(nsPIDOMWindow
* aWindow
)
109 // Initialize the shared active window tracker
110 if (!sActiveWindows
) {
111 sActiveWindows
= new ::WindowTable();
114 nsRefPtr
<nsDOMCameraManager
> cameraManager
=
115 new nsDOMCameraManager(aWindow
);
117 nsCOMPtr
<nsIObserverService
> obs
= services::GetObserverService();
119 DOM_CAMERA_LOGE("Camera manager failed to get observer service\n");
123 nsresult rv
= obs
->AddObserver(cameraManager
, "xpcom-shutdown", true);
125 DOM_CAMERA_LOGE("Camera manager failed to add 'xpcom-shutdown' observer (0x%x)\n", rv
);
129 return cameraManager
.forget();
132 class CameraPermissionRequest
: public nsIContentPermissionRequest
136 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
137 NS_DECL_NSICONTENTPERMISSIONREQUEST
139 NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(CameraPermissionRequest
,
140 nsIContentPermissionRequest
)
142 CameraPermissionRequest(nsIPrincipal
* aPrincipal
,
143 nsPIDOMWindow
* aWindow
,
144 nsRefPtr
<nsDOMCameraManager
> aManager
,
146 const CameraConfiguration
& aInitialConfig
,
147 nsRefPtr
<Promise
> aPromise
)
148 : mPrincipal(aPrincipal
)
150 , mCameraManager(aManager
)
151 , mCameraId(aCameraId
)
152 , mInitialConfig(aInitialConfig
)
157 virtual ~CameraPermissionRequest() { }
159 nsresult
DispatchCallback(uint32_t aPermission
);
162 nsCOMPtr
<nsIPrincipal
> mPrincipal
;
163 nsCOMPtr
<nsPIDOMWindow
> mWindow
;
164 nsRefPtr
<nsDOMCameraManager
> mCameraManager
;
166 CameraConfiguration mInitialConfig
;
167 nsRefPtr
<Promise
> mPromise
;
170 NS_IMPL_CYCLE_COLLECTION(CameraPermissionRequest
, mWindow
, mPromise
)
172 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CameraPermissionRequest
)
173 NS_INTERFACE_MAP_ENTRY(nsIContentPermissionRequest
)
174 NS_INTERFACE_MAP_ENTRY(nsIRunnable
)
175 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIContentPermissionRequest
)
178 NS_IMPL_CYCLE_COLLECTING_ADDREF(CameraPermissionRequest
)
179 NS_IMPL_CYCLE_COLLECTING_RELEASE(CameraPermissionRequest
)
182 CameraPermissionRequest::Run()
184 return nsContentPermissionUtils::AskPermission(this, mWindow
);
188 CameraPermissionRequest::GetPrincipal(nsIPrincipal
** aRequestingPrincipal
)
190 NS_ADDREF(*aRequestingPrincipal
= mPrincipal
);
195 CameraPermissionRequest::GetWindow(nsIDOMWindow
** aRequestingWindow
)
197 NS_ADDREF(*aRequestingWindow
= mWindow
);
202 CameraPermissionRequest::GetElement(nsIDOMElement
** aElement
)
209 CameraPermissionRequest::Cancel()
211 return DispatchCallback(nsIPermissionManager::DENY_ACTION
);
215 CameraPermissionRequest::Allow(JS::HandleValue aChoices
)
217 MOZ_ASSERT(aChoices
.isUndefined());
218 return DispatchCallback(nsIPermissionManager::ALLOW_ACTION
);
222 CameraPermissionRequest::DispatchCallback(uint32_t aPermission
)
224 nsCOMPtr
<nsIRunnable
> callbackRunnable
;
225 if (aPermission
== nsIPermissionManager::ALLOW_ACTION
) {
226 callbackRunnable
= NS_NewRunnableMethod(this, &CameraPermissionRequest::CallAllow
);
228 callbackRunnable
= NS_NewRunnableMethod(this, &CameraPermissionRequest::CallCancel
);
230 return NS_DispatchToMainThread(callbackRunnable
);
234 CameraPermissionRequest::CallAllow()
236 mCameraManager
->PermissionAllowed(mCameraId
, mInitialConfig
, mPromise
);
240 CameraPermissionRequest::CallCancel()
242 mCameraManager
->PermissionCancelled(mCameraId
, mInitialConfig
, mPromise
);
246 CameraPermissionRequest::GetTypes(nsIArray
** aTypes
)
248 nsTArray
<nsString
> emptyOptions
;
249 return nsContentPermissionUtils::CreatePermissionArray(NS_LITERAL_CSTRING("camera"),
250 NS_LITERAL_CSTRING("unused"),
255 #ifdef MOZ_WIDGET_GONK
257 nsDOMCameraManager::PreinitCameraHardware()
259 nsDOMCameraControl::PreinitCameraHardware();
263 already_AddRefed
<Promise
>
264 nsDOMCameraManager::GetCamera(const nsAString
& aCamera
,
265 const CameraConfiguration
& aInitialConfig
,
268 DOM_CAMERA_LOGT("%s:%d\n", __func__
, __LINE__
);
270 uint32_t cameraId
= 0; // back (or forward-facing) camera by default
271 if (aCamera
.EqualsLiteral("front")) {
275 nsCOMPtr
<nsIGlobalObject
> global
= do_QueryInterface(mWindow
);
277 aRv
.Throw(NS_ERROR_FAILURE
);
281 nsRefPtr
<Promise
> promise
= Promise::Create(global
, aRv
);
286 if (mPermission
== nsIPermissionManager::ALLOW_ACTION
) {
287 PermissionAllowed(cameraId
, aInitialConfig
, promise
);
288 return promise
.forget();
291 nsCOMPtr
<nsIScriptObjectPrincipal
> sop
= do_QueryInterface(mWindow
);
293 aRv
.Throw(NS_ERROR_UNEXPECTED
);
297 nsCOMPtr
<nsIPrincipal
> principal
= sop
->GetPrincipal();
298 // If we are a CERTIFIED app, we can short-circuit the permission check,
299 // which gets us a performance win.
300 uint16_t status
= nsIPrincipal::APP_STATUS_NOT_INSTALLED
;
301 principal
->GetAppStatus(&status
);
302 if (status
== nsIPrincipal::APP_STATUS_CERTIFIED
&& CheckPermission(mWindow
)) {
303 PermissionAllowed(cameraId
, aInitialConfig
, promise
);
304 return promise
.forget();
307 nsCOMPtr
<nsIRunnable
> permissionRequest
=
308 new CameraPermissionRequest(principal
, mWindow
, this, cameraId
,
309 aInitialConfig
, promise
);
311 NS_DispatchToMainThread(permissionRequest
);
312 return promise
.forget();
316 nsDOMCameraManager::PermissionAllowed(uint32_t aCameraId
,
317 const CameraConfiguration
& aInitialConfig
,
320 mPermission
= nsIPermissionManager::ALLOW_ACTION
;
322 // Creating this object will trigger the aOnSuccess callback
323 // (or the aOnError one, if it fails).
324 nsRefPtr
<nsDOMCameraControl
> cameraControl
=
325 new nsDOMCameraControl(aCameraId
, aInitialConfig
, aPromise
, mWindow
);
327 Register(cameraControl
);
331 nsDOMCameraManager::PermissionCancelled(uint32_t aCameraId
,
332 const CameraConfiguration
& aInitialConfig
,
335 mPermission
= nsIPermissionManager::DENY_ACTION
;
336 aPromise
->MaybeReject(NS_ERROR_DOM_SECURITY_ERR
);
340 nsDOMCameraManager::Register(nsDOMCameraControl
* aDOMCameraControl
)
342 DOM_CAMERA_LOGI(">>> Register( aDOMCameraControl = %p ) mWindowId = 0x%" PRIx64
"\n", aDOMCameraControl
, mWindowId
);
343 MOZ_ASSERT(NS_IsMainThread());
345 CameraControls
* controls
= sActiveWindows
->Get(mWindowId
);
347 controls
= new CameraControls();
348 sActiveWindows
->Put(mWindowId
, controls
);
351 // Remove any stale CameraControl objects to limit our memory usage
352 uint32_t i
= controls
->Length();
355 nsRefPtr
<nsDOMCameraControl
> cameraControl
=
356 do_QueryObject(controls
->ElementAt(i
));
357 if (!cameraControl
) {
358 controls
->RemoveElementAt(i
);
362 // Put the camera control into the hash table
363 nsWeakPtr cameraControl
=
364 do_GetWeakReference(static_cast<DOMMediaStream
*>(aDOMCameraControl
));
365 controls
->AppendElement(cameraControl
);
369 nsDOMCameraManager::Shutdown(uint64_t aWindowId
)
371 DOM_CAMERA_LOGI(">>> Shutdown( aWindowId = 0x%" PRIx64
" )\n", aWindowId
);
372 MOZ_ASSERT(NS_IsMainThread());
374 CameraControls
* controls
= sActiveWindows
->Get(aWindowId
);
379 uint32_t i
= controls
->Length();
382 nsRefPtr
<nsDOMCameraControl
> cameraControl
=
383 do_QueryObject(controls
->ElementAt(i
));
385 cameraControl
->Shutdown();
390 sActiveWindows
->Remove(aWindowId
);
394 nsDOMCameraManager::XpComShutdown()
396 DOM_CAMERA_LOGI(">>> XPCOM Shutdown\n");
397 MOZ_ASSERT(NS_IsMainThread());
399 nsCOMPtr
<nsIObserverService
> obs
= services::GetObserverService();
400 obs
->RemoveObserver(this, "xpcom-shutdown");
402 delete sActiveWindows
;
403 sActiveWindows
= nullptr;
407 nsDOMCameraManager::Observe(nsISupports
* aSubject
, const char* aTopic
, const char16_t
* aData
)
409 if (strcmp(aTopic
, "xpcom-shutdown") == 0) {
416 nsDOMCameraManager::OnNavigation(uint64_t aWindowId
)
418 DOM_CAMERA_LOGI(">>> OnNavigation event\n");
423 nsDOMCameraManager::IsWindowStillActive(uint64_t aWindowId
)
425 MOZ_ASSERT(NS_IsMainThread());
427 if (!sActiveWindows
) {
431 return !!sActiveWindows
->Get(aWindowId
);
435 nsDOMCameraManager::WrapObject(JSContext
* aCx
)
437 return CameraManagerBinding::Wrap(aCx
, this);