Bug 782352 - Broadcast local io to onchange listeners. r=sicking

This commit is contained in:
Doug Turner 2012-08-17 19:43:00 -07:00
parent f27b60d7fb
commit 3ff1f51432
9 changed files with 104 additions and 187 deletions

View File

@ -13,7 +13,6 @@
class nsDOMDeviceStorage MOZ_FINAL
: public nsIDOMDeviceStorage
, public nsIFileUpdateListener
, public nsDOMEventTargetHelper
, public nsIObserver
{
@ -21,7 +20,6 @@ public:
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMDEVICESTORAGE
NS_DECL_NSIFILEUPDATELISTENER
NS_DECL_NSIOBSERVER
NS_DECL_NSIDOMEVENTTARGET
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsDOMDeviceStorage, nsDOMEventTargetHelper)
@ -58,11 +56,13 @@ private:
nsCOMPtr<nsIPrincipal> mPrincipal;
bool mIsWatchingFile;
nsresult Notify(const char* aReason, nsIFile* aFile);
friend class WatchFileEvent;
friend class DeviceStorageRequest;
bool mIsWatchingFile;
#ifdef MOZ_WIDGET_GONK
void DispatchMountChangeEvent(nsAString& aType);
#endif

View File

@ -274,7 +274,7 @@ DeviceStorageRequestParent::DeleteFileEvent::CancelableRun()
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
mFile->mFile->Remove(true);
mFile->Remove();
nsRefPtr<nsRunnable> r;

View File

@ -50,6 +50,32 @@ using namespace mozilla::dom::devicestorage;
#include "nsDirectoryServiceDefs.h"
class IOEventComplete : public nsRunnable
{
public:
IOEventComplete(nsIFile *aFile, const char *aType)
: mFile(aFile)
, mType(aType)
{
}
~IOEventComplete() {}
NS_IMETHOD Run()
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
nsString data;
CopyASCIItoUTF16(mType, data);
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
obs->NotifyObservers(mFile, "file-watcher-update", data.get());
return NS_OK;
}
private:
nsCOMPtr<nsIFile> mFile;
nsCString mType;
};
DeviceStorageFile::DeviceStorageFile(nsIFile* aFile, const nsAString& aPath)
: mPath(aPath)
, mEditable(false)
@ -159,6 +185,9 @@ DeviceStorageFile::Write(nsIInputStream* aInputStream)
return rv;
}
nsCOMPtr<IOEventComplete> iocomplete = new IOEventComplete(mFile, "created");
NS_DispatchToMainThread(iocomplete);
PRUint64 bufSize = 0;
aInputStream->Available(&bufSize);
@ -181,13 +210,18 @@ DeviceStorageFile::Write(nsIInputStream* aInputStream)
rv = NS_OK;
while (bufSize) {
PRUint32 wrote;
rv = bufferedOutputStream->WriteFrom(aInputStream, static_cast<PRUint32>(NS_MIN<PRUint64>(bufSize, PR_UINT32_MAX)), &wrote);
rv = bufferedOutputStream->WriteFrom(aInputStream,
static_cast<PRUint32>(NS_MIN<PRUint64>(bufSize, PR_UINT32_MAX)),
&wrote);
if (NS_FAILED(rv)) {
break;
}
bufSize -= wrote;
}
iocomplete = new IOEventComplete(mFile, "modified");
NS_DispatchToMainThread(iocomplete);
bufferedOutputStream->Close();
outputStream->Close();
if (NS_FAILED(rv)) {
@ -204,6 +238,9 @@ DeviceStorageFile::Write(InfallibleTArray<PRUint8>& aBits) {
return rv;
}
nsCOMPtr<IOEventComplete> iocomplete = new IOEventComplete(mFile, "created");
NS_DispatchToMainThread(iocomplete);
nsCOMPtr<nsIOutputStream> outputStream;
NS_NewLocalFileOutputStream(getter_AddRefs(outputStream), mFile);
@ -215,12 +252,24 @@ DeviceStorageFile::Write(InfallibleTArray<PRUint8>& aBits) {
outputStream->Write((char*) aBits.Elements(), aBits.Length(), &wrote);
outputStream->Close();
iocomplete = new IOEventComplete(mFile, "modified");
NS_DispatchToMainThread(iocomplete);
if (aBits.Length() != wrote) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
nsresult
DeviceStorageFile::Remove()
{
mFile->Remove(true);
nsCOMPtr<IOEventComplete> iocomplete = new IOEventComplete(mFile, "deleted");
NS_DispatchToMainThread(iocomplete);
return NS_OK;
}
void
DeviceStorageFile::CollectFiles(nsTArray<nsRefPtr<DeviceStorageFile> > &aFiles,
PRUint64 aSince)
@ -447,6 +496,9 @@ nsDOMDeviceStorage::SetRootFileForType(const nsAString& aType)
#ifdef MOZ_WIDGET_GONK
RegisterForSDCardChanges(this);
#endif
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
obs->AddObserver(this, "file-watcher-update", false);
mFile = f;
}
@ -897,7 +949,6 @@ private:
nsRefPtr<DOMRequest> mRequest;
};
class PostResultEvent : public nsRunnable
{
public:
@ -970,10 +1021,8 @@ public:
return NS_OK;
}
nsCOMPtr<PostResultEvent> event = new PostResultEvent(mRequest,
mFile->mPath);
nsCOMPtr<PostResultEvent> event = new PostResultEvent(mRequest, mFile->mPath);
NS_DispatchToMainThread(event);
return NS_OK;
}
@ -982,6 +1031,7 @@ private:
nsRefPtr<DeviceStorageFile> mFile;
nsRefPtr<DOMRequest> mRequest;
};
class ReadFileEvent : public nsRunnable
{
public:
@ -1034,8 +1084,7 @@ public:
NS_IMETHOD Run()
{
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
mFile->mFile->Remove(true);
mFile->Remove();
nsRefPtr<nsRunnable> r;
@ -1283,22 +1332,7 @@ public:
case DEVICE_STORAGE_REQUEST_WATCH:
{
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;
// do something?
}
}
@ -1378,7 +1412,6 @@ 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)
@ -1425,19 +1458,9 @@ nsDOMDeviceStorage::Shutdown()
#ifdef MOZ_WIDGET_GONK
UnregisterForSDCardChanges(this);
#endif
if (mIsWatchingFile) {
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);
}
}
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
obs->RemoveObserver(this, "file-watcher-update");
}
void
@ -1792,39 +1815,16 @@ nsDOMDeviceStorage::Observe(nsISupports *aSubject, const char *aTopic, const PRU
{
if (!strcmp(aTopic, "file-watcher-update")) {
// 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)) {
nsCOMPtr<nsIFile> file = do_QueryInterface(aSubject);
if (!file) {
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;
CopyUTF16toUTF8(reason, creason);
Update(creason.get(), f);
Notify(NS_ConvertUTF16toUTF8(aData).get(), file);
return NS_OK;
}
#ifdef MOZ_WIDGET_GONK
if (!strcmp(aTopic, NS_VOLUME_STATE_CHANGED)) {
else if (!strcmp(aTopic, NS_VOLUME_STATE_CHANGED)) {
nsCOMPtr<nsIVolume> vol = do_QueryInterface(aSubject);
if (!vol) {
return NS_OK;
@ -1859,9 +1859,13 @@ nsDOMDeviceStorage::Observe(nsISupports *aSubject, const char *aTopic, const PRU
return NS_OK;
}
NS_IMETHODIMP
nsDOMDeviceStorage::Update(const char* aReason, nsIFile* aFile)
nsresult
nsDOMDeviceStorage::Notify(const char* aReason, nsIFile* aFile)
{
if (!mFile) {
return NS_ERROR_FAILURE;
}
nsString rootpath;
nsresult rv = mFile->GetPath(rootpath);
if (NS_FAILED(rv)) {
@ -1926,6 +1930,12 @@ nsDOMDeviceStorage::AddSystemEventListener(const nsAString & aType,
bool aWantsUntrusted,
PRUint8 aArgc)
{
if (!mIsWatchingFile) {
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
obs->AddObserver(this, "file-watcher-update", false);
mIsWatchingFile = true;
}
return nsDOMDeviceStorage::AddEventListener(aType,aListener,aUseCapture,aWantsUntrusted, aArgc);
}
@ -1937,16 +1947,9 @@ nsDOMDeviceStorage::RemoveEventListener(const nsAString & aType,
nsDOMEventTargetHelper::RemoveEventListener(aType, aListener, false);
if (mIsWatchingFile && !HasListenersFor(NS_LITERAL_STRING("change"))) {
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);
}
mIsWatchingFile = false;
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
obs->RemoveObserver(this, "file-watcher-update");
}
return NS_OK;
}

View File

@ -57,6 +57,7 @@ public:
// outside of the type of storage the user asked for.
bool IsSafePath();
nsresult Remove();
nsresult Write(nsIInputStream* aInputStream);
nsresult Write(InfallibleTArray<PRUint8>& bits);
void CollectFiles(nsTArray<nsRefPtr<DeviceStorageFile> > &aFiles, PRUint64 aSince = 0);

View File

@ -36,7 +36,7 @@ function addError(e) {
function onChange(e) {
dump("we saw: " + e.path);
dump("we saw: " + e.path + " " + e.reason + "\n");
if (e.path == gFileName) {
ok(true, "we saw the file get created");

View File

@ -947,15 +947,13 @@ ContentChild::RecvLastPrivateDocShellDestroyed()
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<nsIFile> file;
NS_NewLocalFile(path, false, getter_AddRefs(file));
nsString reason;
CopyASCIItoUTF16(aReason, reason);
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
obs->NotifyObservers(nullptr, "file-watcher-update", data.get());
obs->NotifyObservers(file, "file-watcher-update", reason.get());
return true;
}

View File

@ -370,6 +370,7 @@ ContentParent::Init()
obs->AddObserver(this, "child-gc-request", false);
obs->AddObserver(this, "child-cc-request", false);
obs->AddObserver(this, "last-pb-context-exited", false);
obs->AddObserver(this, "file-watcher-update", false);
#ifdef MOZ_WIDGET_GONK
obs->AddObserver(this, NS_VOLUME_STATE_CHANGED, false);
#endif
@ -543,6 +544,7 @@ ContentParent::ActorDestroy(ActorDestroyReason why)
obs->RemoveObserver(static_cast<nsIObserver*>(this), "child-gc-request");
obs->RemoveObserver(static_cast<nsIObserver*>(this), "child-cc-request");
obs->RemoveObserver(static_cast<nsIObserver*>(this), "last-pb-context-exited");
obs->RemoveObserver(static_cast<nsIObserver*>(this), "file-watcher-update");
#ifdef MOZ_WIDGET_GONK
obs->RemoveObserver(static_cast<nsIObserver*>(this), NS_VOLUME_STATE_CHANGED);
#endif
@ -697,8 +699,6 @@ ContentParent::ContentParent(const nsAString& aAppManifestURL)
//Sending all information to content process
unused << SendAppInfo(version, buildID);
}
mFileWatchers.Init();
}
ContentParent::~ContentParent()
@ -938,9 +938,6 @@ ContentParent::Observe(nsISupports* aSubject,
const PRUnichar* aData)
{
if (!strcmp(aTopic, "xpcom-shutdown") && mSubprocess) {
mFileWatchers.Clear();
Close();
NS_ASSERTION(!mSubprocess, "Close should have nulled mSubprocess");
}
@ -995,6 +992,18 @@ ContentParent::Observe(nsISupports* aSubject,
else if (!strcmp(aTopic, "last-pb-context-exited")) {
unused << SendLastPrivateDocShellDestroyed();
}
else if (!strcmp(aTopic, "file-watcher-update")) {
nsCString creason;
CopyUTF16toUTF8(aData, creason);
nsCOMPtr<nsIFile> file = do_QueryInterface(aSubject);
if (!file) {
return NS_OK;
}
nsString path;
file->GetPath(path);
unused << SendFilePathUpdate(path, creason);
}
#ifdef MOZ_WIDGET_GONK
else if(!strcmp(aTopic, NS_VOLUME_STATE_CHANGED)) {
nsCOMPtr<nsIVolume> vol = do_QueryInterface(aSubject);
@ -1739,64 +1748,5 @@ 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

View File

@ -23,7 +23,6 @@
#include "nsIMemoryReporter.h"
#include "nsCOMArray.h"
#include "nsDataHashtable.h"
#include "nsInterfaceHashtable.h"
#include "nsHashKeys.h"
class mozIApplication;
@ -274,9 +273,6 @@ private:
virtual bool RecvPrivateDocShellsExist(const bool& aExist);
virtual bool RecvAddFileWatch(const nsString& root);
virtual bool RecvRemoveFileWatch(const nsString& root);
virtual void ProcessingError(Result what) MOZ_OVERRIDE;
GeckoChildProcessHost* mSubprocess;
@ -297,34 +293,6 @@ private:
const nsString mAppManifestURL;
nsRefPtr<nsFrameMessageManager> mMessageManager;
class WatchedFile MOZ_FINAL : 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

@ -298,9 +298,6 @@ 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);
};