Bug 763976 - Add onchange notifications to DeviceStorage - IPC - r=khuey

This commit is contained in:
Doug Turner 2012-08-01 23:32:04 -07:00
parent 0cc5c1e0ee
commit 7f0d522454
7 changed files with 197 additions and 8 deletions

View File

@ -7,18 +7,21 @@
#include "nsIDOMDeviceStorage.h"
#include "nsIFile.h"
#include "nsIObserver.h"
#include "nsDOMEventTargetHelper.h"
class nsDOMDeviceStorage MOZ_FINAL
: public nsIDOMDeviceStorage
, public nsIFileUpdateListener
, public nsDOMEventTargetHelper
, public nsIObserver
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMDEVICESTORAGE
NS_DECL_NSIFILEUPDATELISTENER
NS_DECL_NSIOBSERVER
NS_DECL_NSIDOMEVENTTARGET
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsDOMDeviceStorage, nsDOMEventTargetHelper)
NS_DECL_EVENT_HANDLER(change)

View File

@ -1216,10 +1216,21 @@ public:
case DEVICE_STORAGE_REQUEST_WATCH:
{
if (!mDeviceStorage->mIsWatchingFile) {
mFile->mFile->Watch(mDeviceStorage);
mDeviceStorage->mIsWatchingFile = true;
}
if (XRE_GetProcessType() != GeckoProcessType_Default) {
nsString fullpath;
mFile->mFile->GetPath(fullpath);
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
obs->AddObserver(mDeviceStorage, "file-watcher-update", false);
ContentChild::GetSingleton()->SendAddFileWatch(fullpath);
} else {
if (!mDeviceStorage->mIsWatchingFile) {
//TODO
mFile->mFile->Watch(mDeviceStorage);
mDeviceStorage->mIsWatchingFile = true;
}
}
return NS_OK;
}
}
@ -1301,6 +1312,7 @@ DOMCI_DATA(DeviceStorage, nsDOMDeviceStorage)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsDOMDeviceStorage)
NS_INTERFACE_MAP_ENTRY(nsIDOMDeviceStorage)
NS_INTERFACE_MAP_ENTRY(nsIFileUpdateListener)
NS_INTERFACE_MAP_ENTRY(nsIObserver)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(DeviceStorage)
NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
@ -1345,7 +1357,17 @@ nsDOMDeviceStorage::Shutdown()
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
if (mIsWatchingFile) {
mFile->Unwatch(this);
if (XRE_GetProcessType() != GeckoProcessType_Default) {
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
obs->RemoveObserver(this, "file-watcher-update");
nsString fullpath;
mFile->GetPath(fullpath);
ContentChild::GetSingleton()->SendRemoveFileWatch(fullpath);
}
else {
mFile->Unwatch(this);
}
}
}
@ -1633,6 +1655,42 @@ nsDOMDeviceStorage::EnumerateInternal(const JS::Value & aName,
return NS_OK;
}
NS_IMETHODIMP
nsDOMDeviceStorage::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *aData)
{
// data strings will have the format of
// reason:path
nsDependentString data(aData);
nsAString::const_iterator start, end;
nsAString::const_iterator colon;
data.BeginReading(start);
data.EndReading(end);
colon = end;
nsString reason;
nsString filepath;
if (!FindInReadable(NS_LITERAL_STRING(":"), start, colon)) {
return NS_OK;
}
filepath = Substring(colon, end);
data.BeginReading(start);
reason = Substring(start, --colon);
nsCOMPtr<nsIFile> f;
NS_NewLocalFile(filepath, false, getter_AddRefs(f));
nsCString creason;
creason.AssignWithConversion(reason);
CopyUTF16toUTF8(reason, creason);
Update(creason.get(), f);
return NS_OK;
}
NS_IMETHODIMP
nsDOMDeviceStorage::Update(const char* aReason, nsIFile* aFile)
{
@ -1709,7 +1767,16 @@ nsDOMDeviceStorage::RemoveEventListener(const nsAString & aType,
nsDOMEventTargetHelper::RemoveEventListener(aType, aListener, false);
if (mIsWatchingFile && !HasListenersFor(NS_LITERAL_STRING("change"))) {
mFile->Unwatch(this);
if (XRE_GetProcessType() != GeckoProcessType_Default) {
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
obs->RemoveObserver(this, "file-watcher-update");
nsString fullpath;
mFile->GetPath(fullpath);
ContentChild::GetSingleton()->SendRemoveFileWatch(fullpath);
} else {
mFile->Unwatch(this);
}
}
return NS_OK;
}

View File

@ -911,5 +911,20 @@ ContentChild::RecvLastPrivateDocShellDestroyed()
return true;
}
bool
ContentChild::RecvFilePathUpdate(const nsString& path, const nsCString& aReason)
{
// data strings will have the format of
// reason:path
nsString data;
CopyASCIItoUTF16(aReason, data);
data.Append(NS_LITERAL_STRING(":"));
data.Append(path);
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
obs->NotifyObservers(nullptr, "file-watcher-update", data.get());
return true;
}
} // namespace dom
} // namespace mozilla
} // namespace mozilla

View File

@ -162,6 +162,8 @@ public:
virtual bool RecvLastPrivateDocShellDestroyed();
virtual bool RecvFilePathUpdate(const nsString& path, const nsCString& reason);
#ifdef ANDROID
gfxIntSize GetScreenSize() { return mScreenSize; }
#endif

View File

@ -528,6 +528,8 @@ ContentParent::ContentParent(const nsAString& aAppManifestURL)
//Sending all information to content process
unused << SendAppInfo(version, buildID);
}
mFileWatchers.Init();
}
ContentParent::~ContentParent()
@ -764,6 +766,9 @@ ContentParent::Observe(nsISupports* aSubject,
const PRUnichar* aData)
{
if (!strcmp(aTopic, "xpcom-shutdown") && mSubprocess) {
mFileWatchers.Clear();
Close();
NS_ASSERTION(!mSubprocess, "Close should have nulled mSubprocess");
}
@ -1507,5 +1512,64 @@ ContentParent::RecvPrivateDocShellsExist(const bool& aExist)
return true;
}
bool
ContentParent::RecvAddFileWatch(const nsString& root)
{
nsRefPtr<WatchedFile> f;
if (mFileWatchers.Get(root, getter_AddRefs(f))) {
f->mUsageCount++;
return true;
}
f = new WatchedFile(this, root);
mFileWatchers.Put(root, f);
f->Watch();
return true;
}
bool
ContentParent::RecvRemoveFileWatch(const nsString& root)
{
nsRefPtr<WatchedFile> f;
bool result = mFileWatchers.Get(root, getter_AddRefs(f));
if (!result) {
return true;
}
if (!f)
return true;
f->mUsageCount--;
if (f->mUsageCount > 0) {
return true;
}
f->Unwatch();
mFileWatchers.Remove(root);
return true;
}
NS_IMPL_ISUPPORTS1(ContentParent::WatchedFile, nsIFileUpdateListener)
nsresult
ContentParent::WatchedFile::Update(const char* aReason, nsIFile* aFile)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
nsString path;
aFile->GetPath(path);
unused << mParent->SendFilePathUpdate(path, nsDependentCString(aReason));
#ifdef DEBUG
nsCString cpath;
aFile->GetNativePath(cpath);
printf("ContentParent::WatchedFile::Update: %s -- %s\n", cpath.get(), aReason);
#endif
return NS_OK;
}
} // namespace dom
} // namespace mozilla
} // namespace mozilla

View File

@ -22,6 +22,7 @@
#include "nsIMemoryReporter.h"
#include "nsCOMArray.h"
#include "nsDataHashtable.h"
#include "nsInterfaceHashtable.h"
#include "nsHashKeys.h"
class nsFrameMessageManager;
@ -256,6 +257,10 @@ private:
const nsCString& aCategory);
virtual bool RecvPrivateDocShellsExist(const bool& aExist);
virtual bool RecvAddFileWatch(const nsString& root);
virtual bool RecvRemoveFileWatch(const nsString& root);
GeckoChildProcessHost* mSubprocess;
PRInt32 mGeolocationWatchID;
@ -274,6 +279,34 @@ private:
const nsString mAppManifestURL;
nsRefPtr<nsFrameMessageManager> mMessageManager;
class WatchedFile : public nsIFileUpdateListener {
public:
WatchedFile(ContentParent* aParent, const nsString& aPath)
: mParent(aParent)
, mUsageCount(1)
{
NS_NewLocalFile(aPath, false, getter_AddRefs(mFile));
}
NS_DECL_ISUPPORTS
NS_DECL_NSIFILEUPDATELISTENER
void Watch() {
mFile->Watch(this);
}
void Unwatch() {
mFile->Watch(this);
}
nsRefPtr<ContentParent> mParent;
PRInt32 mUsageCount;
nsCOMPtr<nsIFile> mFile;
};
// This is a cache of all of the registered file watchers.
nsInterfaceHashtable<nsStringHashKey, WatchedFile> mFileWatchers;
friend class CrashReporterParent;
};

View File

@ -199,6 +199,8 @@ child:
// Notify child that last-pb-context-exited notification was observed
LastPrivateDocShellDestroyed();
FilePathUpdate(nsString filepath, nsCString reasons);
parent:
PAudio(PRInt32 aNumChannels, PRInt32 aRate, PRInt32 aFormat);
@ -281,6 +283,9 @@ parent:
// Notify the parent of the presence or absence of private docshells
PrivateDocShellsExist(bool aExist);
AddFileWatch(nsString filepath);
RemoveFileWatch(nsString filepath);
both:
AsyncMessage(nsString aMessage, ClonedMessageData aData);
};