Browse Source

import changes from `dev' branch of rmottola/Arctic-Fox:

- Bug 1173051 - Minor optimizations for device storage enumerate on parent and child. r=dhylands (31037e471a)
- Bug 1020179 followup: Mark DeviceStorageRequest::GetRequester as override (and use NS_IMETHOD instead of NS_IMETHODIMP inside of class definition). rs=ehsan (b2a0808c21)
- Bug 1171170 - Consolidate/cache access to permissions, cycle collected objects in device storage. r=dhylands (8eddc30aed)
- Bug 1204618 - Add a field to the DeviceStorage object holding the low-disk-space status. r=dhylands, r=bzbarsky (52257b821f)
- Bug 1128505 - Preload Webapps.js for faster mozApps instantiation. r=fabrice (d540be89af)
- Bug 1166207 - Load preload.js in the Nuwa process. r=khuey (1310da32df)
- MOZ_FINAL -> final (887f351669)
- Bug 1200922: Add the ability to shut down a thread asynchronously. r=froydnj (b09ea156b6)
- Bug 1195767 - part 1 - remove nsCOMPtr temporary from nsEventQueue::PtEvent; r=gerald (fed354ffb7)
- Bug 1195767 - part 2 - create an nsEventQueueBase templated over the monitor type; r=gerald (ede20ac6f4)
- Bug 1202497 - part 1 - switch nsEventQueue to use a non-reentrant Monitor; r=gerald (cd043d1267)
- Bug 1195767 - part 3 - modify nsThreadPool to use a non-reentrant monitor; r=gerald (52eec3d125)
- Bug 1202497 - part 2 - remove ReentrantMonitor specializations for nsEventQueueBase; r=gerald (ceb1a9e63e)
- Bug 1202497 - part 3 - remove nsThread::GetEvent; r=gerald (ef9a5924fe)
- Bug 1202828 - use nsEventQueue::HasPendingEvent in nsThread.cpp; r=mccr8 nsEventQueue's HasPending event is defined to simply: (2e7a6ebcd2)
- Bug 1202497 - part 4 - lock around call to nsChainedEventQueue::HasPendingEvent; r=gerald (bc69bb30db)
- Bug 1202497 - part 5 - make the locking requirements of nsChainedEventQueue explicit; r=gerald (fbd73f2b0c)
- Bug 1195767 - part 4 - remove nsEventQueue::GetReentrantMonitor; r=gerald (1dfa6b186a)
- Bug 1195767 - part 5 - use signaling instead of broadcast when work items are placed in nsEventQueue; r=gerald (1f01f6198a)
- Bug 1202497 - part 6 - make the locking requirements of nsEventQueue explicit; r=gerald (7aaf4eb9cd)
- Bug 1202497 - part 7 - make nsEventQueue use external locking; r=gerald (2b31ff22f0)
- Bug 1202497 - follow-up - fix static analysis bustage; r=me (b7997e75f5)
- Bug 1197672 - s/_sendPromise/createPromiseWithId/ in mozInputMethod.addInput(). r=kchen (fb8e91e67e)
- Bug 1132349 - Test for focus removal after pagehide/submit/beforeload. r=janjongboom (a9adc87bb5)
- Bug 1137557 - Part 3: Allow content to pass a dict representing the property of the keyboard event to send. r=masayuki, sr=smaug (4e27b2bfc9)
- Bug 895274 part.18 Rename NS_PLUGIN_ACTIVATE to ePluginActivate r=smaug (6ad79fee12)
- Bug 1167069 - Watch out for deletion of current frame. r=jmathies (2868b2689d)
- Bug 895274 part.19 Rename NS_PLUGIN_FOCUS to ePluginFocus r=smaug (792d1d41d8)
- Bug 895274 part.20 Rename NS_OFFLINE to eOffline r=smaug (6eab162432)
- Bug 895274 part.21 Rename NS_ONLINE to eOnline r=smaug (91fb9aea87)
- Bug 895274 part.22 Get rid of NS_MOZ_USER_* since nobody is using them r=smaug (a46848bfc5)
- Bug 895274 part.23 Rename NS_LANGUAGECHANGE to eLanguageChange r=smaug (11ee7a6511)
- Bug 895274 part.24 Rename NS_MOUSE_MESSAGE_START to eMouseEventFirst r=smaug (52168d3374)
master
roytam1 2 months ago
parent
commit
c554d461ab
  1. 12
      dom/browser-element/BrowserElementChildPreload.js
  2. 43
      dom/devicestorage/DeviceStorage.h
  3. 131
      dom/devicestorage/DeviceStorageRequestChild.cpp
  4. 15
      dom/devicestorage/DeviceStorageRequestChild.h
  5. 31
      dom/devicestorage/DeviceStorageStatics.cpp
  6. 2
      dom/devicestorage/DeviceStorageStatics.h
  7. 3055
      dom/devicestorage/nsDeviceStorage.cpp
  8. 291
      dom/devicestorage/nsDeviceStorage.h
  9. 6
      dom/ipc/ContentChild.cpp
  10. 79
      dom/ipc/TabChild.cpp
  11. 57
      dom/ipc/preload.js
  12. 3
      dom/webidl/DeviceStorage.webidl
  13. 10
      ipc/glue/MessageChannel.h
  14. 20
      ipc/glue/MessageLink.cpp
  15. 16
      ipc/glue/MessageLink.h
  16. 2
      ipc/glue/ProtocolUtils.h
  17. 24
      mozglue/build/Nuwa.cpp
  18. 10
      mozglue/build/Nuwa.h
  19. 15
      xpcom/threads/nsThread.cpp

12
dom/browser-element/BrowserElementChildPreload.js

@ -1622,5 +1622,13 @@ BrowserElementChild.prototype = {
}
};
var api = new BrowserElementChild();
var api = null;
if ('DoPreloadPostfork' in this && typeof this.DoPreloadPostfork === 'function') {
// If we are preloaded, instantiate BrowserElementChild after a content
// process is forked.
this.DoPreloadPostfork(function() {
api = new BrowserElementChild();
});
} else {
api = new BrowserElementChild();
}

43
dom/devicestorage/DeviceStorage.h

@ -41,9 +41,15 @@ class DeviceStorageFileSystem;
} // namespace dom
namespace ipc {
class FileDescriptor;
class PrincipalInfo;
} // namespace ipc
} // namespace mozilla
class DeviceStorageRequest;
class DeviceStorageCursorRequest;
class DeviceStorageRequestManager;
class nsDOMDeviceStorageCursor;
class DeviceStorageFile final
: public nsISupports {
public:
@ -197,10 +203,6 @@ public:
AppendNamed(mozilla::dom::Blob* aBlob, const nsAString& aPath,
ErrorResult& aRv);
already_AddRefed<DOMRequest>
AddOrAppendNamed(mozilla::dom::Blob* aBlob, const nsAString& aPath,
const int32_t aRequestType, ErrorResult& aRv);
already_AddRefed<DOMRequest>
Get(const nsAString& aPath, ErrorResult& aRv)
{
@ -247,6 +249,7 @@ public:
bool CanBeFormatted();
bool CanBeShared();
bool IsRemovable();
bool LowDiskSpace();
bool Default();
void GetStorageName(nsAString& aStorageName);
@ -290,15 +293,31 @@ public:
void OnVolumeStateChanged(nsIVolume* aVolume);
#endif
uint32_t CreateDOMRequest(DOMRequest** aRequest, ErrorResult& aRv);
uint32_t CreateDOMCursor(DeviceStorageCursorRequest* aRequest,
nsDOMDeviceStorageCursor** aCursor,
ErrorResult& aRv);
already_AddRefed<DOMRequest> CreateAndRejectDOMRequest(const char *aReason,
ErrorResult& aRv);
nsresult CheckPermission(DeviceStorageRequest* aRequest);
void StorePermission(DeviceStorageRequest* aRequest, bool aAllow);
bool IsOwningThread();
nsresult DispatchToOwningThread(nsIRunnable* aRunnable);
private:
~nsDOMDeviceStorage();
static nsresult CheckPrincipal(nsPIDOMWindow* aWindow, bool aIsAppsStorage,
nsIPrincipal** aPrincipal);
already_AddRefed<DOMRequest>
GetInternal(const nsAString& aPath, bool aEditable, ErrorResult& aRv);
AddOrAppendNamed(mozilla::dom::Blob* aBlob, const nsAString& aPath,
bool aCreate, ErrorResult& aRv);
void
GetInternal(nsPIDOMWindow* aWin, const nsAString& aPath, DOMRequest* aRequest,
bool aEditable);
already_AddRefed<DOMRequest>
GetInternal(const nsAString& aPath, bool aEditable, ErrorResult& aRv);
void
DeleteInternal(nsPIDOMWindow* aWin, const nsAString& aPath,
@ -327,10 +346,6 @@ private:
const nsAString& aStorageName,
const nsAString& aType);
nsCOMPtr<nsIPrincipal> mPrincipal;
bool mIsWatchingFile;
bool mAllowedToWatchFile;
bool mIsDefaultLocation;
nsresult Notify(const char* aReason, class DeviceStorageFile* aFile);
@ -347,7 +362,11 @@ private:
void DispatchStorageStatusChangeEvent(nsAString& aStorageStatus);
#endif
uint64_t mInnerWindowID;
nsRefPtr<DeviceStorageFileSystem> mFileSystem;
nsRefPtr<DeviceStorageRequestManager> mManager;
nsAutoPtr<mozilla::ipc::PrincipalInfo> mPrincipalInfo;
nsCOMPtr<nsIThread> mOwningThread;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsDOMDeviceStorage, NS_DOM_DEVICE_STORAGE_CID)

131
dom/devicestorage/DeviceStorageRequestChild.cpp

@ -16,33 +16,14 @@ namespace dom {
namespace devicestorage {
DeviceStorageRequestChild::DeviceStorageRequestChild()
: mCallback(nullptr)
{
MOZ_COUNT_CTOR(DeviceStorageRequestChild);
}
DeviceStorageRequestChild::DeviceStorageRequestChild(DOMRequest* aRequest,
DeviceStorageFile* aDSFile)
DeviceStorageRequestChild::DeviceStorageRequestChild(DeviceStorageRequest* aRequest)
: mRequest(aRequest)
, mDSFile(aDSFile)
, mCallback(nullptr)
{
MOZ_ASSERT(aRequest);
MOZ_ASSERT(aDSFile);
MOZ_COUNT_CTOR(DeviceStorageRequestChild);
}
DeviceStorageRequestChild::DeviceStorageRequestChild(DOMRequest* aRequest,
DeviceStorageFile* aDSFile,
DeviceStorageFileDescriptor* aDSFileDescriptor)
: mRequest(aRequest)
, mDSFile(aDSFile)
, mDSFileDescriptor(aDSFileDescriptor)
, mCallback(nullptr)
{
MOZ_ASSERT(aRequest);
MOZ_ASSERT(aDSFile);
MOZ_ASSERT(aDSFileDescriptor);
MOZ_COUNT_CTOR(DeviceStorageRequestChild);
}
@ -54,159 +35,126 @@ bool
DeviceStorageRequestChild::
Recv__delete__(const DeviceStorageResponseValue& aValue)
{
if (mCallback) {
mCallback->RequestComplete();
mCallback = nullptr;
}
nsCOMPtr<nsPIDOMWindow> window = mRequest->GetOwner();
if (!window) {
return true;
}
switch (aValue.type()) {
case DeviceStorageResponseValue::TErrorResponse:
{
DS_LOG_INFO("error %u", mRequest->GetId());
ErrorResponse r = aValue;
mRequest->FireError(r.error());
mRequest->Reject(r.error());
break;
}
case DeviceStorageResponseValue::TSuccessResponse:
{
DS_LOG_INFO("success %u", mRequest->GetId());
nsString fullPath;
mDSFile->GetFullPath(fullPath);
AutoJSContext cx;
JS::Rooted<JS::Value> result(cx);
StringToJsval(window, fullPath, &result);
mRequest->FireSuccess(result);
mRequest->GetFile()->GetFullPath(fullPath);
mRequest->Resolve(fullPath);
break;
}
case DeviceStorageResponseValue::TFileDescriptorResponse:
{
DS_LOG_INFO("fd %u", mRequest->GetId());
FileDescriptorResponse r = aValue;
DeviceStorageFile* file = mRequest->GetFile();
DeviceStorageFileDescriptor* descriptor = mRequest->GetFileDescriptor();
nsString fullPath;
mDSFile->GetFullPath(fullPath);
AutoJSContext cx;
JS::Rooted<JS::Value> result(cx);
StringToJsval(window, fullPath, &result);
mDSFileDescriptor->mDSFile = mDSFile;
mDSFileDescriptor->mFileDescriptor = r.fileDescriptor();
mRequest->FireSuccess(result);
file->GetFullPath(fullPath);
descriptor->mDSFile = file;
descriptor->mFileDescriptor = r.fileDescriptor();
mRequest->Resolve(fullPath);
break;
}
case DeviceStorageResponseValue::TBlobResponse:
{
DS_LOG_INFO("blob %u", mRequest->GetId());
BlobResponse r = aValue;
BlobChild* actor = static_cast<BlobChild*>(r.blobChild());
nsRefPtr<BlobImpl> bloblImpl = actor->GetBlobImpl();
nsRefPtr<Blob> blob = Blob::Create(mRequest->GetParentObject(),
bloblImpl);
AutoJSContext cx;
JS::Rooted<JSObject*> obj(cx, blob->WrapObject(cx, nullptr));
MOZ_ASSERT(obj);
JS::Rooted<JS::Value> result(cx, JS::ObjectValue(*obj));
mRequest->FireSuccess(result);
nsRefPtr<BlobImpl> blobImpl = actor->GetBlobImpl();
mRequest->Resolve(blobImpl.get());
break;
}
case DeviceStorageResponseValue::TFreeSpaceStorageResponse:
{
DS_LOG_INFO("free %u", mRequest->GetId());
FreeSpaceStorageResponse r = aValue;
AutoJSContext cx;
JS::Rooted<JS::Value> result(cx, JS_NumberValue(double(r.freeBytes())));
mRequest->FireSuccess(result);
mRequest->Resolve(r.freeBytes());
break;
}
case DeviceStorageResponseValue::TUsedSpaceStorageResponse:
{
DS_LOG_INFO("used %u", mRequest->GetId());
UsedSpaceStorageResponse r = aValue;
AutoJSContext cx;
JS::Rooted<JS::Value> result(cx, JS_NumberValue(double(r.usedBytes())));
mRequest->FireSuccess(result);
mRequest->Resolve(r.usedBytes());
break;
}
case DeviceStorageResponseValue::TAvailableStorageResponse:
{
DS_LOG_INFO("available %u", mRequest->GetId());
AvailableStorageResponse r = aValue;
AutoJSContext cx;
JS::Rooted<JS::Value> result(cx);
StringToJsval(window, r.mountState(), &result);
mRequest->FireSuccess(result);
mRequest->Resolve(r.mountState());
break;
}
case DeviceStorageResponseValue::TStorageStatusResponse:
{
DS_LOG_INFO("status %u", mRequest->GetId());
StorageStatusResponse r = aValue;
AutoJSContext cx;
JS::Rooted<JS::Value> result(cx);
StringToJsval(window, r.storageStatus(), &result);
mRequest->FireSuccess(result);
mRequest->Resolve(r.storageStatus());
break;
}
case DeviceStorageResponseValue::TFormatStorageResponse:
{
DS_LOG_INFO("format %u", mRequest->GetId());
FormatStorageResponse r = aValue;
AutoJSContext cx;
JS::Rooted<JS::Value> result(cx);
StringToJsval(window, r.mountState(), &result);
mRequest->FireSuccess(result);
mRequest->Resolve(r.mountState());
break;
}
case DeviceStorageResponseValue::TMountStorageResponse:
{
DS_LOG_INFO("mount %u", mRequest->GetId());
MountStorageResponse r = aValue;
AutoJSContext cx;
JS::Rooted<JS::Value> result(cx);
StringToJsval(window, r.storageStatus(), &result);
mRequest->FireSuccess(result);
mRequest->Resolve(r.storageStatus());
break;
}
case DeviceStorageResponseValue::TUnmountStorageResponse:
{
DS_LOG_INFO("unmount %u", mRequest->GetId());
UnmountStorageResponse r = aValue;
AutoJSContext cx;
JS::Rooted<JS::Value> result(cx);
StringToJsval(window, r.storageStatus(), &result);
mRequest->FireSuccess(result);
mRequest->Resolve(r.storageStatus());
break;
}
case DeviceStorageResponseValue::TEnumerationResponse:
{
DS_LOG_INFO("enumerate %u", mRequest->GetId());
EnumerationResponse r = aValue;
nsDOMDeviceStorageCursor* cursor
= static_cast<nsDOMDeviceStorageCursor*>(mRequest.get());
auto request = static_cast<DeviceStorageCursorRequest*>(mRequest.get());
uint32_t count = r.paths().Length();
request->AddFiles(count);
for (uint32_t i = 0; i < count; i++) {
nsRefPtr<DeviceStorageFile> dsf
= new DeviceStorageFile(r.type(), r.paths()[i].storageName(),
r.rootdir(), r.paths()[i].name());
cursor->mFiles.AppendElement(dsf);
request->AddFile(dsf.forget());
}
nsRefPtr<ContinueCursorEvent> event = new ContinueCursorEvent(cursor);
event->Continue();
request->Continue();
break;
}
default:
{
DS_LOG_ERROR("unknown %u", mRequest->GetId());
NS_RUNTIMEABORT("not reached");
break;
}
@ -214,13 +162,6 @@ DeviceStorageRequestChild::
return true;
}
void
DeviceStorageRequestChild::
SetCallback(DeviceStorageRequestChildCallback *aCallback)
{
mCallback = aCallback;
}
} // namespace devicestorage
} // namespace dom
} // namespace mozilla

15
dom/devicestorage/DeviceStorageRequestChild.h

@ -10,13 +10,12 @@
#include "mozilla/dom/devicestorage/PDeviceStorageRequestChild.h"
class DeviceStorageFile;
class DeviceStorageRequest;
struct DeviceStorageFileDescriptor;
namespace mozilla {
namespace dom {
class DOMRequest;
namespace devicestorage {
class DeviceStorageRequestChildCallback
@ -29,21 +28,13 @@ class DeviceStorageRequestChild : public PDeviceStorageRequestChild
{
public:
DeviceStorageRequestChild();
DeviceStorageRequestChild(DOMRequest* aRequest, DeviceStorageFile* aFile);
DeviceStorageRequestChild(DOMRequest* aRequest, DeviceStorageFile* aFile,
DeviceStorageFileDescriptor* aFileDescrptor);
explicit DeviceStorageRequestChild(DeviceStorageRequest* aRequest);
~DeviceStorageRequestChild();
void SetCallback(class DeviceStorageRequestChildCallback *aCallback);
virtual bool Recv__delete__(const DeviceStorageResponseValue& value);
private:
nsRefPtr<DOMRequest> mRequest;
nsRefPtr<DeviceStorageFile> mDSFile;
nsRefPtr<DeviceStorageFileDescriptor> mDSFileDescriptor;
DeviceStorageRequestChildCallback* mCallback;
nsRefPtr<DeviceStorageRequest> mRequest;
};
} // namespace devicestorage

31
dom/devicestorage/DeviceStorageStatics.cpp

@ -72,6 +72,7 @@ DeviceStorageStatics::InitializeDirs()
DeviceStorageStatics::DeviceStorageStatics()
: mInitialized(false)
, mPromptTesting(false)
, mLowDiskSpace(false)
{
DS_LOG_INFO("");
}
@ -358,6 +359,16 @@ DeviceStorageStatics::IsPromptTesting()
return sInstance->mPromptTesting;
}
/* static */ bool
DeviceStorageStatics::LowDiskSpace()
{
StaticMutexAutoLock lock(sMutex);
if (NS_WARN_IF(!sInstance)) {
return false;
}
return sInstance->mLowDiskSpace;
}
/* static */ void
DeviceStorageStatics::GetWritableName(nsString& aName)
{
@ -605,27 +616,29 @@ DeviceStorageStatics::Observe(nsISupports* aSubject,
}
if (!strcmp(aTopic, kDiskSpaceWatcher)) {
StaticMutexAutoLock lock(sMutex);
if (NS_WARN_IF(!sInstance)) {
return NS_OK;
}
// 'disk-space-watcher' notifications are sent when there is a modification
// of a file in a specific location while a low device storage situation
// exists or after recovery of a low storage situation. For Firefox OS,
// these notifications are specific for apps storage.
bool lowDiskSpace = false;
if (!NS_strcmp(aData, MOZ_UTF16("full"))) {
lowDiskSpace = true;
} else if (NS_strcmp(aData, MOZ_UTF16("free"))) {
sInstance->mLowDiskSpace = true;
} else if (!NS_strcmp(aData, MOZ_UTF16("free"))) {
sInstance->mLowDiskSpace = false;
} else {
return NS_OK;
}
StaticMutexAutoLock lock(sMutex);
if (NS_WARN_IF(!sInstance)) {
return NS_OK;
}
uint32_t i = mListeners.Length();
DS_LOG_INFO("disk space %d (%u)", lowDiskSpace, i);
DS_LOG_INFO("disk space %d (%u)", sInstance->mLowDiskSpace, i);
while (i > 0) {
--i;
mListeners[i]->OnDiskSpaceWatcher(lowDiskSpace);
mListeners[i]->OnDiskSpaceWatcher(sInstance->mLowDiskSpace);
}
return NS_OK;
}

2
dom/devicestorage/DeviceStorageStatics.h

@ -30,6 +30,7 @@ public:
static void AddListener(nsDOMDeviceStorage* aListener);
static void RemoveListener(nsDOMDeviceStorage* aListener);
static bool LowDiskSpace();
static bool IsPromptTesting();
static void GetWritableName(nsString& aName);
static void SetWritableName(const nsAString& aName);
@ -92,6 +93,7 @@ private:
bool mInitialized;
bool mPromptTesting;
bool mLowDiskSpace;
nsString mWritableName;
static StaticRefPtr<DeviceStorageStatics> sInstance;

3055
dom/devicestorage/nsDeviceStorage.cpp

File diff suppressed because it is too large Load Diff

291
dom/devicestorage/nsDeviceStorage.h

@ -8,6 +8,7 @@
#define nsDeviceStorage_h
class nsPIDOMWindow;
#include "mozilla/Atomics.h"
#include "mozilla/Attributes.h"
#include "mozilla/Logging.h"
#include "mozilla/dom/devicestorage/DeviceStorageRequestChild.h"
@ -18,7 +19,6 @@ class nsPIDOMWindow;
#include "nsCycleCollectionParticipant.h"
#include "nsDOMClassInfoID.h"
#include "nsIClassInfo.h"
#include "nsIContentPermissionPrompt.h"
#include "nsIDOMWindow.h"
#include "nsIURI.h"
#include "nsIPrincipal.h"
@ -36,13 +36,18 @@ namespace mozilla {
class ErrorResult;
namespace dom {
class Blob;
class BlobImpl;
class DeviceStorageParams;
} // namespace dom
} // namespace mozilla
class nsDOMDeviceStorage;
class DeviceStorageCursorRequest;
//#define DS_LOGGING 1
#ifdef DS_LOGGING
// FIXME -- use MOZ_LOG and set to warn by default
#define DS_LOG_DEBUG(msg, ...) printf_stderr("[%s:%d] " msg "\n", __func__, __LINE__, ##__VA_ARGS__)
#define DS_LOG_INFO DS_LOG_DEBUG
#define DS_LOG_WARN DS_LOG_DEBUG
@ -62,20 +67,29 @@ class Blob;
#define POST_ERROR_EVENT_UNKNOWN "Unknown"
enum DeviceStorageRequestType {
DEVICE_STORAGE_REQUEST_READ,
DEVICE_STORAGE_REQUEST_WRITE,
DEVICE_STORAGE_REQUEST_APPEND,
DEVICE_STORAGE_REQUEST_CREATE,
DEVICE_STORAGE_REQUEST_DELETE,
DEVICE_STORAGE_REQUEST_WATCH,
DEVICE_STORAGE_REQUEST_FREE_SPACE,
DEVICE_STORAGE_REQUEST_USED_SPACE,
DEVICE_STORAGE_REQUEST_AVAILABLE,
DEVICE_STORAGE_REQUEST_STATUS,
DEVICE_STORAGE_REQUEST_FORMAT,
DEVICE_STORAGE_REQUEST_MOUNT,
DEVICE_STORAGE_REQUEST_UNMOUNT,
DEVICE_STORAGE_REQUEST_CREATEFD
DEVICE_STORAGE_REQUEST_READ,
DEVICE_STORAGE_REQUEST_WRITE,
DEVICE_STORAGE_REQUEST_APPEND,
DEVICE_STORAGE_REQUEST_CREATE,
DEVICE_STORAGE_REQUEST_DELETE,
DEVICE_STORAGE_REQUEST_WATCH,
DEVICE_STORAGE_REQUEST_FREE_SPACE,
DEVICE_STORAGE_REQUEST_USED_SPACE,
DEVICE_STORAGE_REQUEST_AVAILABLE,
DEVICE_STORAGE_REQUEST_STATUS,
DEVICE_STORAGE_REQUEST_FORMAT,
DEVICE_STORAGE_REQUEST_MOUNT,
DEVICE_STORAGE_REQUEST_UNMOUNT,
DEVICE_STORAGE_REQUEST_CREATEFD,
DEVICE_STORAGE_REQUEST_CURSOR
};
enum DeviceStorageAccessType {
DEVICE_STORAGE_ACCESS_READ,
DEVICE_STORAGE_ACCESS_WRITE,
DEVICE_STORAGE_ACCESS_CREATE,
DEVICE_STORAGE_ACCESS_UNDEFINED,
DEVICE_STORAGE_ACCESS_COUNT
};
class DeviceStorageUsedSpaceCache final
@ -176,14 +190,17 @@ public:
void InitFromBundle(nsIStringBundle* aBundle);
bool Check(const nsAString& aType, mozilla::dom::Blob* aBlob);
bool Check(const nsAString& aType, mozilla::dom::BlobImpl* aBlob);
bool Check(const nsAString& aType, nsIFile* aFile);
bool Check(const nsAString& aType, const nsString& aPath);
void GetTypeFromFile(nsIFile* aFile, nsAString& aType);
void GetTypeFromFileName(const nsAString& aFileName, nsAString& aType);
static nsresult GetPermissionForType(const nsAString& aType, nsACString& aPermissionResult);
static nsresult GetAccessForRequest(const DeviceStorageRequestType aRequestType, nsACString& aAccessResult);
static nsresult GetPermissionForType(const nsAString& aType,
nsACString& aPermissionResult);
static nsresult GetAccessForRequest(const DeviceStorageRequestType aRequestType,
nsACString& aAccessResult);
static nsresult GetAccessForIndex(size_t aAccessIndex, nsACString& aAccessResult);
static size_t GetAccessIndexForRequest(const DeviceStorageRequestType aRequestType);
static bool IsVolumeBased(const nsAString& aType);
static bool IsSharedMediaRoot(const nsAString& aType);
@ -195,64 +212,224 @@ private:
static mozilla::StaticAutoPtr<DeviceStorageTypeChecker> sDeviceStorageTypeChecker;
};
class ContinueCursorEvent final : public nsRunnable
{
public:
explicit ContinueCursorEvent(already_AddRefed<mozilla::dom::DOMRequest> aRequest);
explicit ContinueCursorEvent(mozilla::dom::DOMRequest* aRequest);
~ContinueCursorEvent();
void Continue();
NS_IMETHOD Run() override;
private:
already_AddRefed<DeviceStorageFile> GetNextFile();
nsRefPtr<mozilla::dom::DOMRequest> mRequest;
};
class nsDOMDeviceStorageCursor final
: public mozilla::dom::DOMCursor
, public nsIContentPermissionRequest
, public mozilla::dom::devicestorage::DeviceStorageRequestChildCallback
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSICONTENTPERMISSIONREQUEST
NS_FORWARD_NSIDOMDOMCURSOR(mozilla::dom::DOMCursor::)
// DOMCursor
virtual void Continue(mozilla::ErrorResult& aRv) override;
nsDOMDeviceStorageCursor(nsPIDOMWindow* aWindow,
nsIPrincipal* aPrincipal,
DeviceStorageFile* aFile,
PRTime aSince);
nsDOMDeviceStorageCursor(nsIGlobalObject* aGlobal,
DeviceStorageCursorRequest* aRequest);
void FireSuccess(JS::Handle<JS::Value> aResult);
void FireError(const nsString& aReason);
void FireDone();
private:
virtual ~nsDOMDeviceStorageCursor();
nsTArray<nsRefPtr<DeviceStorageFile> > mFiles;
bool mOkToCallContinue;
PRTime mSince;
nsRefPtr<DeviceStorageCursorRequest> mRequest;
};
class DeviceStorageRequestManager final
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DeviceStorageRequestManager)
static const uint32_t INVALID_ID = 0;
DeviceStorageRequestManager();
bool IsOwningThread();
nsresult DispatchToOwningThread(nsIRunnable* aRunnable);
void GetStorageType(nsAString & aType);
void StorePermission(size_t aAccess, bool aAllow);
uint32_t CheckPermission(size_t aAccess);
void RequestComplete() override;
/* These must be called on the owning thread context of the device
storage object. It will hold onto a device storage reference until
all of the pending requests are completed or shutdown is called. */
uint32_t Create(nsDOMDeviceStorage* aDeviceStorage,
mozilla::dom::DOMRequest** aRequest);
uint32_t Create(nsDOMDeviceStorage* aDeviceStorage,
DeviceStorageCursorRequest* aRequest,
nsDOMDeviceStorageCursor** aCursor);
/* These may be called from any thread context and post a request
to the owning thread to resolve the underlying DOMRequest or
DOMCursor. In order to trigger FireDone for a DOMCursor, one
should call Resolve with only the request ID. */
nsresult Resolve(uint32_t aId, bool aForceDispatch);
nsresult Resolve(uint32_t aId, const nsString& aValue, bool aForceDispatch);
nsresult Resolve(uint32_t aId, uint64_t aValue, bool aForceDispatch);
nsresult Resolve(uint32_t aId, DeviceStorageFile* aValue, bool aForceDispatch);
nsresult Resolve(uint32_t aId, mozilla::dom::BlobImpl* aValue, bool aForceDispatch);
nsresult Reject(uint32_t aId, const nsString& aReason);
nsresult Reject(uint32_t aId, const char* aReason);
void Shutdown();
private:
~nsDOMDeviceStorageCursor();
DeviceStorageRequestManager(const DeviceStorageRequestManager&) = delete;
DeviceStorageRequestManager& operator=(const DeviceStorageRequestManager&) = delete;
struct ListEntry {
nsRefPtr<mozilla::dom::DOMRequest> mRequest;
uint32_t mId;
bool mCursor;
};
typedef nsTArray<ListEntry> ListType;
typedef ListType::index_type ListIndex;
virtual ~DeviceStorageRequestManager();
uint32_t CreateInternal(mozilla::dom::DOMRequest* aRequest, bool aCursor);
nsresult ResolveInternal(ListIndex aIndex, JS::HandleValue aResult);
nsresult RejectInternal(ListIndex aIndex, const nsString& aReason);
nsresult DispatchOrAbandon(uint32_t aId, nsIRunnable* aRunnable);
ListType::index_type Find(uint32_t aId);
nsCOMPtr<nsIThread> mOwningThread;
ListType mPending; // owning thread or destructor only
mozilla::Mutex mMutex;
uint32_t mPermissionCache[DEVICE_STORAGE_ACCESS_COUNT];
bool mShutdown;
static mozilla::Atomic<uint32_t> sLastRequestId;
};
class DeviceStorageRequest
: public nsRunnable
{
protected:
DeviceStorageRequest();
public:
virtual void Initialize(DeviceStorageRequestManager* aManager,
DeviceStorageFile* aFile,
uint32_t aRequest);
virtual void Initialize(DeviceStorageRequestManager* aManager,
DeviceStorageFile* aFile,
uint32_t aRequest,
mozilla::dom::BlobImpl* aBlob);
virtual void Initialize(DeviceStorageRequestManager* aManager,
DeviceStorageFile* aFile,
uint32_t aRequest,
DeviceStorageFileDescriptor* aDSFileDescriptor);
DeviceStorageAccessType GetAccess() const;
void GetStorageType(nsAString& aType) const;
DeviceStorageFile* GetFile() const;
DeviceStorageFileDescriptor* GetFileDescriptor() const;
DeviceStorageRequestManager* GetManager() const;
uint32_t GetId() const
{
return mId;
}
void PermissionCacheMissed()
{
mPermissionCached = false;
}
nsresult Cancel();
nsresult Allow();
nsresult Resolve()
{
/* Always dispatch an empty resolve because that signals a cursor end
and should not be executed directly from the caller's context due
to the object potentially getting freed before we return. */
uint32_t id = mId;
mId = DeviceStorageRequestManager::INVALID_ID;
return mManager->Resolve(id, true);
}
template<class T>
nsresult Resolve(T aValue)
{
uint32_t id = mId;
if (!mMultipleResolve) {
mId = DeviceStorageRequestManager::INVALID_ID;
}
return mManager->Resolve(id, aValue, ForceDispatch());
}
template<class T>
nsresult Reject(T aReason)
{
uint32_t id = mId;
mId = DeviceStorageRequestManager::INVALID_ID;
return mManager->Reject(id, aReason);
}
protected:
bool ForceDispatch() const
{
return !mSendToParent && mPermissionCached;
}
virtual ~DeviceStorageRequest();
virtual void Prepare();
virtual nsresult CreateSendParams(mozilla::dom::DeviceStorageParams& aParams);
nsresult AllowInternal();
nsresult SendToParentProcess();
nsRefPtr<DeviceStorageRequestManager> mManager;
nsRefPtr<DeviceStorageFile> mFile;
nsCOMPtr<nsIPrincipal> mPrincipal;
nsCOMPtr<nsIContentPermissionRequester> mRequester;
uint32_t mId;
nsRefPtr<mozilla::dom::BlobImpl> mBlob;
nsRefPtr<DeviceStorageFileDescriptor> mDSFileDescriptor;
DeviceStorageAccessType mAccess;
bool mSendToParent;
bool mUseStreamTransport;
bool mCheckFile;
bool mCheckBlob;
bool mMultipleResolve;
bool mPermissionCached;
private:
DeviceStorageRequest(const DeviceStorageRequest&) = delete;
DeviceStorageRequest& operator=(const DeviceStorageRequest&) = delete;
};
//helpers
bool
StringToJsval(nsPIDOMWindow* aWindow, nsAString& aString,
JS::MutableHandle<JS::Value> result);
class DeviceStorageCursorRequest final
: public DeviceStorageRequest
{
public:
DeviceStorageCursorRequest();
using DeviceStorageRequest::Initialize;
virtual void Initialize(DeviceStorageRequestManager* aManager,
DeviceStorageFile* aFile,
uint32_t aRequest,
PRTime aSince);
void AddFiles(size_t aSize);
void AddFile(already_AddRefed<DeviceStorageFile> aFile);
nsresult Continue();
NS_IMETHOD Run() override;
protected:
virtual ~DeviceStorageCursorRequest()
{ };
JS::Value
nsIFileToJsval(nsPIDOMWindow* aWindow, DeviceStorageFile* aFile);
nsresult SendContinueToParentProcess();
nsresult CreateSendParams(mozilla::dom::DeviceStorageParams& aParams) override;
JS::Value
InterfaceToJsval(nsPIDOMWindow* aWindow, nsISupports* aObject, const nsIID* aIID);
size_t mIndex;
PRTime mSince;
nsString mStorageType;
nsTArray<nsRefPtr<DeviceStorageFile> > mFiles;
};
#endif

6
dom/ipc/ContentChild.cpp

@ -2298,11 +2298,7 @@ ContentChild::RecvAppInit()
// PreloadSlowThings() may set the docshell of the first TabChild
// inactive, and we can only safely restore it to active from
// BrowserElementChild.js.
if ((mIsForApp || mIsForBrowser)
#ifdef MOZ_NUWA_PROCESS
&& !IsNuwaProcess()
#endif
) {
if (mIsForApp || mIsForBrowser) {
PreloadSlowThings();
}

79
dom/ipc/TabChild.cpp

@ -23,6 +23,9 @@
#include "mozilla/plugins/PluginWidgetChild.h"
#include "mozilla/IMEStateManager.h"
#include "mozilla/ipc/DocumentRendererChild.h"
#ifdef MOZ_NUWA_PROCESS
#include "ipc/Nuwa.h"
#endif
#include "mozilla/ipc/FileDescriptorUtils.h"
#include "mozilla/layers/APZCCallbackHelper.h"
#include "mozilla/layers/APZCTreeManager.h"
@ -479,10 +482,67 @@ TabChild::FindTabChild(const TabId& aTabId)
return tabChild.forget();
}
static void
PreloadSlowThingsPostFork(void* aUnused)
{
nsCOMPtr<nsIObserverService> observerService =
mozilla::services::GetObserverService();
observerService->NotifyObservers(nullptr, "preload-postfork", nullptr);
}
#ifdef MOZ_NUWA_PROCESS
class MessageChannelAutoBlock MOZ_STACK_CLASS
{
public:
MessageChannelAutoBlock()
{
SetMessageChannelBlocked(true);
}
~MessageChannelAutoBlock()
{
SetMessageChannelBlocked(false);
}
private:
void SetMessageChannelBlocked(bool aBlock)
{
if (!IsNuwaProcess()) {
return;
}
mozilla::dom::ContentChild* content =
mozilla::dom::ContentChild::GetSingleton();
if (aBlock) {
content->GetIPCChannel()->Block();
} else {
content->GetIPCChannel()->Unblock();
}
nsTArray<IToplevelProtocol*> actors;
content->GetOpenedActors(actors);
for (size_t j = 0; j < actors.Length(); j++) {
IToplevelProtocol* actor = actors[j];
if (aBlock) {
actor->GetIPCChannel()->Block();
} else {
actor->GetIPCChannel()->Unblock();
}
}
}
};
#endif
static bool sPreloaded = false;
/*static*/ void
TabChild::PreloadSlowThings()
{
MOZ_ASSERT(!sPreallocatedTab);
if (sPreloaded) {
// If we are alredy initialized in Nuwa, don't redo preloading.
return;
}
sPreloaded = true;
// Pass nullptr to aManager since at this point the TabChild is
// not connected to any manager. Any attempt to use the TabChild
@ -494,6 +554,13 @@ TabChild::PreloadSlowThings()
!tab->InitTabChildGlobal(DONT_LOAD_SCRIPTS)) {
return;
}
#ifdef MOZ_NUWA_PROCESS
// Temporarily block the IPC channels to the chrome process when we are
// preloading.
MessageChannelAutoBlock autoblock;
#endif
// Just load and compile these scripts, but don't run them.
tab->TryCacheLoadAndCompileScript(BROWSER_ELEMENT_CHILD_SCRIPT, true);
// Load, compile, and run these scripts.
@ -501,6 +568,16 @@ TabChild::PreloadSlowThings()
NS_LITERAL_STRING("chrome://global/content/preload.js"),
true);
#ifdef MOZ_NUWA_PROCESS
if (IsNuwaProcess()) {
NuwaAddFinalConstructor(PreloadSlowThingsPostFork, nullptr);
} else {
PreloadSlowThingsPostFork(nullptr);
}
#else
PreloadSlowThingsPostFork(nullptr);
#endif
nsCOMPtr<nsIDocShell> docShell = do_GetInterface(tab->WebNavigation());
if (nsIPresShell* presShell = docShell->GetPresShell()) {
// Initialize and do an initial reflow of the about:blank

57
dom/ipc/preload.js

@ -9,6 +9,17 @@
const BrowserElementIsPreloaded = true;
const DoPreloadPostfork = function(aCallback) {
Services.obs.addObserver({
_callback: aCallback,
observe: function() {
this._callback();
Services.obs.removeObserver(this, "preload-postfork");
}
}, "preload-postfork", false);
};
(function (global) {
"use strict";
@ -16,7 +27,6 @@ const BrowserElementIsPreloaded = true;
let Cc = Components.classes;
let Ci = Components.interfaces;
Cu.import("resource://gre/modules/AppsServiceChild.jsm");
Cu.import("resource://gre/modules/AppsUtils.jsm");
Cu.import("resource://gre/modules/BrowserElementPromptService.jsm");
Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
@ -35,12 +45,10 @@ const BrowserElementIsPreloaded = true;
Cc["@mozilla.org/appshell/appShellService;1"].getService(Ci["nsIAppShellService"]);
Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci["nsIWindowMediator"]);
Cc["@mozilla.org/AppsService;1"].getService(Ci["nsIAppsService"]);
Cc["@mozilla.org/base/telemetry;1"].getService(Ci["nsITelemetry"]);
Cc["@mozilla.org/categorymanager;1"].getService(Ci["nsICategoryManager"]);
Cc["@mozilla.org/childprocessmessagemanager;1"].getService(Ci["nsIMessageSender"]);
Cc["@mozilla.org/consoleservice;1"].getService(Ci["nsIConsoleService"]);
Cc["@mozilla.org/cookieService;1"].getService(Ci["nsICookieService"]);
Cc["@mozilla.org/docshell/urifixup;1"].getService(Ci["nsIURIFixup"]);
Cc["@mozilla.org/dom/dom-request-service;1"].getService(Ci["nsIDOMRequestService"]);
Cc["@mozilla.org/embedcomp/prompt-service;1"].getService(Ci["nsIPromptService"]);
@ -58,14 +66,12 @@ const BrowserElementIsPreloaded = true;
Cc["@mozilla.org/network/idn-service;1"].getService(Ci["nsIIDNService"]);
Cc["@mozilla.org/network/io-service;1"].getService(Ci["nsIIOService2"]);
Cc["@mozilla.org/network/mime-hdrparam;1"].getService(Ci["nsIMIMEHeaderParam"]);
Cc["@mozilla.org/network/protocol-proxy-service;1"].getService(Ci["nsIProtocolProxyService"]);
Cc["@mozilla.org/network/socket-transport-service;1"].getService(Ci["nsISocketTransportService"]);
Cc["@mozilla.org/network/stream-transport-service;1"].getService(Ci["nsIStreamTransportService"]);
Cc["@mozilla.org/network/url-parser;1?auth=maybe"].getService(Ci["nsIURLParser"]);
Cc["@mozilla.org/network/url-parser;1?auth=no"].getService(Ci["nsIURLParser"]);
Cc["@mozilla.org/network/url-parser;1?auth=yes"].getService(Ci["nsIURLParser"]);
Cc["@mozilla.org/observer-service;1"].getService(Ci["nsIObserverService"]);
Cc["@mozilla.org/permissionmanager;1"].getService(Ci["nsIPermissionManager"]);
Cc["@mozilla.org/preferences-service;1"].getService(Ci["nsIPrefBranch"]);
Cc["@mozilla.org/scriptsecuritymanager;1"].getService(Ci["nsIScriptSecurityManager"]);
Cc["@mozilla.org/storage/service;1"].getService(Ci["mozIStorageService"]);
@ -108,7 +114,44 @@ const BrowserElementIsPreloaded = true;
Services.io.getProtocolHandler("app");
Services.io.getProtocolHandler("default");
docShell.isActive = false;
docShell.createAboutBlankContentViewer(null);
// Register an observer for topic "preload_postfork" after we fork a content
// process.
DoPreloadPostfork(function () {
// Load AppsServiceChild.jsm after fork since it sends an async message to
// the chrome process in its init() function.
Cu.import("resource://gre/modules/AppsServiceChild.jsm");
// Load UserCustomizations.jsm after fork since it sends an async message to
// the chrome process in its init() function.
try {
if (Services.prefs.getBoolPref("dom.apps.customization.enabled")) {
Cu.import("resource://gre/modules/UserCustomizations.jsm");
}
} catch(e) {}
// Load nsIAppsService after fork since its implementation loads
// AppsServiceChild.jsm
Cc["@mozilla.org/AppsService;1"].getService(Ci["nsIAppsService"]);
// Load nsICookieService after fork since it sends an IPC constructor
// message to the chrome process.
Cc["@mozilla.org/cookieService;1"].getService(Ci["nsICookieService"]);
// Load nsIPermissionManager after fork since it sends a message to the
// chrome process to read permissions.
Cc["@mozilla.org/permissionmanager;1"].getService(Ci["nsIPermissionManager"]);
// Create this instance after fork since it loads AppsServiceChild.jsm
Cc["@mozilla.org/webapps;1"].createInstance(Ci["nsISupports"]);
// Load nsIProtocolProxyService after fork since it asynchronously accesses
// the "Proxy Resolution" thread after it's frozen.
Cc["@mozilla.org/network/protocol-proxy-service;1"].getService(Ci["nsIProtocolProxyService"]);
// Call docShell.createAboutBlankContentViewer() after fork since it has IPC
// activity in the PCompositor protocol.
docShell.createAboutBlankContentViewer(null);
docShell.isActive = false;
});
})(this);

3
dom/webidl/DeviceStorage.webidl

@ -86,6 +86,9 @@ interface DeviceStorage : EventTarget {
// Indicates if the storage area denoted by storageName is removable
readonly attribute boolean isRemovable;
// True if the storage area is close to being full
readonly attribute boolean lowDiskSpace;
[NewObject]
// XXXbz what type does this really return?
Promise<any> getRoot();

10
ipc/glue/MessageChannel.h

@ -170,6 +170,16 @@ class MessageChannel : HasResultCodes
sIsPumpingMessages = aIsPumping;
}
#ifdef MOZ_NUWA_PROCESS
void Block() {
mLink->Block();
}
void Unblock() {
mLink->Unblock();
}
#endif
#ifdef OS_WIN
struct MOZ_STACK_CLASS SyncStackFrame
{

20
ipc/glue/MessageLink.cpp

@ -16,6 +16,10 @@
#include "mozilla/dom/PContent.h"
#include "mozilla/dom/PNuwa.h"
#include "mozilla/hal_sandbox/PHal.h"
#if defined(DEBUG) || defined(ENABLE_TESTS)
#include "jsprf.h"
extern "C" char* PrintJSStack();
#endif
#endif
#include "mozilla/Assertions.h"
@ -75,6 +79,7 @@ ProcessLink::ProcessLink(MessageChannel *aChan)
, mExistingListener(nullptr)
#ifdef MOZ_NUWA_PROCESS
, mIsToNuwaProcess(false)
, mIsBlocked(false)
#endif
{
}
@ -175,6 +180,8 @@ ProcessLink::SendMessage(Message *msg)
mChan->mMonitor->AssertCurrentThreadOwns();
#ifdef MOZ_NUWA_PROCESS
// Parent to child: check whether we are sending some unexpected message to
// the Nuwa process.
if (mIsToNuwaProcess && mozilla::dom::ContentParent::IsNuwaReady()) {
switch (msg->type()) {
case mozilla::dom::PNuwa::Msg_Fork__ID:
@ -194,6 +201,19 @@ ProcessLink::SendMessage(Message *msg)
#endif
}
}
// Nuwa to parent: check whether we are currently blocked.
if (IsNuwaProcess() && mIsBlocked) {
#if defined(ENABLE_TESTS) || defined(DEBUG)
char* jsstack = PrintJSStack();
printf_stderr("Fatal error: sending a message to the chrome process"
"with a blocked IPC channel from \n%s",
jsstack ? jsstack : "<no JS stack>");
JS_smprintf_free(jsstack);
MOZ_CRASH();
#endif
}
#endif
mIOLoop->PostTask(

16
ipc/glue/MessageLink.h

@ -128,6 +128,12 @@ class MessageLink
virtual bool Unsound_IsClosed() const = 0;
virtual uint32_t Unsound_NumQueuedMessages() const = 0;
#ifdef MOZ_NUWA_PROCESS
// To be overridden by ProcessLink.
virtual void Block() {}
virtual void Unblock() {}
#endif
protected:
MessageChannel *mChan;
};
@ -175,12 +181,22 @@ class ProcessLink
virtual bool Unsound_IsClosed() const override;
virtual uint32_t Unsound_NumQueuedMessages() const override;
#ifdef MOZ_NUWA_PROCESS
void Block() override {
mIsBlocked = true;
}
void Unblock() override {
mIsBlocked = false;
}
#endif
protected:
Transport* mTransport;
MessageLoop* mIOLoop; // thread where IO happens
Transport::Listener* mExistingListener; // channel's previous listener
#ifdef MOZ_NUWA_PROCESS
bool mIsToNuwaProcess;
bool mIsBlocked;
#endif
};

2
ipc/glue/ProtocolUtils.h

@ -239,6 +239,8 @@ public:
void GetOpenedActors(nsTArray<IToplevelProtocol*>& aActors);
virtual MessageChannel* GetIPCChannel() = 0;
// This Unsafe version should only be used when all other threads are
// frozen, since it performs no locking. It also takes a stack-allocated
// array and its size (number of elements) rather than an nsTArray. The Nuwa

24
mozglue/build/Nuwa.cpp

@ -1923,4 +1923,28 @@ IsNuwaReady() {
return sNuwaReady;
}
#if defined(DEBUG) || defined(ENABLE_TESTS)
MFBT_API void
NuwaAssertNotFrozen(unsigned int aThread, const char* aThreadName) {
if (!sIsNuwaProcess || !sIsFreezing) {
return;
}
thread_info_t *tinfo = GetThreadInfo(static_cast<pthread_t>(aThread));
if (!tinfo) {
return;
}
if ((tinfo->flags & TINFO_FLAG_NUWA_SUPPORT) &&
!(tinfo->flags & TINFO_FLAG_NUWA_EXPLICIT_CHECKPOINT)) {
__android_log_print(ANDROID_LOG_FATAL, "Nuwa",
"Fatal error: the Nuwa process is about to deadlock in "
"accessing a frozen thread (%s, tid=%d).",
aThreadName ? aThreadName : "(unnamed)",
tinfo->origNativeThreadID);
abort();
}
}
#endif
} // extern "C"

10
mozglue/build/Nuwa.h

@ -186,6 +186,16 @@ MFBT_API bool IsNuwaProcess();
* @return If the Nuwa process is ready for spawning new processes.
*/
MFBT_API bool IsNuwaReady();
#if defined(DEBUG) || defined(ENABLE_TESTS)
/**
* Asserts that aThread is not frozen.
*/
MFBT_API void NuwaAssertNotFrozen(unsigned int aThread,
const char* aThreadName);
#else
#define NuwaAssertNotFrozen(aThread, aThreadName) do {} while(0);
#endif
};
#endif /* __NUWA_H_ */

15
xpcom/threads/nsThread.cpp

@ -36,6 +36,15 @@
#include "mozilla/ChaosMode.h"
#include "mozilla/TimeStamp.h"
#ifdef MOZ_CRASHREPORTER
#include "nsServiceManagerUtils.h"
#include "nsICrashReporter.h"
#endif
#ifdef MOZ_NUWA_PROCESS
#include "private/pprthred.h"
#endif
#ifdef XP_LINUX
#include <sys/time.h>
#include <sys/resource.h>
@ -478,6 +487,12 @@ nsThread::PutEvent(already_AddRefed<nsIRunnable>&& aEvent, nsNestedEventTarget*
{
nsCOMPtr<nsIThreadObserver> obs;
#ifdef MOZ_NUWA_PROCESS
// On debug build or when tests are enabled, assert that we are not about to
// create a deadlock in the Nuwa process.
NuwaAssertNotFrozen(PR_GetThreadID(mThread), PR_GetThreadName(mThread));
#endif
{
MutexAutoLock lock(mLock);
nsChainedEventQueue* queue = aTarget ? aTarget->mQueue : &mEventsRoot;

Loading…
Cancel
Save