dom/camera/DOMCameraManager.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
michael@0 3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 #include "DOMCameraManager.h"
michael@0 6 #include "nsDebug.h"
michael@0 7 #include "jsapi.h"
michael@0 8 #include "Navigator.h"
michael@0 9 #include "nsPIDOMWindow.h"
michael@0 10 #include "mozilla/Services.h"
michael@0 11 #include "nsContentPermissionHelper.h"
michael@0 12 #include "nsIObserverService.h"
michael@0 13 #include "nsIPermissionManager.h"
michael@0 14 #include "DOMCameraControl.h"
michael@0 15 #include "nsDOMClassInfo.h"
michael@0 16 #include "CameraCommon.h"
michael@0 17 #include "mozilla/dom/BindingUtils.h"
michael@0 18 #include "mozilla/dom/CameraManagerBinding.h"
michael@0 19 #include "mozilla/dom/PermissionMessageUtils.h"
michael@0 20 #include "mozilla/dom/TabChild.h"
michael@0 21 #include "PCOMContentPermissionRequestChild.h"
michael@0 22
michael@0 23 using namespace mozilla;
michael@0 24 using namespace mozilla::dom;
michael@0 25
michael@0 26 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(nsDOMCameraManager, mWindow)
michael@0 27
michael@0 28 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMCameraManager)
michael@0 29 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver)
michael@0 30 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
michael@0 31 NS_INTERFACE_MAP_ENTRY(nsIObserver)
michael@0 32 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
michael@0 33 NS_INTERFACE_MAP_END
michael@0 34
michael@0 35 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMCameraManager)
michael@0 36 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMCameraManager)
michael@0 37
michael@0 38 /**
michael@0 39 * Global camera logging object
michael@0 40 *
michael@0 41 * Set the NSPR_LOG_MODULES environment variable to enable logging
michael@0 42 * in a debug build, e.g. NSPR_LOG_MODULES=Camera:5
michael@0 43 */
michael@0 44 PRLogModuleInfo*
michael@0 45 GetCameraLog()
michael@0 46 {
michael@0 47 static PRLogModuleInfo *sLog;
michael@0 48 if (!sLog) {
michael@0 49 sLog = PR_NewLogModule("Camera");
michael@0 50 }
michael@0 51 return sLog;
michael@0 52 }
michael@0 53
michael@0 54 WindowTable* nsDOMCameraManager::sActiveWindows = nullptr;
michael@0 55
michael@0 56 nsDOMCameraManager::nsDOMCameraManager(nsPIDOMWindow* aWindow)
michael@0 57 : mWindowId(aWindow->WindowID())
michael@0 58 , mPermission(nsIPermissionManager::DENY_ACTION)
michael@0 59 , mWindow(aWindow)
michael@0 60 {
michael@0 61 /* member initializers and constructor code */
michael@0 62 DOM_CAMERA_LOGT("%s:%d : this=%p, windowId=%llx\n", __func__, __LINE__, this, mWindowId);
michael@0 63 MOZ_COUNT_CTOR(nsDOMCameraManager);
michael@0 64 SetIsDOMBinding();
michael@0 65 }
michael@0 66
michael@0 67 nsDOMCameraManager::~nsDOMCameraManager()
michael@0 68 {
michael@0 69 /* destructor code */
michael@0 70 MOZ_COUNT_DTOR(nsDOMCameraManager);
michael@0 71 DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
michael@0 72 }
michael@0 73
michael@0 74 /* static */
michael@0 75 void
michael@0 76 nsDOMCameraManager::GetListOfCameras(nsTArray<nsString>& aList, ErrorResult& aRv)
michael@0 77 {
michael@0 78 aRv = ICameraControl::GetListOfCameras(aList);
michael@0 79 }
michael@0 80
michael@0 81 /* static */
michael@0 82 bool
michael@0 83 nsDOMCameraManager::HasSupport(JSContext* aCx, JSObject* aGlobal)
michael@0 84 {
michael@0 85 return Navigator::HasCameraSupport(aCx, aGlobal);
michael@0 86 }
michael@0 87
michael@0 88 /* static */
michael@0 89 bool
michael@0 90 nsDOMCameraManager::CheckPermission(nsPIDOMWindow* aWindow)
michael@0 91 {
michael@0 92 nsCOMPtr<nsIPermissionManager> permMgr =
michael@0 93 do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
michael@0 94 NS_ENSURE_TRUE(permMgr, false);
michael@0 95
michael@0 96 uint32_t permission = nsIPermissionManager::DENY_ACTION;
michael@0 97 permMgr->TestPermissionFromWindow(aWindow, "camera", &permission);
michael@0 98 if (permission != nsIPermissionManager::ALLOW_ACTION &&
michael@0 99 permission != nsIPermissionManager::PROMPT_ACTION) {
michael@0 100 return false;
michael@0 101 }
michael@0 102
michael@0 103 return true;
michael@0 104 }
michael@0 105
michael@0 106 /* static */
michael@0 107 already_AddRefed<nsDOMCameraManager>
michael@0 108 nsDOMCameraManager::CreateInstance(nsPIDOMWindow* aWindow)
michael@0 109 {
michael@0 110 // Initialize the shared active window tracker
michael@0 111 if (!sActiveWindows) {
michael@0 112 sActiveWindows = new WindowTable();
michael@0 113 }
michael@0 114
michael@0 115 nsRefPtr<nsDOMCameraManager> cameraManager =
michael@0 116 new nsDOMCameraManager(aWindow);
michael@0 117
michael@0 118 nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
michael@0 119 obs->AddObserver(cameraManager, "xpcom-shutdown", true);
michael@0 120
michael@0 121 return cameraManager.forget();
michael@0 122 }
michael@0 123
michael@0 124 class CameraPermissionRequest : public nsIContentPermissionRequest
michael@0 125 , public PCOMContentPermissionRequestChild
michael@0 126 , public nsIRunnable
michael@0 127 {
michael@0 128 public:
michael@0 129 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
michael@0 130 NS_DECL_NSICONTENTPERMISSIONREQUEST
michael@0 131 NS_DECL_NSIRUNNABLE
michael@0 132 NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(CameraPermissionRequest,
michael@0 133 nsIContentPermissionRequest)
michael@0 134
michael@0 135 CameraPermissionRequest(nsIPrincipal* aPrincipal,
michael@0 136 nsPIDOMWindow* aWindow,
michael@0 137 nsRefPtr<nsDOMCameraManager> aManager,
michael@0 138 uint32_t aCameraId,
michael@0 139 const CameraConfiguration& aInitialConfig,
michael@0 140 nsRefPtr<GetCameraCallback> aOnSuccess,
michael@0 141 nsRefPtr<CameraErrorCallback> aOnError)
michael@0 142 : mPrincipal(aPrincipal)
michael@0 143 , mWindow(aWindow)
michael@0 144 , mCameraManager(aManager)
michael@0 145 , mCameraId(aCameraId)
michael@0 146 , mInitialConfig(aInitialConfig)
michael@0 147 , mOnSuccess(aOnSuccess)
michael@0 148 , mOnError(aOnError)
michael@0 149 {
michael@0 150 }
michael@0 151
michael@0 152 virtual ~CameraPermissionRequest()
michael@0 153 {
michael@0 154 }
michael@0 155
michael@0 156 bool Recv__delete__(const bool& aAllow,
michael@0 157 const InfallibleTArray<PermissionChoice>& choices);
michael@0 158
michael@0 159 void IPDLRelease()
michael@0 160 {
michael@0 161 Release();
michael@0 162 }
michael@0 163
michael@0 164 protected:
michael@0 165 nsresult DispatchCallback(uint32_t aPermission);
michael@0 166 void CallAllow();
michael@0 167 void CallCancel();
michael@0 168 nsCOMPtr<nsIPrincipal> mPrincipal;
michael@0 169 nsCOMPtr<nsPIDOMWindow> mWindow;
michael@0 170 nsRefPtr<nsDOMCameraManager> mCameraManager;
michael@0 171 uint32_t mCameraId;
michael@0 172 CameraConfiguration mInitialConfig;
michael@0 173 nsRefPtr<GetCameraCallback> mOnSuccess;
michael@0 174 nsRefPtr<CameraErrorCallback> mOnError;
michael@0 175 };
michael@0 176
michael@0 177 NS_IMPL_CYCLE_COLLECTION(CameraPermissionRequest, mWindow, mOnSuccess, mOnError)
michael@0 178
michael@0 179 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CameraPermissionRequest)
michael@0 180 NS_INTERFACE_MAP_ENTRY(nsIContentPermissionRequest)
michael@0 181 NS_INTERFACE_MAP_ENTRY(nsIRunnable)
michael@0 182 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContentPermissionRequest)
michael@0 183 NS_INTERFACE_MAP_END
michael@0 184
michael@0 185 NS_IMPL_CYCLE_COLLECTING_ADDREF(CameraPermissionRequest)
michael@0 186 NS_IMPL_CYCLE_COLLECTING_RELEASE(CameraPermissionRequest)
michael@0 187
michael@0 188 NS_IMETHODIMP
michael@0 189 CameraPermissionRequest::Run()
michael@0 190 {
michael@0 191 if (XRE_GetProcessType() == GeckoProcessType_Content) {
michael@0 192 TabChild* child = TabChild::GetFrom(mWindow->GetDocShell());
michael@0 193 if (!child) {
michael@0 194 return NS_ERROR_NOT_AVAILABLE;
michael@0 195 }
michael@0 196
michael@0 197 // Retain a reference so the object isn't deleted without IPDL's knowledge.
michael@0 198 // Corresponding release occurs in DeallocPContentPermissionRequest.
michael@0 199 AddRef();
michael@0 200
michael@0 201 nsTArray<PermissionRequest> permArray;
michael@0 202 nsTArray<nsString> emptyOptions;
michael@0 203 permArray.AppendElement(PermissionRequest(
michael@0 204 NS_LITERAL_CSTRING("camera"),
michael@0 205 NS_LITERAL_CSTRING("unused"),
michael@0 206 emptyOptions));
michael@0 207 child->SendPContentPermissionRequestConstructor(this, permArray,
michael@0 208 IPC::Principal(mPrincipal));
michael@0 209
michael@0 210 Sendprompt();
michael@0 211 return NS_OK;
michael@0 212 }
michael@0 213
michael@0 214 nsCOMPtr<nsIContentPermissionPrompt> prompt =
michael@0 215 do_GetService(NS_CONTENT_PERMISSION_PROMPT_CONTRACTID);
michael@0 216 if (prompt) {
michael@0 217 prompt->Prompt(this);
michael@0 218 }
michael@0 219
michael@0 220 return NS_OK;
michael@0 221 }
michael@0 222
michael@0 223 bool
michael@0 224 CameraPermissionRequest::Recv__delete__(const bool& aAllow,
michael@0 225 const InfallibleTArray<PermissionChoice>& choices)
michael@0 226 {
michael@0 227 if (aAllow) {
michael@0 228 Allow(JS::UndefinedHandleValue);
michael@0 229 } else {
michael@0 230 Cancel();
michael@0 231 }
michael@0 232 return true;
michael@0 233 }
michael@0 234
michael@0 235 NS_IMETHODIMP
michael@0 236 CameraPermissionRequest::GetPrincipal(nsIPrincipal** aRequestingPrincipal)
michael@0 237 {
michael@0 238 NS_ADDREF(*aRequestingPrincipal = mPrincipal);
michael@0 239 return NS_OK;
michael@0 240 }
michael@0 241
michael@0 242 NS_IMETHODIMP
michael@0 243 CameraPermissionRequest::GetWindow(nsIDOMWindow** aRequestingWindow)
michael@0 244 {
michael@0 245 NS_ADDREF(*aRequestingWindow = mWindow);
michael@0 246 return NS_OK;
michael@0 247 }
michael@0 248
michael@0 249 NS_IMETHODIMP
michael@0 250 CameraPermissionRequest::GetElement(nsIDOMElement** aElement)
michael@0 251 {
michael@0 252 *aElement = nullptr;
michael@0 253 return NS_OK;
michael@0 254 }
michael@0 255
michael@0 256 NS_IMETHODIMP
michael@0 257 CameraPermissionRequest::Cancel()
michael@0 258 {
michael@0 259 return DispatchCallback(nsIPermissionManager::DENY_ACTION);
michael@0 260 }
michael@0 261
michael@0 262 NS_IMETHODIMP
michael@0 263 CameraPermissionRequest::Allow(JS::HandleValue aChoices)
michael@0 264 {
michael@0 265 MOZ_ASSERT(aChoices.isUndefined());
michael@0 266 return DispatchCallback(nsIPermissionManager::ALLOW_ACTION);
michael@0 267 }
michael@0 268
michael@0 269 nsresult
michael@0 270 CameraPermissionRequest::DispatchCallback(uint32_t aPermission)
michael@0 271 {
michael@0 272 nsCOMPtr<nsIRunnable> callbackRunnable;
michael@0 273 if (aPermission == nsIPermissionManager::ALLOW_ACTION) {
michael@0 274 callbackRunnable = NS_NewRunnableMethod(this, &CameraPermissionRequest::CallAllow);
michael@0 275 } else {
michael@0 276 callbackRunnable = NS_NewRunnableMethod(this, &CameraPermissionRequest::CallCancel);
michael@0 277 }
michael@0 278 return NS_DispatchToMainThread(callbackRunnable);
michael@0 279 }
michael@0 280
michael@0 281 void
michael@0 282 CameraPermissionRequest::CallAllow()
michael@0 283 {
michael@0 284 mCameraManager->PermissionAllowed(mCameraId, mInitialConfig, mOnSuccess, mOnError);
michael@0 285 }
michael@0 286
michael@0 287 void
michael@0 288 CameraPermissionRequest::CallCancel()
michael@0 289 {
michael@0 290 mCameraManager->PermissionCancelled(mCameraId, mInitialConfig, mOnSuccess, mOnError);
michael@0 291 }
michael@0 292
michael@0 293 NS_IMETHODIMP
michael@0 294 CameraPermissionRequest::GetTypes(nsIArray** aTypes)
michael@0 295 {
michael@0 296 nsTArray<nsString> emptyOptions;
michael@0 297 return CreatePermissionArray(NS_LITERAL_CSTRING("camera"),
michael@0 298 NS_LITERAL_CSTRING("unused"),
michael@0 299 emptyOptions,
michael@0 300 aTypes);
michael@0 301 }
michael@0 302
michael@0 303 void
michael@0 304 nsDOMCameraManager::GetCamera(const nsAString& aCamera,
michael@0 305 const CameraConfiguration& aInitialConfig,
michael@0 306 GetCameraCallback& aOnSuccess,
michael@0 307 const OptionalNonNullCameraErrorCallback& aOnError,
michael@0 308 ErrorResult& aRv)
michael@0 309 {
michael@0 310 DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
michael@0 311
michael@0 312 uint32_t cameraId = 0; // back (or forward-facing) camera by default
michael@0 313 if (aCamera.EqualsLiteral("front")) {
michael@0 314 cameraId = 1;
michael@0 315 }
michael@0 316
michael@0 317 nsRefPtr<CameraErrorCallback> errorCallback = nullptr;
michael@0 318 if (aOnError.WasPassed()) {
michael@0 319 errorCallback = &aOnError.Value();
michael@0 320 }
michael@0 321
michael@0 322 if (mPermission == nsIPermissionManager::ALLOW_ACTION) {
michael@0 323 PermissionAllowed(cameraId, aInitialConfig, &aOnSuccess, errorCallback);
michael@0 324 return;
michael@0 325 }
michael@0 326
michael@0 327 nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(mWindow);
michael@0 328 if (!sop) {
michael@0 329 aRv.Throw(NS_ERROR_UNEXPECTED);
michael@0 330 return;
michael@0 331 }
michael@0 332
michael@0 333 nsCOMPtr<nsIPrincipal> principal = sop->GetPrincipal();
michael@0 334
michael@0 335 nsCOMPtr<nsIRunnable> permissionRequest =
michael@0 336 new CameraPermissionRequest(principal, mWindow, this, cameraId, aInitialConfig,
michael@0 337 &aOnSuccess, errorCallback);
michael@0 338
michael@0 339 NS_DispatchToMainThread(permissionRequest);
michael@0 340 }
michael@0 341
michael@0 342 void
michael@0 343 nsDOMCameraManager::PermissionAllowed(uint32_t aCameraId,
michael@0 344 const CameraConfiguration& aInitialConfig,
michael@0 345 GetCameraCallback* aOnSuccess,
michael@0 346 CameraErrorCallback* aOnError)
michael@0 347 {
michael@0 348 mPermission = nsIPermissionManager::ALLOW_ACTION;
michael@0 349
michael@0 350 // Creating this object will trigger the aOnSuccess callback
michael@0 351 // (or the aOnError one, if it fails).
michael@0 352 nsRefPtr<nsDOMCameraControl> cameraControl =
michael@0 353 new nsDOMCameraControl(aCameraId, aInitialConfig, aOnSuccess, aOnError, mWindow);
michael@0 354
michael@0 355 Register(cameraControl);
michael@0 356 }
michael@0 357
michael@0 358 void
michael@0 359 nsDOMCameraManager::PermissionCancelled(uint32_t aCameraId,
michael@0 360 const CameraConfiguration& aInitialConfig,
michael@0 361 GetCameraCallback* aOnSuccess,
michael@0 362 CameraErrorCallback* aOnError)
michael@0 363 {
michael@0 364 mPermission = nsIPermissionManager::DENY_ACTION;
michael@0 365
michael@0 366 if (aOnError) {
michael@0 367 ErrorResult ignored;
michael@0 368 aOnError->Call(NS_LITERAL_STRING("Permission denied."), ignored);
michael@0 369 }
michael@0 370 }
michael@0 371
michael@0 372 void
michael@0 373 nsDOMCameraManager::Register(nsDOMCameraControl* aDOMCameraControl)
michael@0 374 {
michael@0 375 DOM_CAMERA_LOGI(">>> Register( aDOMCameraControl = %p ) mWindowId = 0x%llx\n", aDOMCameraControl, mWindowId);
michael@0 376 MOZ_ASSERT(NS_IsMainThread());
michael@0 377
michael@0 378 // Put the camera control into the hash table
michael@0 379 CameraControls* controls = sActiveWindows->Get(mWindowId);
michael@0 380 if (!controls) {
michael@0 381 controls = new CameraControls;
michael@0 382 sActiveWindows->Put(mWindowId, controls);
michael@0 383 }
michael@0 384 controls->AppendElement(aDOMCameraControl);
michael@0 385 }
michael@0 386
michael@0 387 void
michael@0 388 nsDOMCameraManager::Shutdown(uint64_t aWindowId)
michael@0 389 {
michael@0 390 DOM_CAMERA_LOGI(">>> Shutdown( aWindowId = 0x%llx )\n", aWindowId);
michael@0 391 MOZ_ASSERT(NS_IsMainThread());
michael@0 392
michael@0 393 CameraControls* controls = sActiveWindows->Get(aWindowId);
michael@0 394 if (!controls) {
michael@0 395 return;
michael@0 396 }
michael@0 397
michael@0 398 uint32_t length = controls->Length();
michael@0 399 for (uint32_t i = 0; i < length; i++) {
michael@0 400 nsRefPtr<nsDOMCameraControl> cameraControl = controls->ElementAt(i);
michael@0 401 cameraControl->Shutdown();
michael@0 402 }
michael@0 403 controls->Clear();
michael@0 404
michael@0 405 sActiveWindows->Remove(aWindowId);
michael@0 406 }
michael@0 407
michael@0 408 void
michael@0 409 nsDOMCameraManager::XpComShutdown()
michael@0 410 {
michael@0 411 DOM_CAMERA_LOGI(">>> XPCOM Shutdown\n");
michael@0 412 MOZ_ASSERT(NS_IsMainThread());
michael@0 413
michael@0 414 nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
michael@0 415 obs->RemoveObserver(this, "xpcom-shutdown");
michael@0 416
michael@0 417 delete sActiveWindows;
michael@0 418 sActiveWindows = nullptr;
michael@0 419 }
michael@0 420
michael@0 421 nsresult
michael@0 422 nsDOMCameraManager::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData)
michael@0 423 {
michael@0 424 if (strcmp(aTopic, "xpcom-shutdown") == 0) {
michael@0 425 XpComShutdown();
michael@0 426 }
michael@0 427 return NS_OK;
michael@0 428 }
michael@0 429
michael@0 430 void
michael@0 431 nsDOMCameraManager::OnNavigation(uint64_t aWindowId)
michael@0 432 {
michael@0 433 DOM_CAMERA_LOGI(">>> OnNavigation event\n");
michael@0 434 Shutdown(aWindowId);
michael@0 435 }
michael@0 436
michael@0 437 bool
michael@0 438 nsDOMCameraManager::IsWindowStillActive(uint64_t aWindowId)
michael@0 439 {
michael@0 440 MOZ_ASSERT(NS_IsMainThread());
michael@0 441
michael@0 442 if (!sActiveWindows) {
michael@0 443 return false;
michael@0 444 }
michael@0 445
michael@0 446 return !!sActiveWindows->Get(aWindowId);
michael@0 447 }
michael@0 448
michael@0 449 JSObject*
michael@0 450 nsDOMCameraManager::WrapObject(JSContext* aCx)
michael@0 451 {
michael@0 452 return CameraManagerBinding::Wrap(aCx, this);
michael@0 453 }

mercurial