Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
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 "CameraControlImpl.h"
6 #include "base/basictypes.h"
7 #include "mozilla/Assertions.h"
8 #include "mozilla/unused.h"
9 #include "nsIWeakReferenceUtils.h"
10 #include "CameraRecorderProfiles.h"
11 #include "CameraCommon.h"
12 #include "nsGlobalWindow.h"
13 #include "DeviceStorageFileDescriptor.h"
14 #include "CameraControlListener.h"
16 using namespace mozilla;
18 nsWeakPtr CameraControlImpl::sCameraThread;
20 CameraControlImpl::CameraControlImpl(uint32_t aCameraId)
21 : mCameraId(aCameraId)
22 , mPreviewState(CameraControlListener::kPreviewStopped)
23 , mHardwareState(CameraControlListener::kHardwareClosed)
24 {
25 DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
27 // reuse the same camera thread to conserve resources
28 nsCOMPtr<nsIThread> ct = do_QueryReferent(sCameraThread);
29 if (ct) {
30 mCameraThread = ct.forget();
31 } else {
32 nsresult rv = NS_NewNamedThread("CameraThread", getter_AddRefs(mCameraThread));
33 unused << rv; // swallow rv to suppress a compiler warning when the macro
34 // is #defined to nothing (i.e. in non-DEBUG builds).
35 MOZ_ASSERT(NS_SUCCEEDED(rv));
37 // keep a weak reference to the new thread
38 sCameraThread = do_GetWeakReference(mCameraThread);
39 }
41 // Care must be taken with the mListenerLock read-write lock to prevent
42 // deadlocks. Currently this is handled by ensuring that any attempts to
43 // acquire the lock for writing (as in Add/RemoveListener()) happen in a
44 // runnable dispatched to the Camera Thread--even if the method is being
45 // called from that thread. This ensures that if a registered listener
46 // (which is invoked with a read-lock) tries to call Add/RemoveListener(),
47 // the lock-for-writing attempt won't happen until the listener has
48 // completed.
49 //
50 // Multiple parallel listeners being invoked are not a problem because
51 // the read-write lock allows multiple simultaneous read-locks.
52 mListenerLock = PR_NewRWLock(PR_RWLOCK_RANK_NONE, "CameraControlImpl.Listeners.Lock");
53 }
55 CameraControlImpl::~CameraControlImpl()
56 {
57 if (mListenerLock) {
58 PR_DestroyRWLock(mListenerLock);
59 mListenerLock = nullptr;
60 }
61 }
63 already_AddRefed<RecorderProfileManager>
64 CameraControlImpl::GetRecorderProfileManager()
65 {
66 return GetRecorderProfileManagerImpl();
67 }
69 void
70 CameraControlImpl::Shutdown()
71 {
72 DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
73 }
75 void
76 CameraControlImpl::OnHardwareStateChange(CameraControlListener::HardwareState aNewState)
77 {
78 // This callback can run on threads other than the Main Thread and
79 // the Camera Thread. On Gonk, it may be called from the camera's
80 // local binder thread, should the mediaserver process die.
81 RwLockAutoEnterRead lock(mListenerLock);
83 if (aNewState == mHardwareState) {
84 DOM_CAMERA_LOGI("OnHardwareStateChange: state did not change from %d\n", mHardwareState);
85 return;
86 }
88 #ifdef PR_LOGGING
89 const char* state[] = { "open", "closed", "failed" };
90 MOZ_ASSERT(aNewState >= 0);
91 if (static_cast<unsigned int>(aNewState) < sizeof(state) / sizeof(state[0])) {
92 DOM_CAMERA_LOGI("New hardware state is '%s'\n", state[aNewState]);
93 } else {
94 DOM_CAMERA_LOGE("OnHardwareStateChange: got invalid HardwareState value %d\n", aNewState);
95 }
96 #endif
98 mHardwareState = aNewState;
100 for (uint32_t i = 0; i < mListeners.Length(); ++i) {
101 CameraControlListener* l = mListeners[i];
102 l->OnHardwareStateChange(mHardwareState);
103 }
104 }
106 void
107 CameraControlImpl::OnConfigurationChange()
108 {
109 MOZ_ASSERT(NS_GetCurrentThread() == mCameraThread);
110 RwLockAutoEnterRead lock(mListenerLock);
112 DOM_CAMERA_LOGI("OnConfigurationChange : %d listeners\n", mListeners.Length());
114 for (uint32_t i = 0; i < mListeners.Length(); ++i) {
115 CameraControlListener* l = mListeners[i];
116 l->OnConfigurationChange(mCurrentConfiguration);
117 }
118 }
120 void
121 CameraControlImpl::OnAutoFocusComplete(bool aAutoFocusSucceeded)
122 {
123 // This callback can run on threads other than the Main Thread and
124 // the Camera Thread. On Gonk, it is called from the camera
125 // library's auto focus thread.
126 RwLockAutoEnterRead lock(mListenerLock);
128 for (uint32_t i = 0; i < mListeners.Length(); ++i) {
129 CameraControlListener* l = mListeners[i];
130 l->OnAutoFocusComplete(aAutoFocusSucceeded);
131 }
132 }
134 void
135 CameraControlImpl::OnAutoFocusMoving(bool aIsMoving)
136 {
137 RwLockAutoEnterRead lock(mListenerLock);
139 for (uint32_t i = 0; i < mListeners.Length(); ++i) {
140 CameraControlListener* l = mListeners[i];
141 l->OnAutoFocusMoving(aIsMoving);
142 }
143 }
145 void
146 CameraControlImpl::OnFacesDetected(const nsTArray<Face>& aFaces)
147 {
148 // This callback can run on threads other than the Main Thread and
149 // the Camera Thread. On Gonk, it is called from the camera
150 // library's face detection thread.
151 RwLockAutoEnterRead lock(mListenerLock);
153 for (uint32_t i = 0; i < mListeners.Length(); ++i) {
154 CameraControlListener* l = mListeners[i];
155 l->OnFacesDetected(aFaces);
156 }
157 }
159 void
160 CameraControlImpl::OnTakePictureComplete(uint8_t* aData, uint32_t aLength, const nsAString& aMimeType)
161 {
162 // This callback can run on threads other than the Main Thread and
163 // the Camera Thread. On Gonk, it is called from the camera
164 // library's snapshot thread.
165 RwLockAutoEnterRead lock(mListenerLock);
167 for (uint32_t i = 0; i < mListeners.Length(); ++i) {
168 CameraControlListener* l = mListeners[i];
169 l->OnTakePictureComplete(aData, aLength, aMimeType);
170 }
171 }
173 void
174 CameraControlImpl::OnShutter()
175 {
176 // This callback can run on threads other than the Main Thread and
177 // the Camera Thread. On Gonk, it is called from the camera driver's
178 // preview thread.
179 RwLockAutoEnterRead lock(mListenerLock);
181 for (uint32_t i = 0; i < mListeners.Length(); ++i) {
182 CameraControlListener* l = mListeners[i];
183 l->OnShutter();
184 }
185 }
187 void
188 CameraControlImpl::OnClosed()
189 {
190 // This callback can run on threads other than the Main Thread and
191 // the Camera Thread.
192 RwLockAutoEnterRead lock(mListenerLock);
194 for (uint32_t i = 0; i < mListeners.Length(); ++i) {
195 CameraControlListener* l = mListeners[i];
196 l->OnHardwareStateChange(CameraControlListener::kHardwareClosed);
197 }
198 }
200 void
201 CameraControlImpl::OnRecorderStateChange(CameraControlListener::RecorderState aState,
202 int32_t aStatus, int32_t aTrackNumber)
203 {
204 // This callback can run on threads other than the Main Thread and
205 // the Camera Thread. On Gonk, it is called from the media encoder
206 // thread.
207 RwLockAutoEnterRead lock(mListenerLock);
209 for (uint32_t i = 0; i < mListeners.Length(); ++i) {
210 CameraControlListener* l = mListeners[i];
211 l->OnRecorderStateChange(aState, aStatus, aTrackNumber);
212 }
213 }
215 void
216 CameraControlImpl::OnPreviewStateChange(CameraControlListener::PreviewState aNewState)
217 {
218 // This callback runs on the Main Thread and the Camera Thread, and
219 // may run on the local binder thread, should the mediaserver
220 // process die.
221 RwLockAutoEnterRead lock(mListenerLock);
223 if (aNewState == mPreviewState) {
224 DOM_CAMERA_LOGI("OnPreviewStateChange: state did not change from %d\n", mPreviewState);
225 return;
226 }
228 #ifdef PR_LOGGING
229 const char* state[] = { "stopped", "paused", "started" };
230 MOZ_ASSERT(aNewState >= 0);
231 if (static_cast<unsigned int>(aNewState) < sizeof(state) / sizeof(state[0])) {
232 DOM_CAMERA_LOGI("New preview state is '%s'\n", state[aNewState]);
233 } else {
234 DOM_CAMERA_LOGE("OnPreviewStateChange: got unknown PreviewState value %d\n", aNewState);
235 }
236 #endif
238 mPreviewState = aNewState;
240 for (uint32_t i = 0; i < mListeners.Length(); ++i) {
241 CameraControlListener* l = mListeners[i];
242 l->OnPreviewStateChange(mPreviewState);
243 }
244 }
246 bool
247 CameraControlImpl::OnNewPreviewFrame(layers::Image* aImage, uint32_t aWidth, uint32_t aHeight)
248 {
249 // This function runs on neither the Main Thread nor the Camera Thread.
250 // On Gonk, it is called from the camera driver's preview thread.
251 RwLockAutoEnterRead lock(mListenerLock);
253 DOM_CAMERA_LOGI("OnNewPreviewFrame: we have %d preview frame listener(s)\n",
254 mListeners.Length());
256 bool consumed = false;
258 for (uint32_t i = 0; i < mListeners.Length(); ++i) {
259 CameraControlListener* l = mListeners[i];
260 consumed = l->OnNewPreviewFrame(aImage, aWidth, aHeight) || consumed;
261 }
262 return consumed;
263 }
265 void
266 CameraControlImpl::OnError(CameraControlListener::CameraErrorContext aContext,
267 CameraControlListener::CameraError aError)
268 {
269 // This callback can run on threads other than the Main Thread and
270 // the Camera Thread.
271 RwLockAutoEnterRead lock(mListenerLock);
273 #ifdef PR_LOGGING
274 const char* error[] = {
275 "api-failed",
276 "init-failed",
277 "invalid-configuration",
278 "service-failed",
279 "set-picture-size-failed",
280 "set-thumbnail-size-failed",
281 "unknown"
282 };
283 const char* context[] = {
284 "StartCamera",
285 "StopCamera",
286 "AutoFocus",
287 "StartFaceDetection",
288 "StopFaceDetection",
289 "TakePicture",
290 "StartRecording",
291 "StopRecording",
292 "SetConfiguration",
293 "StartPreview",
294 "StopPreview",
295 "ResumeContinuousFocus",
296 "Unspecified"
297 };
298 if (static_cast<unsigned int>(aError) < sizeof(error) / sizeof(error[0]) &&
299 static_cast<unsigned int>(aContext) < sizeof(context) / sizeof(context[0])) {
300 DOM_CAMERA_LOGW("CameraControlImpl::OnError : aContext='%s' (%u), aError='%s' (%u)\n",
301 context[aContext], aContext, error[aError], aError);
302 } else {
303 DOM_CAMERA_LOGE("CameraControlImpl::OnError : aContext=%u, aError=%d\n",
304 aContext, aError);
305 }
306 #endif
308 for (uint32_t i = 0; i < mListeners.Length(); ++i) {
309 CameraControlListener* l = mListeners[i];
310 l->OnError(aContext, aError);
311 }
312 }
314 // Camera control asynchronous message; these are dispatched from
315 // the Main Thread to the Camera Thread, where they are consumed.
317 class CameraControlImpl::ControlMessage : public nsRunnable
318 {
319 public:
320 ControlMessage(CameraControlImpl* aCameraControl,
321 CameraControlListener::CameraErrorContext aContext)
322 : mCameraControl(aCameraControl)
323 , mContext(aContext)
324 {
325 MOZ_COUNT_CTOR(CameraControlImpl::ControlMessage);
326 }
328 virtual ~ControlMessage()
329 {
330 MOZ_COUNT_DTOR(CameraControlImpl::ControlMessage);
331 }
333 virtual nsresult RunImpl() = 0;
335 NS_IMETHOD
336 Run() MOZ_OVERRIDE
337 {
338 MOZ_ASSERT(mCameraControl);
339 MOZ_ASSERT(NS_GetCurrentThread() == mCameraControl->mCameraThread);
341 nsresult rv = RunImpl();
342 if (NS_FAILED(rv)) {
343 DOM_CAMERA_LOGW("Camera control API failed at %d with 0x%x\n", mContext, rv);
344 // XXXmikeh - do we want to report a more specific error code?
345 mCameraControl->OnError(mContext, CameraControlListener::kErrorApiFailed);
346 }
348 return NS_OK;
349 }
351 protected:
352 nsRefPtr<CameraControlImpl> mCameraControl;
353 CameraControlListener::CameraErrorContext mContext;
354 };
356 nsresult
357 CameraControlImpl::Start(const Configuration* aConfig)
358 {
359 class Message : public ControlMessage
360 {
361 public:
362 Message(CameraControlImpl* aCameraControl,
363 CameraControlListener::CameraErrorContext aContext,
364 const Configuration* aConfig)
365 : ControlMessage(aCameraControl, aContext)
366 , mHaveInitialConfig(false)
367 {
368 if (aConfig) {
369 mConfig = *aConfig;
370 mHaveInitialConfig = true;
371 }
372 }
374 nsresult
375 RunImpl() MOZ_OVERRIDE
376 {
377 if (mHaveInitialConfig) {
378 return mCameraControl->StartImpl(&mConfig);
379 }
380 return mCameraControl->StartImpl();
381 }
383 protected:
384 bool mHaveInitialConfig;
385 Configuration mConfig;
386 };
388 return mCameraThread->Dispatch(
389 new Message(this, CameraControlListener::kInStartCamera, aConfig), NS_DISPATCH_NORMAL);
390 }
392 nsresult
393 CameraControlImpl::SetConfiguration(const Configuration& aConfig)
394 {
395 class Message : public ControlMessage
396 {
397 public:
398 Message(CameraControlImpl* aCameraControl,
399 CameraControlListener::CameraErrorContext aContext,
400 const Configuration& aConfig)
401 : ControlMessage(aCameraControl, aContext)
402 , mConfig(aConfig)
403 { }
405 nsresult
406 RunImpl() MOZ_OVERRIDE
407 {
408 return mCameraControl->SetConfigurationImpl(mConfig);
409 }
411 protected:
412 Configuration mConfig;
413 };
415 return mCameraThread->Dispatch(
416 new Message(this, CameraControlListener::kInSetConfiguration, aConfig), NS_DISPATCH_NORMAL);
417 }
419 nsresult
420 CameraControlImpl::AutoFocus()
421 {
422 class Message : public ControlMessage
423 {
424 public:
425 Message(CameraControlImpl* aCameraControl,
426 CameraControlListener::CameraErrorContext aContext)
427 : ControlMessage(aCameraControl, aContext)
428 { }
430 nsresult
431 RunImpl() MOZ_OVERRIDE
432 {
433 return mCameraControl->AutoFocusImpl();
434 }
435 };
437 return mCameraThread->Dispatch(
438 new Message(this, CameraControlListener::kInAutoFocus), NS_DISPATCH_NORMAL);
439 }
441 nsresult
442 CameraControlImpl::StartFaceDetection()
443 {
444 class Message : public ControlMessage
445 {
446 public:
447 Message(CameraControlImpl* aCameraControl,
448 CameraControlListener::CameraErrorContext aContext)
449 : ControlMessage(aCameraControl, aContext)
450 { }
452 nsresult
453 RunImpl() MOZ_OVERRIDE
454 {
455 return mCameraControl->StartFaceDetectionImpl();
456 }
457 };
459 return mCameraThread->Dispatch(
460 new Message(this, CameraControlListener::kInStartFaceDetection), NS_DISPATCH_NORMAL);
461 }
463 nsresult
464 CameraControlImpl::StopFaceDetection()
465 {
466 class Message : public ControlMessage
467 {
468 public:
469 Message(CameraControlImpl* aCameraControl,
470 CameraControlListener::CameraErrorContext aContext)
471 : ControlMessage(aCameraControl, aContext)
472 { }
474 nsresult
475 RunImpl() MOZ_OVERRIDE
476 {
477 return mCameraControl->StopFaceDetectionImpl();
478 }
479 };
481 return mCameraThread->Dispatch(
482 new Message(this, CameraControlListener::kInStopFaceDetection), NS_DISPATCH_NORMAL);
483 }
485 nsresult
486 CameraControlImpl::TakePicture()
487 {
488 class Message : public ControlMessage
489 {
490 public:
491 Message(CameraControlImpl* aCameraControl,
492 CameraControlListener::CameraErrorContext aContext)
493 : ControlMessage(aCameraControl, aContext)
494 { }
496 nsresult
497 RunImpl() MOZ_OVERRIDE
498 {
499 return mCameraControl->TakePictureImpl();
500 }
501 };
503 return mCameraThread->Dispatch(
504 new Message(this, CameraControlListener::kInTakePicture), NS_DISPATCH_NORMAL);
505 }
507 nsresult
508 CameraControlImpl::StartRecording(DeviceStorageFileDescriptor* aFileDescriptor,
509 const StartRecordingOptions* aOptions)
510 {
511 class Message : public ControlMessage
512 {
513 public:
514 Message(CameraControlImpl* aCameraControl,
515 CameraControlListener::CameraErrorContext aContext,
516 const StartRecordingOptions* aOptions,
517 DeviceStorageFileDescriptor* aFileDescriptor)
518 : ControlMessage(aCameraControl, aContext)
519 , mOptionsPassed(false)
520 , mFileDescriptor(aFileDescriptor)
521 {
522 if (aOptions) {
523 mOptions = *aOptions;
524 mOptionsPassed = true;
525 }
526 }
528 nsresult
529 RunImpl() MOZ_OVERRIDE
530 {
531 return mCameraControl->StartRecordingImpl(mFileDescriptor,
532 mOptionsPassed ? &mOptions : nullptr);
533 }
535 protected:
536 StartRecordingOptions mOptions;
537 bool mOptionsPassed;
538 nsRefPtr<DeviceStorageFileDescriptor> mFileDescriptor;
539 };
542 return mCameraThread->Dispatch(new Message(this, CameraControlListener::kInStartRecording,
543 aOptions, aFileDescriptor), NS_DISPATCH_NORMAL);
544 }
546 nsresult
547 CameraControlImpl::StopRecording()
548 {
549 class Message : public ControlMessage
550 {
551 public:
552 Message(CameraControlImpl* aCameraControl,
553 CameraControlListener::CameraErrorContext aContext)
554 : ControlMessage(aCameraControl, aContext)
555 { }
557 nsresult
558 RunImpl() MOZ_OVERRIDE
559 {
560 return mCameraControl->StopRecordingImpl();
561 }
562 };
564 return mCameraThread->Dispatch(
565 new Message(this, CameraControlListener::kInStopRecording), NS_DISPATCH_NORMAL);
566 }
568 nsresult
569 CameraControlImpl::StartPreview()
570 {
571 class Message : public ControlMessage
572 {
573 public:
574 Message(CameraControlImpl* aCameraControl,
575 CameraControlListener::CameraErrorContext aContext)
576 : ControlMessage(aCameraControl, aContext)
577 { }
579 nsresult
580 RunImpl() MOZ_OVERRIDE
581 {
582 return mCameraControl->StartPreviewImpl();
583 }
584 };
586 return mCameraThread->Dispatch(
587 new Message(this, CameraControlListener::kInStartPreview), NS_DISPATCH_NORMAL);
588 }
590 nsresult
591 CameraControlImpl::StopPreview()
592 {
593 class Message : public ControlMessage
594 {
595 public:
596 Message(CameraControlImpl* aCameraControl,
597 CameraControlListener::CameraErrorContext aContext)
598 : ControlMessage(aCameraControl, aContext)
599 { }
601 nsresult
602 RunImpl() MOZ_OVERRIDE
603 {
604 return mCameraControl->StopPreviewImpl();
605 }
606 };
608 return mCameraThread->Dispatch(
609 new Message(this, CameraControlListener::kInStopPreview), NS_DISPATCH_NORMAL);
610 }
612 nsresult
613 CameraControlImpl::ResumeContinuousFocus()
614 {
615 class Message : public ControlMessage
616 {
617 public:
618 Message(CameraControlImpl* aCameraControl,
619 CameraControlListener::CameraErrorContext aContext)
620 : ControlMessage(aCameraControl, aContext)
621 { }
623 nsresult
624 RunImpl() MOZ_OVERRIDE
625 {
626 return mCameraControl->ResumeContinuousFocusImpl();
627 }
628 };
630 return mCameraThread->Dispatch(
631 new Message(this, CameraControlListener::kInResumeContinuousFocus), NS_DISPATCH_NORMAL);
632 }
634 nsresult
635 CameraControlImpl::Stop()
636 {
637 class Message : public ControlMessage
638 {
639 public:
640 Message(CameraControlImpl* aCameraControl,
641 CameraControlListener::CameraErrorContext aContext)
642 : ControlMessage(aCameraControl, aContext)
643 { }
645 nsresult
646 RunImpl() MOZ_OVERRIDE
647 {
648 return mCameraControl->StopImpl();
649 }
650 };
652 return mCameraThread->Dispatch(
653 new Message(this, CameraControlListener::kInStopCamera), NS_DISPATCH_NORMAL);
654 }
656 class CameraControlImpl::ListenerMessage : public CameraControlImpl::ControlMessage
657 {
658 public:
659 ListenerMessage(CameraControlImpl* aCameraControl,
660 CameraControlListener* aListener)
661 : ControlMessage(aCameraControl, CameraControlListener::kInUnspecified)
662 , mListener(aListener)
663 { }
665 protected:
666 nsRefPtr<CameraControlListener> mListener;
667 };
669 void
670 CameraControlImpl::AddListenerImpl(already_AddRefed<CameraControlListener> aListener)
671 {
672 RwLockAutoEnterWrite lock(mListenerLock);
674 CameraControlListener* l = *mListeners.AppendElement() = aListener;
675 DOM_CAMERA_LOGI("Added camera control listener %p\n", l);
677 // Update the newly-added listener's state
678 l->OnConfigurationChange(mCurrentConfiguration);
679 l->OnHardwareStateChange(mHardwareState);
680 l->OnPreviewStateChange(mPreviewState);
681 }
683 void
684 CameraControlImpl::AddListener(CameraControlListener* aListener)
685 {
686 class Message : public ListenerMessage
687 {
688 public:
689 Message(CameraControlImpl* aCameraControl,
690 CameraControlListener* aListener)
691 : ListenerMessage(aCameraControl, aListener)
692 { }
694 nsresult
695 RunImpl() MOZ_OVERRIDE
696 {
697 mCameraControl->AddListenerImpl(mListener.forget());
698 return NS_OK;
699 }
700 };
702 mCameraThread->Dispatch(new Message(this, aListener), NS_DISPATCH_NORMAL);
703 }
705 void
706 CameraControlImpl::RemoveListenerImpl(CameraControlListener* aListener)
707 {
708 RwLockAutoEnterWrite lock(mListenerLock);
710 nsRefPtr<CameraControlListener> l(aListener);
711 mListeners.RemoveElement(l);
712 DOM_CAMERA_LOGI("Removed camera control listener %p\n", l.get());
713 // XXXmikeh - do we want to notify the listener that it has been removed?
714 }
716 void
717 CameraControlImpl::RemoveListener(CameraControlListener* aListener)
718 {
719 class Message : public ListenerMessage
720 {
721 public:
722 Message(CameraControlImpl* aCameraControl, CameraControlListener* aListener)
723 : ListenerMessage(aCameraControl, aListener)
724 { }
726 nsresult
727 RunImpl() MOZ_OVERRIDE
728 {
729 mCameraControl->RemoveListenerImpl(mListener);
730 return NS_OK;
731 }
732 };
734 mCameraThread->Dispatch(new Message(this, aListener), NS_DISPATCH_NORMAL);
735 }