summaryrefslogtreecommitdiffstats
path: root/dom/system/gonk/nsVolumeMountLock.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/system/gonk/nsVolumeMountLock.cpp')
-rw-r--r--dom/system/gonk/nsVolumeMountLock.cpp171
1 files changed, 171 insertions, 0 deletions
diff --git a/dom/system/gonk/nsVolumeMountLock.cpp b/dom/system/gonk/nsVolumeMountLock.cpp
new file mode 100644
index 000000000..288c0f689
--- /dev/null
+++ b/dom/system/gonk/nsVolumeMountLock.cpp
@@ -0,0 +1,171 @@
+/* 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 "nsVolumeMountLock.h"
+
+#include "mozilla/dom/ContentChild.h"
+#include "mozilla/Services.h"
+
+#include "nsIObserverService.h"
+#include "nsIPowerManagerService.h"
+#include "nsIVolume.h"
+#include "nsIVolumeService.h"
+#include "nsString.h"
+#include "nsXULAppAPI.h"
+
+#undef VOLUME_MANAGER_LOG_TAG
+#define VOLUME_MANAGER_LOG_TAG "nsVolumeMountLock"
+#include "VolumeManagerLog.h"
+#include "nsServiceManagerUtils.h"
+#include "mozilla/dom/power/PowerManagerService.h"
+
+using namespace mozilla::dom;
+using namespace mozilla::services;
+
+namespace mozilla {
+namespace system {
+
+NS_IMPL_ISUPPORTS(nsVolumeMountLock, nsIVolumeMountLock,
+ nsIObserver, nsISupportsWeakReference)
+
+// static
+already_AddRefed<nsVolumeMountLock>
+nsVolumeMountLock::Create(const nsAString& aVolumeName)
+{
+ DBG("nsVolumeMountLock::Create called");
+
+ RefPtr<nsVolumeMountLock> mountLock = new nsVolumeMountLock(aVolumeName);
+ nsresult rv = mountLock->Init();
+ NS_ENSURE_SUCCESS(rv, nullptr);
+
+ return mountLock.forget();
+}
+
+nsVolumeMountLock::nsVolumeMountLock(const nsAString& aVolumeName)
+ : mVolumeName(aVolumeName),
+ mVolumeGeneration(-1),
+ mUnlocked(false)
+{
+}
+
+//virtual
+nsVolumeMountLock::~nsVolumeMountLock()
+{
+ Unlock();
+}
+
+nsresult nsVolumeMountLock::Init()
+{
+ LOG("nsVolumeMountLock created for '%s'",
+ NS_LossyConvertUTF16toASCII(mVolumeName).get());
+
+ // Add ourselves as an Observer. It's important that we use a weak
+ // reference here. If we used a strong reference, then that reference
+ // would prevent this object from being destructed.
+ nsCOMPtr<nsIObserverService> obs = GetObserverService();
+ obs->AddObserver(this, NS_VOLUME_STATE_CHANGED, true /*weak*/);
+
+ // Get the initial mountGeneration and grab a lock.
+ nsCOMPtr<nsIVolumeService> vs = do_GetService(NS_VOLUMESERVICE_CONTRACTID);
+ NS_ENSURE_TRUE(vs, NS_ERROR_FAILURE);
+
+ nsCOMPtr<nsIVolume> vol;
+ nsresult rv = vs->GetVolumeByName(mVolumeName, getter_AddRefs(vol));
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+ rv = vol->GetMountGeneration(&mVolumeGeneration);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ return Lock(vol);
+}
+
+NS_IMETHODIMP nsVolumeMountLock::Unlock()
+{
+ LOG("nsVolumeMountLock released for '%s'",
+ NS_LossyConvertUTF16toASCII(mVolumeName).get());
+
+ mUnlocked = true;
+ mWakeLock = nullptr;
+
+ // While we don't really need to remove weak observers, we do so anyways
+ // since it will reduce the number of times Observe gets called.
+ nsCOMPtr<nsIObserverService> obs = GetObserverService();
+ obs->RemoveObserver(this, NS_VOLUME_STATE_CHANGED);
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsVolumeMountLock::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData)
+{
+ if (strcmp(aTopic, NS_VOLUME_STATE_CHANGED) != 0) {
+ return NS_OK;
+ }
+ if (mUnlocked) {
+ // We're not locked anymore, so we don't need to look at the notifications.
+ return NS_OK;
+ }
+
+ nsCOMPtr<nsIVolume> vol = do_QueryInterface(aSubject);
+ if (!vol) {
+ return NS_OK;
+ }
+ nsString volName;
+ vol->GetName(volName);
+ if (!volName.Equals(mVolumeName)) {
+ return NS_OK;
+ }
+ int32_t state;
+ nsresult rv = vol->GetState(&state);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (state != nsIVolume::STATE_MOUNTED) {
+ mWakeLock = nullptr;
+ mVolumeGeneration = -1;
+ return NS_OK;
+ }
+
+ int32_t mountGeneration;
+ rv = vol->GetMountGeneration(&mountGeneration);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ DBG("nsVolumeMountLock::Observe mountGeneration = %d mVolumeGeneration = %d",
+ mountGeneration, mVolumeGeneration);
+
+ if (mVolumeGeneration == mountGeneration) {
+ return NS_OK;
+ }
+
+ // The generation changed, which means that any wakelock we may have
+ // been holding is now invalid. Grab a new wakelock for the new generation
+ // number.
+
+ mWakeLock = nullptr;
+ mVolumeGeneration = mountGeneration;
+
+ return Lock(vol);
+}
+
+nsresult
+nsVolumeMountLock::Lock(nsIVolume* aVolume)
+{
+ RefPtr<power::PowerManagerService> pmService =
+ power::PowerManagerService::GetInstance();
+ NS_ENSURE_TRUE(pmService, NS_ERROR_FAILURE);
+
+ nsString mountLockName;
+ aVolume->GetMountLockName(mountLockName);
+
+ ErrorResult err;
+ mWakeLock = pmService->NewWakeLock(mountLockName, nullptr, err);
+ if (err.Failed()) {
+ return err.StealNSResult();
+ }
+
+ LOG("nsVolumeMountLock acquired for '%s' gen %d",
+ NS_LossyConvertUTF16toASCII(mVolumeName).get(), mVolumeGeneration);
+ return NS_OK;
+}
+
+} // namespace system
+} // namespace mozilla