gecko-dev/dom/system/gonk/nsVolume.cpp
Dave Hylands a2da39cd38 Bug 878310 - Improve DeviceStorage volume status reporting. r=qDot
This changeset causes tranistory states when changing from mounted to shared,
and back to mounted to be reported as shared instead of unavailable.

We also don't send the same status twice in a row.
2013-08-22 16:12:25 -07:00

291 lines
7.1 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"
#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_ISUPPORTS1(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())
{
}
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;
}
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::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;
}
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",
NameStr().get(), StateStr(), MountPointStr().get(),
MountGeneration(), (int)IsMountLocked(), (int)IsFake(),
(int)IsMediaPresent(), (int)IsSharing());
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);
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