Bug 1063877 - Change nsVolumeService to use sync IPC for initial request. r=khuey

This commit is contained in:
Dave Hylands 2014-09-15 11:51:25 -07:00
parent ce68b1757c
commit bc5e85d921
8 changed files with 125 additions and 78 deletions

View File

@ -147,6 +147,7 @@
#ifdef MOZ_WIDGET_GONK
#include "nsIVolume.h"
#include "nsVolumeService.h"
#include "nsIVolumeService.h"
#include "SpeakerManagerService.h"
using namespace mozilla::system;
@ -2440,17 +2441,14 @@ ContentParent::RecvDataStoreGetStores(
}
bool
ContentParent::RecvBroadcastVolume(const nsString& aVolumeName)
ContentParent::RecvGetVolumes(InfallibleTArray<VolumeInfo>* aResult)
{
#ifdef MOZ_WIDGET_GONK
nsresult rv;
nsCOMPtr<nsIVolumeService> vs = do_GetService(NS_VOLUMESERVICE_CONTRACTID, &rv);
if (vs) {
vs->BroadcastVolume(aVolumeName);
}
nsRefPtr<nsVolumeService> vs = nsVolumeService::GetSingleton();
vs->GetVolumesForIPC(aResult);
return true;
#else
NS_WARNING("ContentParent::RecvBroadcastVolume shouldn't be called when MOZ_WIDGET_GONK is not defined");
NS_WARNING("ContentParent::RecvGetVolumes shouldn't be called when MOZ_WIDGET_GONK is not defined");
return false;
#endif
}

View File

@ -596,7 +596,7 @@ private:
virtual bool RecvAudioChannelChangeDefVolChannel(const int32_t& aChannel,
const bool& aHidden) MOZ_OVERRIDE;
virtual bool RecvGetSystemMemory(const uint64_t& getterId) MOZ_OVERRIDE;
virtual bool RecvBroadcastVolume(const nsString& aVolumeName) MOZ_OVERRIDE;
virtual bool RecvGetVolumes(InfallibleTArray<VolumeInfo>* aResult) MOZ_OVERRIDE;
virtual bool RecvDataStoreGetStores(
const nsString& aName,

View File

@ -292,6 +292,19 @@ struct DataStoreSetting {
bool enabled;
};
// Note: Any changes to this structure should also be changed in
// FileSystemUpdate below.
struct VolumeInfo {
nsString name;
nsString mountPoint;
int32_t volState;
int32_t mountGeneration;
bool isMediaPresent;
bool isSharing;
bool isFormatting;
bool isFake;
};
intr protocol PContent
{
parent opens PCompositor;
@ -428,6 +441,8 @@ child:
FilePathUpdate(nsString storageType, nsString storageName, nsString filepath,
nsCString reasons);
// Note: Any changes to this structure should also be changed in
// VolumeInfo above.
FileSystemUpdate(nsString fsName, nsString mountPoint, int32_t fsState,
int32_t mountGeneration, bool isMediaPresent,
bool isSharing, bool isFormatting, bool isFake);
@ -620,8 +635,8 @@ parent:
nsString aStorageName,
nsString aFilepath,
nsCString aReason);
// get nsIVolumeService to broadcast volume information
async BroadcastVolume(nsString volumeName);
sync GetVolumes() returns (VolumeInfo[] volumes);
// Notify the parent that the child has finished handling a system message.
async SystemMessageHandled();

View File

@ -8,15 +8,13 @@
interface nsIArray;
[scriptable, uuid(cab99ab4-542e-4387-bd40-db6ef30e4f5f)]
[scriptable, uuid(c31b182c-61a3-449c-bba8-fd45044499c2)]
interface nsIVolumeService : nsISupports
{
nsIVolume getVolumeByName(in DOMString volName);
nsIVolume getVolumeByPath(in DOMString path);
nsIVolume createOrGetVolumeByPath(in DOMString path);
void BroadcastVolume(in DOMString volName);
nsIVolumeMountLock createMountLock(in DOMString volName);
nsIArray getVolumeNames();

View File

@ -65,18 +65,19 @@ nsresult nsVolumeMountLock::Init()
nsCOMPtr<nsIObserverService> obs = GetObserverService();
obs->AddObserver(this, NS_VOLUME_STATE_CHANGED, true /*weak*/);
// Request the sdcard info, so we know the state/generation without having
// to wait for a state change.
if (XRE_GetProcessType() == GeckoProcessType_Content) {
ContentChild::GetSingleton()->SendBroadcastVolume(mVolumeName);
return NS_OK;
}
// Get the initial mountGeneration and grab a lock.
nsCOMPtr<nsIVolumeService> vs = do_GetService(NS_VOLUMESERVICE_CONTRACTID);
NS_ENSURE_TRUE(vs, NS_ERROR_FAILURE);
vs->BroadcastVolume(mVolumeName);
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 NS_OK;
return Lock(vol);
}
/* void unlock (); */
@ -142,12 +143,18 @@ NS_IMETHODIMP nsVolumeMountLock::Observe(nsISupports* aSubject, const char* aTop
mWakeLock = nullptr;
mVolumeGeneration = mountGeneration;
return Lock(vol);
}
nsresult
nsVolumeMountLock::Lock(nsIVolume* aVolume)
{
nsRefPtr<power::PowerManagerService> pmService =
power::PowerManagerService::GetInstance();
NS_ENSURE_TRUE(pmService, NS_ERROR_FAILURE);
nsString mountLockName;
vol->GetMountLockName(mountLockName);
aVolume->GetMountLockName(mountLockName);
ErrorResult err;
mWakeLock = pmService->NewWakeLock(mountLockName, nullptr, err);

View File

@ -14,6 +14,8 @@
#include "nsAutoPtr.h"
#include "nsWeakReference.h"
class nsIVolume;
namespace mozilla {
namespace system {
@ -41,6 +43,7 @@ private:
~nsVolumeMountLock();
nsresult Init();
nsresult Lock(nsIVolume* aVolume);
nsRefPtr<dom::WakeLock> mWakeLock;
nsString mVolumeName;

View File

@ -86,13 +86,14 @@ nsVolumeService::Shutdown()
}
nsVolumeService::nsVolumeService()
: mArrayMonitor("nsVolumeServiceArray")
: mArrayMonitor("nsVolumeServiceArray"),
mGotVolumesFromParent(false)
{
sSingleton = this;
if (XRE_GetProcessType() != GeckoProcessType_Default) {
// Request the initial state for all volumes.
ContentChild::GetSingleton()->SendBroadcastVolume(NS_LITERAL_STRING(""));
// VolumeServiceIOThread and the WakeLock listener should only run in the
// parent, so we return early.
return;
}
@ -122,59 +123,10 @@ nsVolumeService::Callback(const nsAString& aTopic, const nsAString& aState)
return NS_OK;
}
NS_IMETHODIMP
nsVolumeService::BroadcastVolume(const nsAString& aVolName)
{
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
if (aVolName.EqualsLiteral("")) {
nsVolume::Array volumeArray;
{
// Copy the array since we don't want to call BroadcastVolume
// while we're holding the lock.
MonitorAutoLock autoLock(mArrayMonitor);
volumeArray = mVolumeArray;
}
// We treat being passed the empty string as "broadcast all volumes"
nsVolume::Array::size_type numVolumes = volumeArray.Length();
nsVolume::Array::index_type volIndex;
for (volIndex = 0; volIndex < numVolumes; volIndex++) {
const nsString& volName(volumeArray[volIndex]->Name());
if (!volName.EqualsLiteral("")) {
// Note: The volume service is the only entity that should be able to
// modify the array of volumes. So we shouldn't have any issues with
// the array being modified under our feet (Since we're the volume
// service the array can't change until after we finish iterating the
// the loop).
nsresult rv = BroadcastVolume(volName);
NS_ENSURE_SUCCESS(rv, rv);
}
}
return NS_OK;
}
nsRefPtr<nsVolume> vol;
{
MonitorAutoLock autoLock(mArrayMonitor);
vol = FindVolumeByName(aVolName);
}
if (!vol) {
ERR("BroadcastVolume: Unable to locate volume '%s'",
NS_LossyConvertUTF16toASCII(aVolName).get());
return NS_ERROR_NOT_AVAILABLE;
}
nsCOMPtr<nsIObserverService> obs = GetObserverService();
NS_ENSURE_TRUE(obs, NS_NOINTERFACE);
DBG("nsVolumeService::BroadcastVolume for '%s'", vol->NameStr().get());
NS_ConvertUTF8toUTF16 stateStr(vol->StateStr());
obs->NotifyObservers(vol, NS_VOLUME_STATE_CHANGED, stateStr.get());
return NS_OK;
}
NS_IMETHODIMP nsVolumeService::GetVolumeByName(const nsAString& aVolName, nsIVolume **aResult)
{
GetVolumesFromParent();
MonitorAutoLock autoLock(mArrayMonitor);
nsRefPtr<nsVolume> vol = FindVolumeByName(aVolName);
@ -189,6 +141,8 @@ NS_IMETHODIMP nsVolumeService::GetVolumeByName(const nsAString& aVolName, nsIVol
NS_IMETHODIMP
nsVolumeService::GetVolumeByPath(const nsAString& aPath, nsIVolume **aResult)
{
GetVolumesFromParent();
NS_ConvertUTF16toUTF8 utf8Path(aPath);
char realPathBuf[PATH_MAX];
@ -239,6 +193,8 @@ nsVolumeService::GetVolumeByPath(const nsAString& aPath, nsIVolume **aResult)
NS_IMETHODIMP
nsVolumeService::CreateOrGetVolumeByPath(const nsAString& aPath, nsIVolume** aResult)
{
GetVolumesFromParent();
nsresult rv = GetVolumeByPath(aPath, aResult);
if (rv == NS_OK) {
return NS_OK;
@ -260,6 +216,8 @@ nsVolumeService::CreateOrGetVolumeByPath(const nsAString& aPath, nsIVolume** aRe
NS_IMETHODIMP
nsVolumeService::GetVolumeNames(nsIArray** aVolNames)
{
GetVolumesFromParent();
NS_ENSURE_ARG_POINTER(aVolNames);
MonitorAutoLock autoLock(mArrayMonitor);
@ -289,6 +247,60 @@ nsVolumeService::GetVolumeNames(nsIArray** aVolNames)
return NS_OK;
}
void
nsVolumeService::GetVolumesForIPC(nsTArray<VolumeInfo>* aResult)
{
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
MOZ_ASSERT(NS_IsMainThread());
MonitorAutoLock autoLock(mArrayMonitor);
nsVolume::Array::size_type numVolumes = mVolumeArray.Length();
nsVolume::Array::index_type volIndex;
for (volIndex = 0; volIndex < numVolumes; volIndex++) {
nsRefPtr<nsVolume> vol = mVolumeArray[volIndex];
VolumeInfo* volInfo = aResult->AppendElement();
volInfo->name() = vol->mName;
volInfo->mountPoint() = vol->mMountPoint;
volInfo->volState() = vol->mState;
volInfo->mountGeneration() = vol->mMountGeneration;
volInfo->isMediaPresent() = vol->mIsMediaPresent;
volInfo->isSharing() = vol->mIsSharing;
volInfo->isFormatting() = vol->mIsFormatting;
volInfo->isFake() = vol->mIsFake;
}
}
void
nsVolumeService::GetVolumesFromParent()
{
if (XRE_GetProcessType() == GeckoProcessType_Default) {
// We are the parent. Therefore our volumes are already correct.
return;
}
if (mGotVolumesFromParent) {
// We've already done this, no need to do it again.
return;
}
mGotVolumesFromParent = true;
nsTArray<VolumeInfo> result;
ContentChild::GetSingleton()->SendGetVolumes(&result);
for (uint32_t i = 0; i < result.Length(); i++) {
const VolumeInfo& volInfo(result[i]);
nsRefPtr<nsVolume> vol = new nsVolume(volInfo.name(),
volInfo.mountPoint(),
volInfo.volState(),
volInfo.mountGeneration(),
volInfo.isMediaPresent(),
volInfo.isSharing(),
volInfo.isFormatting(),
volInfo.isFake());
UpdateVolume(vol, false);
}
}
NS_IMETHODIMP
nsVolumeService::CreateMountLock(const nsAString& aVolumeName, nsIVolumeMountLock **aResult)
{
@ -366,7 +378,7 @@ nsVolumeService::CreateOrFindVolumeByName(const nsAString& aName, bool aIsFake /
}
void
nsVolumeService::UpdateVolume(nsIVolume* aVolume)
nsVolumeService::UpdateVolume(nsIVolume* aVolume, bool aNotifyObservers)
{
MOZ_ASSERT(NS_IsMainThread());
@ -386,6 +398,11 @@ nsVolumeService::UpdateVolume(nsIVolume* aVolume)
}
vol->Set(aVolume);
if (!aNotifyObservers) {
return;
}
nsCOMPtr<nsIObserverService> obs = GetObserverService();
if (!obs) {
return;

View File

@ -15,6 +15,11 @@
#include "nsVolume.h"
namespace mozilla {
namespace dom {
class VolumeInfo;
} // dom
namespace system {
class WakeLockCallback;
@ -40,9 +45,11 @@ public:
//static nsVolumeService* GetSingleton();
static void Shutdown();
void UpdateVolume(nsIVolume* aVolume);
void UpdateVolume(nsIVolume* aVolume, bool aNotifyObservers = true);
void UpdateVolumeIOThread(const Volume* aVolume);
void GetVolumesForIPC(nsTArray<dom::VolumeInfo>* aResult);
private:
~nsVolumeService();
@ -51,11 +58,13 @@ private:
already_AddRefed<nsVolume> FindVolumeByMountLockName(const nsAString& aMountLockName);
already_AddRefed<nsVolume> FindVolumeByName(const nsAString& aName);
already_AddRefed<nsVolume> CreateOrFindVolumeByName(const nsAString& aName, bool aIsFake = false);
void GetVolumesFromParent();
Monitor mArrayMonitor;
nsVolume::Array mVolumeArray;
static StaticRefPtr<nsVolumeService> sSingleton;
bool mGotVolumesFromParent;
};
} // system