Bug 1346987 - Part 1: Introduce the asynchronous ContentChild::AsyncOpenAnonymousTemporaryFile() API; r=billm

This commit is contained in:
Ehsan Akhgari 2017-03-13 19:06:04 -04:00
Родитель 32cff5d448
Коммит 4482865081
5 изменённых файлов: 129 добавлений и 0 удалений

Просмотреть файл

@ -198,6 +198,7 @@
#include "gfxPlatform.h"
#include "nscore.h" // for NS_FREE_PERMANENT_DATA
#include "VRManagerChild.h"
#include "private/pprio.h"
#ifdef MOZ_WIDGET_GTK
#include "nsAppRunner.h"
@ -3222,5 +3223,43 @@ ContentChild::RecvParentActivated(PBrowserChild* aTab, const bool& aActivated)
return tab->RecvParentActivated(aActivated);
}
mozilla::ipc::IPCResult
ContentChild::RecvProvideAnonymousTemporaryFile(const uint64_t& aID,
const FileDescOrError& aFDOrError)
{
nsAutoPtr<AnonymousTemporaryFileCallback> callback;
mPendingAnonymousTemporaryFiles.RemoveAndForget(aID, callback);
MOZ_ASSERT(callback);
PRFileDesc* prfile = nullptr;
if (aFDOrError.type() == FileDescOrError::Tnsresult) {
DebugOnly<nsresult> rv = aFDOrError.get_nsresult();
MOZ_ASSERT(NS_FAILED(rv));
} else {
auto rawFD = aFDOrError.get_FileDescriptor().ClonePlatformHandle();
prfile = PR_ImportFile(PROsfd(rawFD.release()));
}
(*callback)(prfile);
return IPC_OK();
}
nsresult
ContentChild::AsyncOpenAnonymousTemporaryFile(AnonymousTemporaryFileCallback aCallback)
{
MOZ_ASSERT(NS_IsMainThread());
static uint64_t id = 0;
auto newID = id++;
if (!SendRequestAnonymousTemporaryFile(newID)) {
return NS_ERROR_FAILURE;
}
// Remember the association with the callback.
MOZ_ASSERT(!mPendingAnonymousTemporaryFiles.Get(newID));
mPendingAnonymousTemporaryFiles.LookupOrAdd(newID, aCallback);
return NS_OK;
}
} // namespace dom
} // namespace mozilla

Просмотреть файл

@ -586,6 +586,9 @@ public:
const StructuredCloneData& aInitialData,
nsTArray<LookAndFeelInt>&& aLookAndFeelIntCache) override;
virtual mozilla::ipc::IPCResult
RecvProvideAnonymousTemporaryFile(const uint64_t& aID, const FileDescOrError& aFD) override;
#if defined(XP_WIN) && defined(ACCESSIBILITY)
bool
SendGetA11yContentId();
@ -628,6 +631,9 @@ public:
const Optional<int64_t>& aLastModified,
bool aExistenceCheck, bool aIsFromNsIFile);
typedef std::function<void(PRFileDesc*)> AnonymousTemporaryFileCallback;
nsresult AsyncOpenAnonymousTemporaryFile(AnonymousTemporaryFileCallback aCallback);
private:
static void ForceKillTimerCallback(nsITimer* aTimer, void* aClosure);
void StartForceKillTimer();
@ -696,6 +702,9 @@ private:
// These items are removed when RecvFileCreationResponse is received.
nsRefPtrHashtable<nsIDHashKey, FileCreatorHelper> mFileCreationPending;
nsClassHashtable<nsUint64HashKey, AnonymousTemporaryFileCallback> mPendingAnonymousTemporaryFiles;
bool mShuttingDown;
DISALLOW_EVIL_CONSTRUCTORS(ContentChild);

Просмотреть файл

@ -4087,6 +4087,80 @@ ContentParent::RecvBackUpXResources(const FileDescriptor& aXSocketFd)
return IPC_OK();
}
class AnonymousTemporaryFileRequestor final : public Runnable
{
public:
AnonymousTemporaryFileRequestor(ContentParent* aCP, const uint64_t& aID)
: mCP(aCP)
, mID(aID)
, mRv(NS_OK)
, mPRFD(nullptr)
{
}
NS_IMETHOD Run() override
{
if (NS_IsMainThread()) {
FileDescOrError result;
if (NS_WARN_IF(NS_FAILED(mRv))) {
// Returning false will kill the child process; instead
// propagate the error and let the child handle it.
result = mRv;
} else {
result = FileDescriptor(FileDescriptor::PlatformHandleType(PR_FileDesc2NativeHandle(mPRFD)));
// The FileDescriptor object owns a duplicate of the file handle; we
// must close the original (and clean up the NSPR descriptor).
PR_Close(mPRFD);
}
Unused << mCP->SendProvideAnonymousTemporaryFile(mID, result);
// It's important to release this reference while wr're on the main thread!
mCP = nullptr;
} else {
mRv = NS_OpenAnonymousTemporaryFile(&mPRFD);
NS_DispatchToMainThread(this);
}
return NS_OK;
}
private:
RefPtr<ContentParent> mCP;
uint64_t mID;
nsresult mRv;
PRFileDesc* mPRFD;
};
mozilla::ipc::IPCResult
ContentParent::RecvRequestAnonymousTemporaryFile(const uint64_t& aID)
{
// Make sure to send a callback to the child if we bail out early.
nsresult rv = NS_OK;
RefPtr<ContentParent> self(this);
auto autoNotifyChildOnError = MakeScopeExit([&]() {
if (NS_FAILED(rv)) {
FileDescOrError result(rv);
Unused << self->SendProvideAnonymousTemporaryFile(aID, result);
}
});
// We use a helper runnable to open the anonymous temporary file on the IO
// thread. The same runnable will call us back on the main thread when the
// file has been opened.
nsCOMPtr<nsIEventTarget> target
= do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv);
if (!target) {
return IPC_OK();
}
rv = target->Dispatch(new AnonymousTemporaryFileRequestor(this, aID),
NS_DISPATCH_NORMAL);
if (NS_WARN_IF(NS_FAILED(rv))) {
return IPC_OK();
}
rv = NS_OK;
return IPC_OK();
}
mozilla::ipc::IPCResult
ContentParent::RecvOpenAnonymousTemporaryFile(FileDescOrError *aFD)
{

Просмотреть файл

@ -1058,6 +1058,9 @@ private:
virtual mozilla::ipc::IPCResult
RecvBackUpXResources(const FileDescriptor& aXSocketFd) override;
virtual mozilla::ipc::IPCResult
RecvRequestAnonymousTemporaryFile(const uint64_t& aID) override;
virtual mozilla::ipc::IPCResult
RecvOpenAnonymousTemporaryFile(FileDescOrError* aFD) override;

Просмотреть файл

@ -591,6 +591,8 @@ child:
async PParentToChildStream();
async ProvideAnonymousTemporaryFile(uint64_t aID, FileDescOrError aFD);
parent:
async InitBackground(Endpoint<PBackgroundParent> aEndpoint);
@ -872,6 +874,8 @@ parent:
*/
async BackUpXResources(FileDescriptor aXSocketFd);
async RequestAnonymousTemporaryFile(uint64_t aID);
sync OpenAnonymousTemporaryFile() returns (FileDescOrError aFD);
/**