зеркало из https://github.com/mozilla/gecko-dev.git
400 строки
9.7 KiB
C++
400 строки
9.7 KiB
C++
/* 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 "nsVolume.h"
|
|
|
|
#include "base/message_loop.h"
|
|
#include "nsIPowerManagerService.h"
|
|
#include "nsISupportsUtils.h"
|
|
#include "nsIVolume.h"
|
|
#include "nsServiceManagerUtils.h"
|
|
#include "nsThreadUtils.h"
|
|
#include "nsVolumeStat.h"
|
|
#include "nsXULAppAPI.h"
|
|
#include "Volume.h"
|
|
#include "AutoMounter.h"
|
|
#include "VolumeManager.h"
|
|
|
|
#define VOLUME_MANAGER_LOG_TAG "nsVolume"
|
|
#include "VolumeManagerLog.h"
|
|
|
|
namespace mozilla {
|
|
namespace system {
|
|
|
|
const char *
|
|
NS_VolumeStateStr(int32_t aState)
|
|
{
|
|
switch (aState) {
|
|
case nsIVolume::STATE_INIT: return "Init";
|
|
case nsIVolume::STATE_NOMEDIA: return "NoMedia";
|
|
case nsIVolume::STATE_IDLE: return "Idle";
|
|
case nsIVolume::STATE_PENDING: return "Pending";
|
|
case nsIVolume::STATE_CHECKING: return "Checking";
|
|
case nsIVolume::STATE_MOUNTED: return "Mounted";
|
|
case nsIVolume::STATE_UNMOUNTING: return "Unmounting";
|
|
case nsIVolume::STATE_FORMATTING: return "Formatting";
|
|
case nsIVolume::STATE_SHARED: return "Shared";
|
|
case nsIVolume::STATE_SHAREDMNT: return "Shared-Mounted";
|
|
}
|
|
return "???";
|
|
}
|
|
|
|
// While nsVolumes can only be used on the main thread, in the
|
|
// UpdateVolumeRunnable constructor (which is called from IOThread) we
|
|
// allocate an nsVolume which is then passed to MainThread. Since we
|
|
// have a situation where we allocate on one thread and free on another
|
|
// we use a thread safe AddRef implementation.
|
|
NS_IMPL_ISUPPORTS(nsVolume, nsIVolume)
|
|
|
|
nsVolume::nsVolume(const Volume* aVolume)
|
|
: mName(NS_ConvertUTF8toUTF16(aVolume->Name())),
|
|
mMountPoint(NS_ConvertUTF8toUTF16(aVolume->MountPoint())),
|
|
mState(aVolume->State()),
|
|
mMountGeneration(aVolume->MountGeneration()),
|
|
mMountLocked(aVolume->IsMountLocked()),
|
|
mIsFake(false),
|
|
mIsMediaPresent(aVolume->MediaPresent()),
|
|
mIsSharing(aVolume->IsSharing()),
|
|
mIsFormatting(aVolume->IsFormatting()),
|
|
mIsUnmounting(aVolume->IsUnmounting())
|
|
{
|
|
}
|
|
|
|
bool nsVolume::Equals(nsIVolume* aVolume)
|
|
{
|
|
nsString volName;
|
|
aVolume->GetName(volName);
|
|
if (!mName.Equals(volName)) {
|
|
return false;
|
|
}
|
|
|
|
nsString volMountPoint;
|
|
aVolume->GetMountPoint(volMountPoint);
|
|
if (!mMountPoint.Equals(volMountPoint)) {
|
|
return false;
|
|
}
|
|
|
|
int32_t volState;
|
|
aVolume->GetState(&volState);
|
|
if (mState != volState){
|
|
return false;
|
|
}
|
|
|
|
int32_t volMountGeneration;
|
|
aVolume->GetMountGeneration(&volMountGeneration);
|
|
if (mMountGeneration != volMountGeneration) {
|
|
return false;
|
|
}
|
|
|
|
bool volIsMountLocked;
|
|
aVolume->GetIsMountLocked(&volIsMountLocked);
|
|
if (mMountLocked != volIsMountLocked) {
|
|
return false;
|
|
}
|
|
|
|
bool isFake;
|
|
aVolume->GetIsFake(&isFake);
|
|
if (mIsFake != isFake) {
|
|
return false;
|
|
}
|
|
|
|
bool isSharing;
|
|
aVolume->GetIsSharing(&isSharing);
|
|
if (mIsSharing != isSharing) {
|
|
return false;
|
|
}
|
|
|
|
bool isFormatting;
|
|
aVolume->GetIsFormatting(&isFormatting);
|
|
if (mIsFormatting != isFormatting) {
|
|
return false;
|
|
}
|
|
|
|
bool isUnmounting;
|
|
aVolume->GetIsUnmounting(&isUnmounting);
|
|
if (mIsUnmounting != isUnmounting) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
NS_IMETHODIMP nsVolume::GetIsMediaPresent(bool* aIsMediaPresent)
|
|
{
|
|
*aIsMediaPresent = mIsMediaPresent;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsVolume::GetIsMountLocked(bool* aIsMountLocked)
|
|
{
|
|
*aIsMountLocked = mMountLocked;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsVolume::GetIsSharing(bool* aIsSharing)
|
|
{
|
|
*aIsSharing = mIsSharing;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsVolume::GetIsFormatting(bool* aIsFormatting)
|
|
{
|
|
*aIsFormatting = mIsFormatting;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsVolume::GetIsUnmounting(bool* aIsUnmounting)
|
|
{
|
|
*aIsUnmounting = mIsUnmounting;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsVolume::GetName(nsAString& aName)
|
|
{
|
|
aName = mName;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsVolume::GetMountGeneration(int32_t* aMountGeneration)
|
|
{
|
|
*aMountGeneration = mMountGeneration;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsVolume::GetMountLockName(nsAString& aMountLockName)
|
|
{
|
|
aMountLockName = NS_LITERAL_STRING("volume-") + Name();
|
|
aMountLockName.AppendPrintf("-%d", mMountGeneration);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsVolume::GetMountPoint(nsAString& aMountPoint)
|
|
{
|
|
aMountPoint = mMountPoint;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsVolume::GetState(int32_t* aState)
|
|
{
|
|
*aState = mState;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsVolume::GetStats(nsIVolumeStat **aResult)
|
|
{
|
|
if (mState != STATE_MOUNTED) {
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
}
|
|
|
|
NS_IF_ADDREF(*aResult = new nsVolumeStat(mMountPoint));
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsVolume::GetIsFake(bool *aIsFake)
|
|
{
|
|
*aIsFake = mIsFake;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsVolume::Format()
|
|
{
|
|
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
|
|
|
|
XRE_GetIOMessageLoop()->PostTask(
|
|
FROM_HERE,
|
|
NewRunnableFunction(FormatVolumeIOThread, NameStr()));
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
/* static */
|
|
void nsVolume::FormatVolumeIOThread(const nsCString& aVolume)
|
|
{
|
|
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
|
|
|
|
MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
|
|
if (VolumeManager::State() != VolumeManager::VOLUMES_READY) {
|
|
return;
|
|
}
|
|
|
|
AutoMounterFormatVolume(aVolume);
|
|
}
|
|
|
|
NS_IMETHODIMP nsVolume::Mount()
|
|
{
|
|
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
|
|
|
|
XRE_GetIOMessageLoop()->PostTask(
|
|
FROM_HERE,
|
|
NewRunnableFunction(MountVolumeIOThread, NameStr()));
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
/* static */
|
|
void nsVolume::MountVolumeIOThread(const nsCString& aVolume)
|
|
{
|
|
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
|
|
|
|
MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
|
|
if (VolumeManager::State() != VolumeManager::VOLUMES_READY) {
|
|
return;
|
|
}
|
|
|
|
AutoMounterMountVolume(aVolume);
|
|
}
|
|
|
|
NS_IMETHODIMP nsVolume::Unmount()
|
|
{
|
|
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
|
|
|
|
XRE_GetIOMessageLoop()->PostTask(
|
|
FROM_HERE,
|
|
NewRunnableFunction(UnmountVolumeIOThread, NameStr()));
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
/* static */
|
|
void nsVolume::UnmountVolumeIOThread(const nsCString& aVolume)
|
|
{
|
|
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
|
|
|
|
MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
|
|
if (VolumeManager::State() != VolumeManager::VOLUMES_READY) {
|
|
return;
|
|
}
|
|
|
|
AutoMounterUnmountVolume(aVolume);
|
|
}
|
|
|
|
void
|
|
nsVolume::LogState() const
|
|
{
|
|
if (mState == nsIVolume::STATE_MOUNTED) {
|
|
LOG("nsVolume: %s state %s @ '%s' gen %d locked %d fake %d "
|
|
"media %d sharing %d formatting %d unmounting %d",
|
|
NameStr().get(), StateStr(), MountPointStr().get(),
|
|
MountGeneration(), (int)IsMountLocked(), (int)IsFake(),
|
|
(int)IsMediaPresent(), (int)IsSharing(),
|
|
(int)IsFormatting(), (int)IsUnmounting());
|
|
return;
|
|
}
|
|
|
|
LOG("nsVolume: %s state %s", NameStr().get(), StateStr());
|
|
}
|
|
|
|
void nsVolume::Set(nsIVolume* aVolume)
|
|
{
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
aVolume->GetName(mName);
|
|
aVolume->GetMountPoint(mMountPoint);
|
|
aVolume->GetState(&mState);
|
|
aVolume->GetIsFake(&mIsFake);
|
|
aVolume->GetIsMediaPresent(&mIsMediaPresent);
|
|
aVolume->GetIsSharing(&mIsSharing);
|
|
aVolume->GetIsFormatting(&mIsFormatting);
|
|
aVolume->GetIsUnmounting(&mIsUnmounting);
|
|
|
|
int32_t volMountGeneration;
|
|
aVolume->GetMountGeneration(&volMountGeneration);
|
|
|
|
if (mState != nsIVolume::STATE_MOUNTED) {
|
|
// Since we're not in the mounted state, we need to
|
|
// forgot whatever mount generation we may have had.
|
|
mMountGeneration = -1;
|
|
return;
|
|
}
|
|
if (mMountGeneration == volMountGeneration) {
|
|
// No change in mount generation, nothing else to do
|
|
return;
|
|
}
|
|
|
|
mMountGeneration = volMountGeneration;
|
|
|
|
if (XRE_GetProcessType() != GeckoProcessType_Default) {
|
|
// Child processes just track the state, not maintain it.
|
|
aVolume->GetIsMountLocked(&mMountLocked);
|
|
return;
|
|
}
|
|
|
|
// Notify the Volume on IOThread whether the volume is locked or not.
|
|
nsCOMPtr<nsIPowerManagerService> pmService =
|
|
do_GetService(POWERMANAGERSERVICE_CONTRACTID);
|
|
if (!pmService) {
|
|
return;
|
|
}
|
|
nsString mountLockName;
|
|
GetMountLockName(mountLockName);
|
|
nsString mountLockState;
|
|
pmService->GetWakeLockState(mountLockName, mountLockState);
|
|
UpdateMountLock(mountLockState);
|
|
}
|
|
|
|
void
|
|
nsVolume::UpdateMountLock(const nsAString& aMountLockState)
|
|
{
|
|
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
// There are 3 states, unlocked, locked-background, and locked-foreground
|
|
// I figured it was easier to use negtive logic and compare for unlocked.
|
|
UpdateMountLock(!aMountLockState.EqualsLiteral("unlocked"));
|
|
}
|
|
|
|
void
|
|
nsVolume::UpdateMountLock(bool aMountLocked)
|
|
{
|
|
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
if (aMountLocked == mMountLocked) {
|
|
return;
|
|
}
|
|
// The locked/unlocked state changed. Tell IOThread about it.
|
|
mMountLocked = aMountLocked;
|
|
LogState();
|
|
XRE_GetIOMessageLoop()->PostTask(
|
|
FROM_HERE,
|
|
NewRunnableFunction(Volume::UpdateMountLock,
|
|
NS_LossyConvertUTF16toASCII(Name()),
|
|
MountGeneration(), aMountLocked));
|
|
}
|
|
|
|
void
|
|
nsVolume::SetIsFake(bool aIsFake)
|
|
{
|
|
mIsFake = aIsFake;
|
|
if (mIsFake) {
|
|
// The media is always present for fake volumes.
|
|
mIsMediaPresent = true;
|
|
MOZ_ASSERT(!mIsSharing);
|
|
}
|
|
}
|
|
|
|
void
|
|
nsVolume::SetState(int32_t aState)
|
|
{
|
|
static int32_t sMountGeneration = 0;
|
|
|
|
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
MOZ_ASSERT(IsFake());
|
|
|
|
if (aState == mState) {
|
|
return;
|
|
}
|
|
|
|
if (aState == nsIVolume::STATE_MOUNTED) {
|
|
mMountGeneration = ++sMountGeneration;
|
|
}
|
|
|
|
mState = aState;
|
|
}
|
|
|
|
} // system
|
|
} // mozilla
|