Bug 1186273 - Part 2. Improve reuse of and releasing of device storage objects where appropriate. r=dhylands

This commit is contained in:
Andrew Osmond 2015-08-18 07:42:14 -04:00
parent 12d520af6a
commit 93a03d15bc
8 changed files with 196 additions and 89 deletions

View File

@ -206,7 +206,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Navigator)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCameraManager)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMediaDevices)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessagesManager)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDeviceStorageStores)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTimeManager)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mServiceWorkerContainer)
@ -328,7 +327,10 @@ Navigator::Invalidate()
uint32_t len = mDeviceStorageStores.Length();
for (uint32_t i = 0; i < len; ++i) {
mDeviceStorageStores[i]->Shutdown();
nsRefPtr<nsDOMDeviceStorage> ds = do_QueryReferent(mDeviceStorageStores[i]);
if (ds) {
ds->Shutdown();
}
}
mDeviceStorageStores.Clear();
@ -961,7 +963,26 @@ Navigator::GetDeviceStorageAreaListener(ErrorResult& aRv)
return mDeviceStorageAreaListener;
}
nsDOMDeviceStorage*
already_AddRefed<nsDOMDeviceStorage>
Navigator::FindDeviceStorage(const nsAString& aName, const nsAString& aType)
{
auto i = mDeviceStorageStores.Length();
while (i > 0) {
--i;
nsRefPtr<nsDOMDeviceStorage> storage =
do_QueryReferent(mDeviceStorageStores[i]);
if (storage) {
if (storage->Equals(mWindow, aName, aType)) {
return storage.forget();
}
} else {
mDeviceStorageStores.RemoveElementAt(i);
}
}
return nullptr;
}
already_AddRefed<nsDOMDeviceStorage>
Navigator::GetDeviceStorage(const nsAString& aType, ErrorResult& aRv)
{
if (!mWindow || !mWindow->GetOuterWindow() || !mWindow->GetDocShell()) {
@ -969,7 +990,13 @@ Navigator::GetDeviceStorage(const nsAString& aType, ErrorResult& aRv)
return nullptr;
}
nsRefPtr<nsDOMDeviceStorage> storage;
nsString name;
nsDOMDeviceStorage::GetDefaultStorageName(aType, name);
nsRefPtr<nsDOMDeviceStorage> storage = FindDeviceStorage(name, aType);
if (storage) {
return storage.forget();
}
nsDOMDeviceStorage::CreateDeviceStorageFor(mWindow, aType,
getter_AddRefs(storage));
@ -977,8 +1004,9 @@ Navigator::GetDeviceStorage(const nsAString& aType, ErrorResult& aRv)
return nullptr;
}
mDeviceStorageStores.AppendElement(storage);
return storage;
mDeviceStorageStores.AppendElement(
do_GetWeakReference(static_cast<DOMEventTargetHelper*>(storage)));
return storage.forget();
}
void
@ -991,12 +1019,31 @@ Navigator::GetDeviceStorages(const nsAString& aType,
return;
}
nsDOMDeviceStorage::CreateDeviceStoragesFor(mWindow, aType, aStores);
nsDOMDeviceStorage::VolumeNameArray volumes;
nsDOMDeviceStorage::GetOrderedVolumeNames(aType, volumes);
if (volumes.IsEmpty()) {
nsRefPtr<nsDOMDeviceStorage> storage = GetDeviceStorage(aType, aRv);
if (storage) {
aStores.AppendElement(storage.forget());
}
} else {
uint32_t len = volumes.Length();
aStores.SetCapacity(len);
for (uint32_t i = 0; i < len; ++i) {
nsRefPtr<nsDOMDeviceStorage> storage =
GetDeviceStorageByNameAndType(volumes[i], aType, aRv);
if (aRv.Failed()) {
break;
}
mDeviceStorageStores.AppendElements(aStores);
if (storage) {
aStores.AppendElement(storage.forget());
}
}
}
}
nsDOMDeviceStorage*
already_AddRefed<nsDOMDeviceStorage>
Navigator::GetDeviceStorageByNameAndType(const nsAString& aName,
const nsAString& aType,
ErrorResult& aRv)
@ -1006,7 +1053,10 @@ Navigator::GetDeviceStorageByNameAndType(const nsAString& aName,
return nullptr;
}
nsRefPtr<nsDOMDeviceStorage> storage;
nsRefPtr<nsDOMDeviceStorage> storage = FindDeviceStorage(aName, aType);
if (storage) {
return storage.forget();
}
nsDOMDeviceStorage::CreateDeviceStorageByNameAndType(mWindow, aName, aType,
getter_AddRefs(storage));
@ -1014,8 +1064,9 @@ Navigator::GetDeviceStorageByNameAndType(const nsAString& aName,
return nullptr;
}
mDeviceStorageStores.AppendElement(storage);
return storage;
mDeviceStorageStores.AppendElement(
do_GetWeakReference(static_cast<DOMEventTargetHelper*>(storage)));
return storage.forget();
}
Geolocation*

View File

@ -18,6 +18,7 @@
#include "nsInterfaceHashtable.h"
#include "nsString.h"
#include "nsTArray.h"
#include "nsWeakPtr.h"
#ifdef MOZ_EME
#include "mozilla/dom/MediaKeySystemAccessManager.h"
#endif
@ -220,14 +221,18 @@ public:
already_AddRefed<WakeLock> RequestWakeLock(const nsAString &aTopic,
ErrorResult& aRv);
DeviceStorageAreaListener* GetDeviceStorageAreaListener(ErrorResult& aRv);
nsDOMDeviceStorage* GetDeviceStorage(const nsAString& aType,
ErrorResult& aRv);
already_AddRefed<nsDOMDeviceStorage> GetDeviceStorage(const nsAString& aType,
ErrorResult& aRv);
void GetDeviceStorages(const nsAString& aType,
nsTArray<nsRefPtr<nsDOMDeviceStorage> >& aStores,
ErrorResult& aRv);
nsDOMDeviceStorage* GetDeviceStorageByNameAndType(const nsAString& aName,
const nsAString& aType,
ErrorResult& aRv);
already_AddRefed<nsDOMDeviceStorage>
GetDeviceStorageByNameAndType(const nsAString& aName, const nsAString& aType,
ErrorResult& aRv);
DesktopNotificationCenter* GetMozNotification(ErrorResult& aRv);
CellBroadcast* GetMozCellBroadcast(ErrorResult& aRv);
IccManager* GetMozIccManager(ErrorResult& aRv);
@ -357,6 +362,9 @@ private:
bool CheckPermission(const char* type);
static bool CheckPermission(nsPIDOMWindow* aWindow, const char* aType);
already_AddRefed<nsDOMDeviceStorage> FindDeviceStorage(const nsAString& aName,
const nsAString& aType);
nsRefPtr<nsMimeTypeArray> mMimeTypes;
nsRefPtr<nsPluginArray> mPlugins;
nsRefPtr<Permissions> mPermissions;
@ -387,7 +395,7 @@ private:
nsRefPtr<nsDOMCameraManager> mCameraManager;
nsRefPtr<MediaDevices> mMediaDevices;
nsCOMPtr<nsIDOMNavigatorSystemMessages> mMessagesManager;
nsTArray<nsRefPtr<nsDOMDeviceStorage> > mDeviceStorageStores;
nsTArray<nsWeakPtr> mDeviceStorageStores;
nsRefPtr<time::TimeManager> mTimeManager;
nsRefPtr<ServiceWorkerContainer> mServiceWorkerContainer;
nsCOMPtr<nsPIDOMWindow> mWindow;

View File

@ -13,6 +13,7 @@
#include "mozilla/RefPtr.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/dom/DOMRequest.h"
#include "nsWeakReference.h"
#define DEVICESTORAGE_PICTURES "pictures"
#define DEVICESTORAGE_VIDEOS "videos"
@ -132,8 +133,13 @@ private:
uint64_t* aTotalSoFar);
};
#define NS_DOM_DEVICE_STORAGE_CID \
{ 0xe4a9b969, 0x81fe, 0x44f1, \
{ 0xaa, 0x0c, 0x9e, 0x16, 0x64, 0x86, 0x2a, 0xd5 } }
class nsDOMDeviceStorage final
: public mozilla::DOMEventTargetHelper
, public nsSupportsWeakReference
{
typedef mozilla::ErrorResult ErrorResult;
typedef mozilla::dom::DeviceStorageEnumerationParameters
@ -145,6 +151,7 @@ class nsDOMDeviceStorage final
public:
typedef nsTArray<nsString> VolumeNameArray;
NS_DECLARE_STATIC_IID_ACCESSOR(NS_DOM_DEVICE_STORAGE_CID)
NS_DECL_ISUPPORTS_INHERITED
NS_REALLY_FORWARD_NSIDOMEVENTTARGET(DOMEventTargetHelper)
@ -251,23 +258,25 @@ public:
const nsAString& aType,
nsDOMDeviceStorage** aStore);
static void
CreateDeviceStoragesFor(nsPIDOMWindow* aWin,
const nsAString& aType,
nsTArray<nsRefPtr<nsDOMDeviceStorage> >& aStores);
static void
CreateDeviceStorageByNameAndType(nsPIDOMWindow* aWin,
const nsAString& aName,
const nsAString& aType,
nsDOMDeviceStorage** aStore);
bool Equals(nsPIDOMWindow* aWin,
const nsAString& aName,
const nsAString& aType);
void Shutdown();
static void GetOrderedVolumeNames(const nsAString& aType,
nsTArray<nsString>& aVolumeNames);
static void GetOrderedVolumeNames(nsTArray<nsString>& aVolumeNames);
static void GetDefaultStorageName(const nsAString& aStorageType,
nsAString &aStorageName);
nsAString& aStorageName);
static bool ParseFullPath(const nsAString& aFullPath,
nsAString& aOutStorageName,
@ -341,4 +350,6 @@ private:
nsRefPtr<DeviceStorageFileSystem> mFileSystem;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsDOMDeviceStorage, NS_DOM_DEVICE_STORAGE_CID)
#endif

View File

@ -421,14 +421,13 @@ DeviceStorageStatics::RemoveListener(nsDOMDeviceStorage* aListener)
uint32_t i = sInstance->mListeners.Length();
while (i > 0) {
--i;
if (sInstance->mListeners[i]->mDeviceStorage.get() == aListener) {
if (sInstance->mListeners[i]->Equals(aListener)) {
sInstance->mListeners.RemoveElementAt(i);
removed = true;
break;
}
}
MOZ_ASSERT(removed);
if (removed && sInstance->mListeners.IsEmpty()) {
NS_DispatchToMainThread(
NS_NewRunnableMethod(sInstance.get(), &DeviceStorageStatics::Deregister));
@ -747,42 +746,70 @@ DeviceStorageStatics::Observe(nsISupports* aSubject,
}
DeviceStorageStatics::ListenerWrapper::ListenerWrapper(nsDOMDeviceStorage* aListener)
: mDeviceStorage(aListener)
: mListener(do_GetWeakReference(static_cast<DOMEventTargetHelper*>(aListener)))
, mOwningThread(NS_GetCurrentThread())
{
}
DeviceStorageStatics::ListenerWrapper::~ListenerWrapper()
{
// Even weak pointers are not thread safe
NS_ProxyRelease(mOwningThread, mListener);
}
bool
DeviceStorageStatics::ListenerWrapper::Equals(nsDOMDeviceStorage* aListener)
{
bool current = false;
mOwningThread->IsOnCurrentThread(&current);
if (current) {
// It is only safe to acquire the reference on the owning thread
nsRefPtr<nsDOMDeviceStorage> listener = do_QueryReferent(mListener);
return listener.get() == aListener;
}
return false;
}
void
DeviceStorageStatics::ListenerWrapper::OnFileWatcherUpdate(const nsCString& aData,
DeviceStorageFile* aFile)
DeviceStorageFile* aFile)
{
nsRefPtr<ListenerWrapper> self = this;
nsCString data = aData;
nsRefPtr<DeviceStorageFile> file = aFile;
NS_DispatchToMainThread(NS_NewRunnableFunction([self, data, file] () -> void {
self->mDeviceStorage->OnFileWatcherUpdate(data, file);
}));
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([self, data, file] () -> void {
nsRefPtr<nsDOMDeviceStorage> listener = do_QueryReferent(self->mListener);
if (listener) {
listener->OnFileWatcherUpdate(data, file);
}
});
mOwningThread->Dispatch(r, NS_DISPATCH_NORMAL);
}
void
DeviceStorageStatics::ListenerWrapper::OnDiskSpaceWatcher(bool aLowDiskSpace)
{
nsRefPtr<ListenerWrapper> self = this;
NS_DispatchToMainThread(NS_NewRunnableFunction([self, aLowDiskSpace] () -> void {
self->mDeviceStorage->OnDiskSpaceWatcher(aLowDiskSpace);
}));
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([self, aLowDiskSpace] () -> void {
nsRefPtr<nsDOMDeviceStorage> listener = do_QueryReferent(self->mListener);
if (listener) {
listener->OnDiskSpaceWatcher(aLowDiskSpace);
}
});
mOwningThread->Dispatch(r, NS_DISPATCH_NORMAL);
}
void
DeviceStorageStatics::ListenerWrapper::OnWritableNameChanged()
{
nsRefPtr<ListenerWrapper> self = this;
NS_DispatchToMainThread(NS_NewRunnableFunction([self] () -> void {
self->mDeviceStorage->OnWritableNameChanged();
}));
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([self] () -> void {
nsRefPtr<nsDOMDeviceStorage> listener = do_QueryReferent(self->mListener);
if (listener) {
listener->OnWritableNameChanged();
}
});
mOwningThread->Dispatch(r, NS_DISPATCH_NORMAL);
}
#ifdef MOZ_WIDGET_GONK
@ -791,9 +818,13 @@ DeviceStorageStatics::ListenerWrapper::OnVolumeStateChanged(nsIVolume* aVolume)
{
nsRefPtr<ListenerWrapper> self = this;
nsCOMPtr<nsIVolume> volume = aVolume;
NS_DispatchToMainThread(NS_NewRunnableFunction([self, volume] () -> void {
self->mDeviceStorage->OnVolumeStateChanged(volume);
}));
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([self, volume] () -> void {
nsRefPtr<nsDOMDeviceStorage> listener = do_QueryReferent(self->mListener);
if (listener) {
listener->OnVolumeStateChanged(volume);
}
});
mOwningThread->Dispatch(r, NS_DISPATCH_NORMAL);
}
#endif

View File

@ -19,7 +19,7 @@ namespace mozilla {
namespace dom {
namespace devicestorage {
class DeviceStorageStatics : public nsIObserver
class DeviceStorageStatics final : public nsIObserver
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
@ -72,6 +72,7 @@ private:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ListenerWrapper)
explicit ListenerWrapper(nsDOMDeviceStorage* aListener);
bool Equals(nsDOMDeviceStorage* aListener);
void OnFileWatcherUpdate(const nsCString& aData, DeviceStorageFile* aFile);
void OnDiskSpaceWatcher(bool aLowDiskSpace);
void OnWritableNameChanged();
@ -79,10 +80,11 @@ private:
void OnVolumeStateChanged(nsIVolume* aVolume);
#endif
nsRefPtr<nsDOMDeviceStorage> mDeviceStorage;
private:
virtual ~ListenerWrapper();
nsWeakPtr mListener;
nsCOMPtr<nsIThread> mOwningThread;
};
nsTArray<nsRefPtr<ListenerWrapper> > mListeners;

View File

@ -2898,6 +2898,12 @@ NS_IMPL_CYCLE_COLLECTION(DeviceStorageRequest,
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsDOMDeviceStorage)
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
/* nsISupports is an ambiguous base of nsDOMDeviceStorage
so we have to work around that. */
if ( aIID.Equals(NS_GET_IID(nsDOMDeviceStorage)) )
foundInterface = static_cast<nsISupports*>(static_cast<void*>(this));
else
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
NS_IMPL_ADDREF_INHERITED(nsDOMDeviceStorage, DOMEventTargetHelper)
@ -2997,6 +3003,7 @@ nsDOMDeviceStorage::~nsDOMDeviceStorage()
{
MOZ_ASSERT(NS_IsMainThread());
sInstanceCount--;
DeviceStorageStatics::RemoveListener(this);
}
void
@ -3028,7 +3035,20 @@ void nsDOMDeviceStorage::InvalidateVolumeCaches()
// static
void
nsDOMDeviceStorage::GetOrderedVolumeNames(
nsDOMDeviceStorage::VolumeNameArray &aVolumeNames)
const nsAString& aType,
nsDOMDeviceStorage::VolumeNameArray& aVolumeNames)
{
if (!DeviceStorageTypeChecker::IsVolumeBased(aType)) {
aVolumeNames.Clear();
return;
}
GetOrderedVolumeNames(aVolumeNames);
}
// static
void
nsDOMDeviceStorage::GetOrderedVolumeNames(
nsDOMDeviceStorage::VolumeNameArray& aVolumeNames)
{
MOZ_ASSERT(NS_IsMainThread());
@ -3077,12 +3097,7 @@ nsDOMDeviceStorage::CreateDeviceStorageFor(nsPIDOMWindow* aWin,
nsDOMDeviceStorage** aStore)
{
nsString storageName;
if (!DeviceStorageTypeChecker::IsVolumeBased(aType)) {
// The storage name will be the empty string
storageName.Truncate();
} else {
GetDefaultStorageName(aType, storageName);
}
GetDefaultStorageName(aType, storageName);
nsRefPtr<nsDOMDeviceStorage> ds = new nsDOMDeviceStorage(aWin);
if (NS_FAILED(ds->Init(aWin, aType, storageName))) {
@ -3092,37 +3107,6 @@ nsDOMDeviceStorage::CreateDeviceStorageFor(nsPIDOMWindow* aWin,
ds.forget(aStore);
}
// static
void
nsDOMDeviceStorage::CreateDeviceStoragesFor(
nsPIDOMWindow* aWin,
const nsAString &aType,
nsTArray<nsRefPtr<nsDOMDeviceStorage> > &aStores)
{
nsresult rv;
if (!DeviceStorageTypeChecker::IsVolumeBased(aType)) {
nsRefPtr<nsDOMDeviceStorage> storage = new nsDOMDeviceStorage(aWin);
rv = storage->Init(aWin, aType, EmptyString());
if (NS_SUCCEEDED(rv)) {
aStores.AppendElement(storage);
}
return;
}
VolumeNameArray volNames;
GetOrderedVolumeNames(volNames);
VolumeNameArray::size_type numVolumeNames = volNames.Length();
for (VolumeNameArray::index_type i = 0; i < numVolumeNames; i++) {
nsRefPtr<nsDOMDeviceStorage> storage = new nsDOMDeviceStorage(aWin);
rv = storage->Init(aWin, aType, volNames[i]);
if (NS_FAILED(rv)) {
break;
}
aStores.AppendElement(storage);
}
}
// static
void
nsDOMDeviceStorage::CreateDeviceStorageByNameAndType(
@ -3151,6 +3135,19 @@ nsDOMDeviceStorage::CreateDeviceStorageByNameAndType(
NS_ADDREF(*aStore = storage.get());
}
bool
nsDOMDeviceStorage::Equals(nsPIDOMWindow* aWin,
const nsAString& aName,
const nsAString& aType)
{
MOZ_ASSERT(aWin);
nsCOMPtr<nsPIDOMWindow> window = GetOwner();
return aWin && aWin == window &&
mStorageName.Equals(aName) &&
mStorageType.Equals(aType);
}
// static
bool
nsDOMDeviceStorage::ParseFullPath(const nsAString& aFullPath,
@ -3246,6 +3243,12 @@ void
nsDOMDeviceStorage::GetDefaultStorageName(const nsAString& aStorageType,
nsAString& aStorageName)
{
if (!DeviceStorageTypeChecker::IsVolumeBased(aStorageType)) {
// The storage name will be the empty string
aStorageName.Truncate();
return;
}
// See if the preferred volume is available.
nsString prefStorageName;
DeviceStorageStatics::GetWritableName(prefStorageName);

View File

@ -16,6 +16,7 @@
#include "nsDeviceStorage.h"
#include "nsIFile.h"
#include "nsPIDOMWindow.h"
#include "nsGlobalWindow.h"
namespace mozilla {
namespace dom {
@ -23,7 +24,7 @@ namespace dom {
DeviceStorageFileSystem::DeviceStorageFileSystem(
const nsAString& aStorageType,
const nsAString& aStorageName)
: mDeviceStorage(nullptr)
: mWindowId(0)
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
@ -76,14 +77,15 @@ DeviceStorageFileSystem::Init(nsDOMDeviceStorage* aDeviceStorage)
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aDeviceStorage);
mDeviceStorage = aDeviceStorage;
nsCOMPtr<nsPIDOMWindow> window = aDeviceStorage->GetOwner();
MOZ_ASSERT(window->IsInnerWindow());
mWindowId = window->WindowID();
}
void
DeviceStorageFileSystem::Shutdown()
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
mDeviceStorage = nullptr;
mShutdown = true;
}
@ -91,10 +93,9 @@ nsPIDOMWindow*
DeviceStorageFileSystem::GetWindow() const
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
if (!mDeviceStorage) {
return nullptr;
}
return mDeviceStorage->GetOwner();
nsGlobalWindow* window = nsGlobalWindow::GetInnerWindowWithId(mWindowId);
MOZ_ASSERT_IF(!mShutdown, window);
return window;
}
void

View File

@ -48,7 +48,7 @@ private:
nsString mStorageType;
nsString mStorageName;
nsDOMDeviceStorage* mDeviceStorage;
uint64_t mWindowId;
};
} // namespace dom