Bug 1090501 - pre-emptively open the camera hardware for certified apps with 'camera' permission, r=fabrice
authorFabrice Desre <fabrice@mozilla.com>
Fri, 31 Oct 2014 13:54:02 -0400
changeset 214202 036de9b00df6162467e598260eef951f18f37014
parent 214201 5c589d9f0a80dbe089463de33b6735fa76452816
child 214203 5a9409a50b0f425b943198515aa83ad6ed24c937
push idunknown
push userunknown
push dateunknown
reviewersfabrice
bugs1090501
milestone36.0a1
Bug 1090501 - pre-emptively open the camera hardware for certified apps with 'camera' permission, r=fabrice
dom/camera/CameraPreferences.cpp
dom/camera/CameraPreferences.h
dom/camera/DOMCameraControl.cpp
dom/camera/DOMCameraControl.h
dom/camera/DOMCameraManager.cpp
dom/camera/DOMCameraManager.h
dom/ipc/TabChild.cpp
dom/ipc/TabChild.h
--- a/dom/camera/CameraPreferences.cpp
+++ b/dom/camera/CameraPreferences.cpp
@@ -1,19 +1,24 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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/. */
 
 #include "CameraPreferences.h"
 #include "CameraCommon.h"
+#include "DOMCameraManager.h"
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Monitor.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/Preferences.h"
+#ifdef MOZ_WIDGET_GONK
+#include "mozilla/Services.h"
+#include "nsIObserverService.h"
+#endif
 
 using namespace mozilla;
 
 /* statics */
 static StaticAutoPtr<Monitor> sPrefMonitor;
 
 StaticAutoPtr<nsCString> CameraPreferences::sPrefTestEnabled;
 StaticAutoPtr<nsCString> CameraPreferences::sPrefHardwareTest;
@@ -21,16 +26,22 @@ StaticAutoPtr<nsCString> CameraPreferenc
 
 nsresult CameraPreferences::sPrefCameraControlMethodErrorOverride = NS_OK;
 nsresult CameraPreferences::sPrefCameraControlAsyncErrorOverride = NS_OK;
 
 uint32_t CameraPreferences::sPrefCameraControlLowMemoryThresholdMB = 0;
 
 bool CameraPreferences::sPrefCameraParametersIsLowMemory = false;
 
+#ifdef MOZ_WIDGET_GONK
+StaticRefPtr<CameraPreferences> CameraPreferences::sObserver;
+
+NS_IMPL_ISUPPORTS(CameraPreferences, nsIObserver);
+#endif
+
 #ifdef CAMERAPREFERENCES_HAVE_SEPARATE_UINT32_AND_NSRESULT
 /* static */
 nsresult
 CameraPreferences::UpdatePref(const char* aPref, nsresult& aVal)
 {
   uint32_t val;
   nsresult rv = Preferences::GetUint(aPref, &val);
   if (NS_SUCCEEDED(rv)) {
@@ -200,16 +211,29 @@ CameraPreferences::PreferenceChanged(con
 /* static */
 bool
 CameraPreferences::Initialize()
 {
   DOM_CAMERA_LOGI("Initializing camera preference callbacks\n");
 
   nsresult rv;
 
+#ifdef MOZ_WIDGET_GONK
+  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
+  if (obs) {
+    sObserver = new CameraPreferences();
+    rv = obs->AddObserver(sObserver, "init-camera-hw", false);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      sObserver = nullptr;
+    }
+  } else {
+    DOM_CAMERA_LOGE("Could not get observer service\n");
+  }
+#endif
+
   sPrefMonitor = new Monitor("CameraPreferences.sPrefMonitor");
 
   sPrefTestEnabled = new nsCString();
   sPrefHardwareTest = new nsCString();
   sPrefGonkParameters = new nsCString();
 
   for (uint32_t i = 0; i < ArrayLength(sPrefs); ++i) {
     rv = Preferences::RegisterCallbackAndCall(CameraPreferences::PreferenceChanged,
@@ -234,19 +258,52 @@ CameraPreferences::Shutdown()
                                     sPrefs[i].mPref);
   }
 
   sPrefTestEnabled = nullptr;
   sPrefHardwareTest = nullptr;
   sPrefGonkParameters = nullptr;
   sPrefMonitor = nullptr;
 
+#ifdef MOZ_WIDGET_GONK
+  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
+  if (obs) {
+    nsresult rv = obs->RemoveObserver(sObserver , "init-camera-hw");
+    if (NS_FAILED(rv)) {
+      DOM_CAMERA_LOGE("Failed to remove CameraPreferences observer (0x%x)\n", rv);
+    }
+    sObserver = nullptr;
+  } else {
+    DOM_CAMERA_LOGE("Could not get observer service\n");
+  }
+#endif
+
   DOM_CAMERA_LOGI("Camera preferences shut down\n");
 }
 
+#ifdef MOZ_WIDGET_GONK
+nsresult
+CameraPreferences::PreinitCameraHardware()
+{
+  nsDOMCameraManager::PreinitCameraHardware();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+CameraPreferences::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData)
+{
+  if (strcmp(aTopic, "init-camera-hw") == 0) {
+    return PreinitCameraHardware();
+  }
+
+  DOM_CAMERA_LOGE("Got unhandled topic '%s'\n", aTopic);
+  return NS_OK;
+}
+#endif
+
 /* static */
 bool
 CameraPreferences::GetPref(const char* aPref, nsACString& aVal)
 {
   MOZ_ASSERT(sPrefMonitor, "sPrefMonitor missing in CameraPreferences::GetPref()");
   MonitorAutoLock mon(*sPrefMonitor);
 
   uint32_t i = PrefToIndex(aPref);
--- a/dom/camera/CameraPreferences.h
+++ b/dom/camera/CameraPreferences.h
@@ -2,31 +2,43 @@
 /* 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/. */
 
 #ifndef DOM_CAMERA_CAMERAPREFERENCES_H
 #define DOM_CAMERA_CAMERAPREFERENCES_H
 
 #include "nsString.h"
+#include "nsIObserver.h"
+#ifdef MOZ_WIDGET_GONK
+#include "mozilla/StaticPtr.h"
+#endif
 
 #if defined(MOZ_HAVE_CXX11_STRONG_ENUMS) || defined(MOZ_HAVE_CXX11_ENUM_TYPE)
 // Older compilers that don't support strongly-typed enums
 // just typedef uint32_t to nsresult, which results in conflicting
 // overloaded members in CameraPreferences.
 #define CAMERAPREFERENCES_HAVE_SEPARATE_UINT32_AND_NSRESULT
 #endif
 
 namespace mozilla {
 
 template<class T> class StaticAutoPtr;
 
 class CameraPreferences
+#ifdef MOZ_WIDGET_GONK
+  : public nsIObserver
+#endif
 {
 public:
+#ifdef MOZ_WIDGET_GONK
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIOBSERVER
+#endif
+
   static bool Initialize();
   static void Shutdown();
 
   static bool GetPref(const char* aPref, nsACString& aVal);
 #ifdef CAMERAPREFERENCES_HAVE_SEPARATE_UINT32_AND_NSRESULT
   static bool GetPref(const char* aPref, nsresult& aVal);
 #endif
   static bool GetPref(const char* aPref, uint32_t& aVal);
@@ -74,17 +86,28 @@ protected:
 
   static nsresult sPrefCameraControlMethodErrorOverride;
   static nsresult sPrefCameraControlAsyncErrorOverride;
 
   static uint32_t sPrefCameraControlLowMemoryThresholdMB;
 
   static bool sPrefCameraParametersIsLowMemory;
 
+#ifdef MOZ_WIDGET_GONK
+  static StaticRefPtr<CameraPreferences> sObserver;
+
+  nsresult PreinitCameraHardware();
+
+protected:
+  // Objects may be instantiated for use as observers.
+  CameraPreferences() { }
+  virtual ~CameraPreferences() { }
+#else
 private:
-  // static class only
+  // Static class only.
   CameraPreferences();
   ~CameraPreferences();
+#endif
 };
 
 } // namespace mozilla
 
 #endif // DOM_CAMERA_CAMERAPREFERENCES_H
--- a/dom/camera/DOMCameraControl.cpp
+++ b/dom/camera/DOMCameraControl.cpp
@@ -41,16 +41,22 @@
 #include "DOMCameraDetectedFace.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "nsPrintfCString.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::ipc;
 
+#ifdef MOZ_WIDGET_GONK
+StaticRefPtr<ICameraControl> nsDOMCameraControl::sCachedCameraControl;
+/* static */ nsresult nsDOMCameraControl::sCachedCameraControlStartResult = NS_OK;
+/* static */ nsCOMPtr<nsITimer> nsDOMCameraControl::sDiscardCachedCameraControlTimer;
+#endif
+
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsDOMCameraControl)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END_INHERITING(DOMMediaStream)
 
 NS_IMPL_ADDREF_INHERITED(nsDOMCameraControl, DOMMediaStream)
 NS_IMPL_RELEASE_INHERITED(nsDOMCameraControl, DOMMediaStream)
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(nsDOMCameraControl, DOMMediaStream,
@@ -139,16 +145,70 @@ nsDOMCameraControl::DOMCameraConfigurati
   MOZ_COUNT_CTOR(nsDOMCameraControl::DOMCameraConfiguration);
 }
 
 nsDOMCameraControl::DOMCameraConfiguration::~DOMCameraConfiguration()
 {
   MOZ_COUNT_DTOR(nsDOMCameraControl::DOMCameraConfiguration);
 }
 
+#ifdef MOZ_WIDGET_GONK
+// This shoudl be long enough for even our slowest platforms.
+static const unsigned long kCachedCameraTimeoutMs = 3500;
+
+// Open the battery-door-facing camera by default.
+static const uint32_t kDefaultCameraId = 0;
+
+/* static */ void
+nsDOMCameraControl::PreinitCameraHardware()
+{
+  // Assume a default, minimal configuration. This should initialize the
+  // hardware, but won't (can't) start the preview.
+  nsRefPtr<ICameraControl> cameraControl = ICameraControl::Create(kDefaultCameraId);
+  if (NS_WARN_IF(!cameraControl)) {
+    return;
+  }
+
+  sCachedCameraControlStartResult = cameraControl->Start();
+  if (NS_WARN_IF(NS_FAILED(sCachedCameraControlStartResult))) {
+    return;
+  }
+
+  sCachedCameraControl = cameraControl;
+
+  nsCOMPtr<nsITimer> timer = do_CreateInstance(NS_TIMER_CONTRACTID);
+  if (NS_WARN_IF(!timer)) {
+    return;
+  }
+
+  nsresult rv = timer->InitWithFuncCallback(DiscardCachedCameraInstance,
+                                            nullptr,
+                                            kCachedCameraTimeoutMs,
+                                            nsITimer::TYPE_ONE_SHOT);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    // If we can't start the timer, it's possible for an app to never grab the
+    // camera, leaving the hardware tied up indefinitely. Better to take the
+    // performance hit.
+    sCachedCameraControl = nullptr;
+    return;
+  }
+
+  sDiscardCachedCameraControlTimer = timer;
+}
+
+/* static */ void
+nsDOMCameraControl::DiscardCachedCameraInstance(nsITimer* aTimer, void* aClosure)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  sDiscardCachedCameraControlTimer = nullptr;
+  sCachedCameraControl = nullptr;
+}
+#endif
+
 nsDOMCameraControl::nsDOMCameraControl(uint32_t aCameraId,
                                        const CameraConfiguration& aInitialConfig,
                                        GetCameraCallback* aOnSuccess,
                                        CameraErrorCallback* aOnError,
                                        Promise* aPromise,
                                        nsPIDOMWindow* aWindow)
   : DOMMediaStream()
   , mCameraControl(nullptr)
@@ -209,36 +269,56 @@ nsDOMCameraControl::nsDOMCameraControl(u
   }
 
   if (haveInitialConfig) {
     config.mPreviewSize.width = aInitialConfig.mPreviewSize.mWidth;
     config.mPreviewSize.height = aInitialConfig.mPreviewSize.mHeight;
     config.mRecorderProfile = aInitialConfig.mRecorderProfile;
   }
 
-  mCameraControl = ICameraControl::Create(aCameraId);
+#ifdef MOZ_WIDGET_GONK
+  bool gotCached = false;
+  if (sCachedCameraControl && aCameraId == kDefaultCameraId) {
+    mCameraControl = sCachedCameraControl;
+    sCachedCameraControl = nullptr;
+    gotCached = true;
+  } else {
+    sCachedCameraControl = nullptr;
+#endif
+    mCameraControl = ICameraControl::Create(aCameraId);
+#ifdef MOZ_WIDGET_GONK
+  }
+#endif
   mCurrentConfiguration = initialConfig.forget();
 
   // Attach our DOM-facing media stream to our viewfinder stream.
   mStream = mInput;
   MOZ_ASSERT(mWindow, "Shouldn't be created with a null window!");
   if (mWindow->GetExtantDoc()) {
     CombineWithPrincipal(mWindow->GetExtantDoc()->NodePrincipal());
   }
 
   // Register a listener for camera events.
   mListener = new DOMCameraControlListener(this, mInput);
   mCameraControl->AddListener(mListener);
 
-  // Start the camera...
-  if (haveInitialConfig) {
-    rv = mCameraControl->Start(&config);
+#ifdef MOZ_WIDGET_GONK
+  if (!gotCached || NS_FAILED(sCachedCameraControlStartResult)) {
+#endif
+    // Start the camera...
+    if (haveInitialConfig) {
+      rv = mCameraControl->Start(&config);
+    } else {
+      rv = mCameraControl->Start();
+    }
+#ifdef MOZ_WIDGET_GONK
   } else {
-    rv = mCameraControl->Start();
+    rv = mCameraControl->SetConfiguration(config);
   }
+#endif
   if (NS_FAILED(rv)) {
     mListener->OnUserError(DOMCameraControlListener::kInStartCamera, rv);
   }
 }
 
 nsDOMCameraControl::~nsDOMCameraControl()
 {
   DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
--- a/dom/camera/DOMCameraControl.h
+++ b/dom/camera/DOMCameraControl.h
@@ -13,16 +13,19 @@
 #include "ICameraControl.h"
 #include "CameraCommon.h"
 #include "DOMMediaStream.h"
 #include "AudioChannelAgent.h"
 #include "nsProxyRelease.h"
 #include "nsHashPropertyBag.h"
 #include "DeviceStorage.h"
 #include "DOMCameraControlListener.h"
+#ifdef MOZ_WIDGET_GONK
+#include "nsITimer.h"
+#endif
 
 class nsDOMDeviceStorage;
 class nsPIDOMWindow;
 class nsIDOMBlob;
 
 namespace mozilla {
 
 namespace dom {
@@ -135,16 +138,21 @@ public:
   void ResumePreview(ErrorResult& aRv);
   already_AddRefed<dom::Promise> ReleaseHardware(const dom::Optional<dom::OwningNonNull<dom::CameraReleaseCallback> >& aOnSuccess,
                                                  const dom::Optional<dom::OwningNonNull<dom::CameraErrorCallback> >& aOnError,
                                                  ErrorResult& aRv);
   void ResumeContinuousFocus(ErrorResult& aRv);
 
   virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
 
+#ifdef MOZ_WIDGET_GONK
+  static void PreinitCameraHardware();
+  static void DiscardCachedCameraInstance(nsITimer* aTimer, void* aClosure);
+#endif
+
   IMPL_EVENT_HANDLER(facesdetected)
   IMPL_EVENT_HANDLER(shutter)
   IMPL_EVENT_HANDLER(close)
   IMPL_EVENT_HANDLER(recorderstatechange)
   IMPL_EVENT_HANDLER(previewstatechange)
   IMPL_EVENT_HANDLER(focus)
   IMPL_EVENT_HANDLER(picture)
   IMPL_EVENT_HANDLER(configurationchange)
@@ -248,16 +256,23 @@ protected:
 
   // set once when this object is created
   nsCOMPtr<nsPIDOMWindow>   mWindow;
 
   dom::CameraStartRecordingOptions mOptions;
   nsRefPtr<DeviceStorageFileDescriptor> mDSFileDescriptor;
   DOMCameraControlListener::PreviewState mPreviewState;
 
+#ifdef MOZ_WIDGET_GONK
+  // cached camera control, to improve start-up time
+  static StaticRefPtr<ICameraControl> sCachedCameraControl;
+  static nsresult sCachedCameraControlStartResult;
+  static nsCOMPtr<nsITimer> sDiscardCachedCameraControlTimer;
+#endif
+
 private:
   nsDOMCameraControl(const nsDOMCameraControl&) MOZ_DELETE;
   nsDOMCameraControl& operator=(const nsDOMCameraControl&) MOZ_DELETE;
 };
 
 } // namespace mozilla
 
 #endif // DOM_CAMERA_DOMCAMERACONTROL_H
--- a/dom/camera/DOMCameraManager.cpp
+++ b/dom/camera/DOMCameraManager.cpp
@@ -259,16 +259,24 @@ CameraPermissionRequest::GetTypes(nsIArr
 {
   nsTArray<nsString> emptyOptions;
   return nsContentPermissionUtils::CreatePermissionArray(NS_LITERAL_CSTRING("camera"),
                                                          NS_LITERAL_CSTRING("unused"),
                                                          emptyOptions,
                                                          aTypes);
 }
 
+#ifdef MOZ_WIDGET_GONK
+/* static */ void
+nsDOMCameraManager::PreinitCameraHardware()
+{
+  nsDOMCameraControl::PreinitCameraHardware();
+}
+#endif
+
 already_AddRefed<Promise>
 nsDOMCameraManager::GetCamera(const nsAString& aCamera,
                               const CameraConfiguration& aInitialConfig,
                               const OptionalNonNullGetCameraCallback& aOnSuccess,
                               const OptionalNonNullCameraErrorCallback& aOnError,
                               ErrorResult& aRv)
 {
   DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
--- a/dom/camera/DOMCameraManager.h
+++ b/dom/camera/DOMCameraManager.h
@@ -84,16 +84,20 @@ public:
             const OptionalNonNullCameraErrorCallback& aOnError,
             mozilla::ErrorResult& aRv);
   void GetListOfCameras(nsTArray<nsString>& aList, mozilla::ErrorResult& aRv);
 
   nsPIDOMWindow* GetParentObject() const { return mWindow; }
   virtual JSObject* WrapObject(JSContext* aCx)
     MOZ_OVERRIDE;
 
+#ifdef MOZ_WIDGET_GONK
+  static void PreinitCameraHardware();
+#endif
+
 protected:
   void XpComShutdown();
   void Shutdown(uint64_t aWindowId);
   ~nsDOMCameraManager();
 
 private:
   nsDOMCameraManager() MOZ_DELETE;
   explicit nsDOMCameraManager(nsPIDOMWindow* aWindow);
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -79,16 +79,19 @@
 #include "mozilla/gfx/Matrix.h"
 #include "UnitTransforms.h"
 #include "ClientLayerManager.h"
 #include "LayersLogging.h"
 #include "nsIOService.h"
 #include "nsDOMClassInfoID.h"
 #include "nsColorPickerProxy.h"
 #include "nsPresShell.h"
+#include "nsIAppsService.h"
+#include "nsNetUtil.h"
+#include "nsIPermissionManager.h"
 
 #define BROWSER_ELEMENT_CHILD_SCRIPT \
     NS_LITERAL_STRING("chrome://global/content/BrowserElementChild.js")
 
 #define TABC_LOG(...)
 // #define TABC_LOG(...) printf_stderr("TABC: " __VA_ARGS__)
 
 using namespace mozilla;
@@ -1809,16 +1812,74 @@ TabChild::CancelCachedFileDescriptorCall
 
 void
 TabChild::DoFakeShow()
 {
   RecvShow(nsIntSize(0, 0));
   mDidFakeShow = true;
 }
 
+#ifdef MOZ_WIDGET_GONK
+void
+TabChild::MaybeRequestPreinitCamera()
+{
+    // Check if this tab will use the `camera` permission.
+    nsCOMPtr<nsIAppsService> appsService = do_GetService("@mozilla.org/AppsService;1");
+    if (NS_WARN_IF(!appsService)) {
+      return;
+    }
+
+    nsString manifestUrl = EmptyString();
+    appsService->GetManifestURLByLocalId(OwnAppId(), manifestUrl);
+    nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
+    if (NS_WARN_IF(!secMan)) {
+      return;
+    }
+
+    nsCOMPtr<nsIURI> uri;
+    nsresult rv = NS_NewURI(getter_AddRefs(uri), manifestUrl);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return;
+    }
+
+    nsCOMPtr<nsIPrincipal> principal;
+    rv = secMan->GetAppCodebasePrincipal(uri, OwnAppId(), false,
+                                         getter_AddRefs(principal));
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return;
+    }
+
+    uint16_t status = nsIPrincipal::APP_STATUS_NOT_INSTALLED;
+    principal->GetAppStatus(&status);
+    bool isCertified = status == nsIPrincipal::APP_STATUS_CERTIFIED;
+    if (!isCertified) {
+      return;
+    }
+
+    nsCOMPtr<nsIPermissionManager> permMgr = services::GetPermissionManager();
+    if (NS_WARN_IF(!permMgr)) {
+      return;
+    }
+
+    uint32_t permission = nsIPermissionManager::DENY_ACTION;
+    permMgr->TestPermissionFromPrincipal(principal, "camera", &permission);
+    bool hasPermission = permission == nsIPermissionManager::ALLOW_ACTION;
+    if (!hasPermission) {
+      return;
+    }
+
+    nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
+    if (NS_WARN_IF(!observerService)) {
+      return;
+    }
+
+    observerService->NotifyObservers(nullptr, "init-camera-hw", nullptr);
+}
+#endif
+
 bool
 TabChild::RecvShow(const nsIntSize& size)
 {
 
     if (mDidFakeShow) {
         return true;
     }
 
@@ -1833,16 +1894,20 @@ TabChild::RecvShow(const nsIntSize& size
         // remote> has already been destroyed, and we couldn't hook
         // into the parent-process's layer system.  That's not a fatal
         // error.
         return true;
     }
 
     baseWindow->SetVisibility(true);
 
+#ifdef MOZ_WIDGET_GONK
+    MaybeRequestPreinitCamera();
+#endif
+
     return InitTabChildGlobal();
 }
 
 bool
 TabChild::RecvUpdateDimensions(const nsIntRect& rect, const nsIntSize& size, const ScreenOrientation& orientation)
 {
     if (!mRemoteFrame) {
         return true;
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -493,16 +493,20 @@ protected:
                                                       bool* aSuccess) MOZ_OVERRIDE;
     virtual bool DeallocPRenderFrameChild(PRenderFrameChild* aFrame) MOZ_OVERRIDE;
     virtual bool RecvDestroy() MOZ_OVERRIDE;
     virtual bool RecvSetUpdateHitRegion(const bool& aEnabled) MOZ_OVERRIDE;
     virtual bool RecvSetIsDocShellActive(const bool& aIsActive) MOZ_OVERRIDE;
 
     virtual bool RecvRequestNotifyAfterRemotePaint();
 
+#ifdef MOZ_WIDGET_GONK
+    void MaybeRequestPreinitCamera();
+#endif
+
 private:
     /**
      * Create a new TabChild object.
      *
      * |aOwnOrContainingAppId| is the app-id of our frame or of the closest app
      * frame in the hierarchy which contains us.
      *
      * |aIsBrowserElement| indicates whether we're a browser (but not an app).