зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to fx-team a=merge
This commit is contained in:
Коммит
f85451e616
|
@ -61,6 +61,7 @@ this.EventManager.prototype = {
|
|||
this.addEventListener('wheel', this, true);
|
||||
this.addEventListener('scroll', this, true);
|
||||
this.addEventListener('resize', this, true);
|
||||
this._preDialogPosition = new WeakMap();
|
||||
}
|
||||
this.present(Presentation.tabStateChanged(null, 'newtab'));
|
||||
|
||||
|
@ -78,6 +79,7 @@ this.EventManager.prototype = {
|
|||
Logger.debug('EventManager.stop');
|
||||
AccessibilityEventObserver.removeListener(this);
|
||||
try {
|
||||
this._preDialogPosition.clear();
|
||||
this.webProgress.removeProgressListener(this);
|
||||
this.removeEventListener('wheel', this, true);
|
||||
this.removeEventListener('scroll', this, true);
|
||||
|
@ -272,8 +274,8 @@ this.EventManager.prototype = {
|
|||
// positioned inside it.
|
||||
break;
|
||||
}
|
||||
this.contentControl.autoMove(
|
||||
aEvent.accessible, { delay: 500 });
|
||||
this._preDialogPosition.set(aEvent.accessible.DOMNode, position);
|
||||
this.contentControl.autoMove(aEvent.accessible, { delay: 500 });
|
||||
break;
|
||||
}
|
||||
case Events.VALUE_CHANGE:
|
||||
|
@ -366,7 +368,8 @@ this.EventManager.prototype = {
|
|||
if (vc.position &&
|
||||
(Utils.getState(vc.position).contains(States.DEFUNCT) ||
|
||||
Utils.isInSubtree(vc.position, acc))) {
|
||||
let position = aEvent.targetPrevSibling || aEvent.targetParent;
|
||||
let position = this._preDialogPosition.get(aEvent.accessible.DOMNode) ||
|
||||
aEvent.targetPrevSibling || aEvent.targetParent;
|
||||
if (!position) {
|
||||
try {
|
||||
position = acc.previousSibling;
|
||||
|
|
|
@ -75,13 +75,13 @@
|
|||
<div>Phone status bar</div>
|
||||
<div id="windows">
|
||||
<button id="back">Back</button>
|
||||
<div id="appframe"></div>
|
||||
<div role="dialog" id="alert" hidden>
|
||||
<h1>This is an alert!</h1>
|
||||
<p>Do you agree?</p>
|
||||
<button onclick="hideAlert()">Yes</button>
|
||||
<button onclick="setTimeout(hideAlert, 500)">Yes</button>
|
||||
<button onclick="hideAlert()">No</button>
|
||||
</div>
|
||||
<div id="appframe"></div>
|
||||
</div>
|
||||
<button id="home">Home</button>
|
||||
</body>
|
||||
|
|
|
@ -179,16 +179,15 @@
|
|||
[ContentMessages.clearCursor, 'AccessFu:CursorCleared'],
|
||||
|
||||
// Open dialog in outer doc, while cursor is also in outer doc
|
||||
[ContentMessages.simpleMoveNext,
|
||||
new ExpectedCursorChange(['Phone status bar', 'Traversal Rule test document'])],
|
||||
[ContentMessages.simpleMoveLast,
|
||||
new ExpectedCursorChange(['Home', {'string': 'pushbutton'}])],
|
||||
[doc.defaultView.showAlert,
|
||||
new ExpectedCursorChange(['This is an alert!',
|
||||
{'string': 'headingLevel', 'args': [1]},
|
||||
{'string': 'dialog'}])],
|
||||
|
||||
[doc.defaultView.hideAlert,
|
||||
new ExpectedCursorChange(["wow",
|
||||
{"string": "headingLevel", "args": [1]}, "such app"])],
|
||||
new ExpectedCursorChange(['Home', {'string': 'pushbutton'}])],
|
||||
|
||||
[ContentMessages.clearCursor, 'AccessFu:CursorCleared'],
|
||||
|
||||
|
@ -204,8 +203,12 @@
|
|||
{'string': 'headingLevel', 'args': [1]},
|
||||
{'string': 'dialog'}])],
|
||||
|
||||
// XXX: Place cursor back where it was.
|
||||
[doc.defaultView.hideAlert,
|
||||
[ContentMessages.simpleMoveNext,
|
||||
new ExpectedCursorChange(['Do you agree?'])],
|
||||
[ContentMessages.simpleMoveNext,
|
||||
new ExpectedCursorChange(['Yes', {'string': 'pushbutton'}])],
|
||||
[ContentMessages.activateCurrent(),
|
||||
new ExpectedClickAction(),
|
||||
new ExpectedCursorChange(
|
||||
['wow', {'string': 'headingLevel', 'args': [1]}, 'such app'])],
|
||||
|
||||
|
|
|
@ -59,3 +59,9 @@
|
|||
<label id="pointerLock-cancel" value="&pointerLock.notification.message;"/>
|
||||
</popupnotificationcontent>
|
||||
</popupnotification>
|
||||
|
||||
#ifdef E10S_TESTING_ONLY
|
||||
<popupnotification id="enable-e10s-notification" hidden="true">
|
||||
<popupnotificationcontent orient="vertical"/>
|
||||
</popupnotification>
|
||||
#endif
|
||||
|
|
|
@ -107,6 +107,11 @@ XPCOMUtils.defineLazyModuleGetter(this, "SignInToWebsiteUX",
|
|||
XPCOMUtils.defineLazyModuleGetter(this, "ContentSearch",
|
||||
"resource:///modules/ContentSearch.jsm");
|
||||
|
||||
#ifdef E10S_TESTING_ONLY
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "UpdateChannel",
|
||||
"resource://gre/modules/UpdateChannel.jsm");
|
||||
#endif
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "ShellService", function() {
|
||||
try {
|
||||
return Cc["@mozilla.org/browser/shell-service;1"].
|
||||
|
@ -2261,12 +2266,15 @@ let DefaultBrowserCheck = {
|
|||
let E10SUINotification = {
|
||||
// Increase this number each time we want to roll out an
|
||||
// e10s testing period to Nightly users.
|
||||
CURRENT_NOTICE_COUNT: 0,
|
||||
CURRENT_NOTICE_COUNT: 1,
|
||||
CURRENT_PROMPT_PREF: "browser.displayedE10SPrompt.1",
|
||||
PREVIOUS_PROMPT_PREF: "browser.displayedE10SPrompt",
|
||||
|
||||
checkStatus: function() {
|
||||
let skipE10sChecks = false;
|
||||
try {
|
||||
skipE10sChecks = Services.prefs.getBoolPref("browser.tabs.remote.autostart.disabled-because-using-a11y");
|
||||
skipE10sChecks = (UpdateChannel.get() != "nightly") ||
|
||||
Services.prefs.getBoolPref("browser.tabs.remote.autostart.disabled-because-using-a11y");
|
||||
} catch(e) {}
|
||||
|
||||
if (skipE10sChecks) {
|
||||
|
@ -2312,17 +2320,26 @@ let E10SUINotification = {
|
|||
|
||||
let e10sPromptShownCount = 0;
|
||||
try {
|
||||
e10sPromptShownCount = Services.prefs.getIntPref("browser.displayedE10SPrompt");
|
||||
e10sPromptShownCount = Services.prefs.getIntPref(this.CURRENT_PROMPT_PREF);
|
||||
} catch(e) {}
|
||||
|
||||
let isHardwareAccelerated = true;
|
||||
try {
|
||||
let win = RecentWindow.getMostRecentBrowserWindow();
|
||||
let winutils = win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
|
||||
isHardwareAccelerated = winutils.layerManagerType != "Basic";
|
||||
} catch (e) {}
|
||||
|
||||
if (!Services.appinfo.inSafeMode &&
|
||||
!Services.appinfo.accessibilityEnabled &&
|
||||
!Services.appinfo.keyboardMayHaveIME &&
|
||||
isHardwareAccelerated &&
|
||||
e10sPromptShownCount < 5) {
|
||||
Services.tm.mainThread.dispatch(() => {
|
||||
try {
|
||||
this._showE10SPrompt();
|
||||
Services.prefs.setIntPref("browser.displayedE10SPrompt", e10sPromptShownCount + 1);
|
||||
Services.prefs.setIntPref(this.CURRENT_PROMPT_PREF, e10sPromptShownCount + 1);
|
||||
Services.prefs.clearUserPref(this.PREVIOUS_PROMPT_PREF);
|
||||
} catch (ex) {
|
||||
Cu.reportError("Failed to show e10s prompt: " + ex);
|
||||
}
|
||||
|
@ -2369,7 +2386,7 @@ let E10SUINotification = {
|
|||
|
||||
let browser = win.gBrowser.selectedBrowser;
|
||||
|
||||
let promptMessage = "Would you like to help us test multiprocess Nightly (e10s)? You can also enable e10s in Nightly preferences.";
|
||||
let promptMessage = "Would you like to help us test multiprocess Nightly (e10s)? You can also enable e10s in Nightly preferences. Notable fixes:";
|
||||
let mainAction = {
|
||||
label: "Enable and Restart",
|
||||
accessKey: "E",
|
||||
|
@ -2389,7 +2406,7 @@ let E10SUINotification = {
|
|||
label: "No thanks",
|
||||
accessKey: "N",
|
||||
callback: function () {
|
||||
Services.prefs.setIntPref("browser.displayedE10SPrompt", 5);
|
||||
Services.prefs.setIntPref(E10SUINotification.CURRENT_PROMPT_PREF, 5);
|
||||
}
|
||||
}
|
||||
];
|
||||
|
@ -2399,7 +2416,21 @@ let E10SUINotification = {
|
|||
persistWhileVisible: true
|
||||
};
|
||||
|
||||
win.PopupNotifications.show(browser, "enable_e10s", promptMessage, null, mainAction, secondaryActions, options);
|
||||
win.PopupNotifications.show(browser, "enable-e10s", promptMessage, null, mainAction, secondaryActions, options);
|
||||
|
||||
let highlights = [
|
||||
"Less crashing!",
|
||||
"Improved add-on compatibility and DevTools",
|
||||
"PDF.js, Web Console, Spellchecking, WebRTC now work"
|
||||
];
|
||||
|
||||
let doorhangerExtraContent = win.document.getElementById("enable-e10s-notification")
|
||||
.querySelector("popupnotificationcontent");
|
||||
for (let highlight of highlights) {
|
||||
let highlightLabel = win.document.createElement("label");
|
||||
highlightLabel.setAttribute("value", highlight);
|
||||
doorhangerExtraContent.appendChild(highlightLabel);
|
||||
}
|
||||
},
|
||||
|
||||
_warnedAboutAccessibility: false,
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
|
||||
#include "js/OldDebugAPI.h"
|
||||
#include "xpcprivate.h"
|
||||
#include "XPCWrapper.h"
|
||||
#include "nsIAppsService.h"
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#include "mozilla/dom/MessageEvent.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
|
||||
#include "js/OldDebugAPI.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsMimeTypes.h"
|
||||
#include "nsIPromptFactory.h"
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
|
||||
#include "jsapi.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "js/OldDebugAPI.h"
|
||||
#include "mozilla/DOMEventTargetHelper.h"
|
||||
#include "mozilla/net/WebSocketChannel.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#include "imgRequestProxy.h"
|
||||
#include "jsapi.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "js/OldDebugAPI.h"
|
||||
#include "js/Value.h"
|
||||
#include "Layers.h"
|
||||
#include "MediaDecoder.h"
|
||||
|
|
|
@ -545,6 +545,11 @@ public:
|
|||
|
||||
|
||||
bool IsEventAttributeName(nsIAtom* aName) MOZ_OVERRIDE;
|
||||
|
||||
// Returns the principal of the "top level" document; the origin displayed
|
||||
// in the URL bar of the browser window.
|
||||
already_AddRefed<nsIPrincipal> GetTopLevelPrincipal();
|
||||
|
||||
#endif // MOZ_EME
|
||||
|
||||
bool MozAutoplayEnabled() const
|
||||
|
|
|
@ -3407,6 +3407,11 @@ void HTMLMediaElement::NotifyDecoderPrincipalChanged()
|
|||
OutputMediaStream* ms = &mOutputStreams[i];
|
||||
ms->mStream->CombineWithPrincipal(principal);
|
||||
}
|
||||
#ifdef MOZ_EME
|
||||
if (mMediaKeys && NS_FAILED(mMediaKeys->CheckPrincipals())) {
|
||||
mMediaKeys->Shutdown();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void HTMLMediaElement::UpdateMediaSize(nsIntSize size)
|
||||
|
@ -4008,17 +4013,35 @@ HTMLMediaElement::SetMediaKeys(mozilla::dom::MediaKeys* aMediaKeys,
|
|||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
// TODO: Need to shutdown existing MediaKeys instance? bug 1016709.
|
||||
nsRefPtr<Promise> promise = Promise::Create(global, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
if (mMediaKeys != aMediaKeys) {
|
||||
if (mMediaKeys == aMediaKeys) {
|
||||
promise->MaybeResolve(JS::UndefinedHandleValue);
|
||||
return promise.forget();
|
||||
}
|
||||
if (aMediaKeys && aMediaKeys->IsBoundToMediaElement()) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_QUOTA_EXCEEDED_ERR);
|
||||
return promise.forget();
|
||||
}
|
||||
if (mMediaKeys) {
|
||||
// Existing MediaKeys object. Shut it down.
|
||||
mMediaKeys->Shutdown();
|
||||
mMediaKeys = nullptr;
|
||||
}
|
||||
|
||||
mMediaKeys = aMediaKeys;
|
||||
if (mMediaKeys) {
|
||||
if (NS_FAILED(mMediaKeys->Bind(this))) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
mMediaKeys = nullptr;
|
||||
return promise.forget();
|
||||
}
|
||||
if (mDecoder) {
|
||||
mDecoder->SetCDMProxy(mMediaKeys->GetCDMProxy());
|
||||
}
|
||||
}
|
||||
promise->MaybeResolve(JS::UndefinedHandleValue);
|
||||
return promise.forget();
|
||||
}
|
||||
|
@ -4063,6 +4086,28 @@ HTMLMediaElement::IsEventAttributeName(nsIAtom* aName)
|
|||
return aName == nsGkAtoms::onencrypted ||
|
||||
nsGenericHTMLElement::IsEventAttributeName(aName);
|
||||
}
|
||||
|
||||
already_AddRefed<nsIPrincipal>
|
||||
HTMLMediaElement::GetTopLevelPrincipal()
|
||||
{
|
||||
nsRefPtr<nsIPrincipal> principal;
|
||||
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(OwnerDoc()->GetParentObject());
|
||||
nsCOMPtr<nsIDOMWindow> topWindow;
|
||||
if (!window) {
|
||||
return nullptr;
|
||||
}
|
||||
window->GetTop(getter_AddRefs(topWindow));
|
||||
nsCOMPtr<nsPIDOMWindow> top = do_QueryInterface(topWindow);
|
||||
if (!top) {
|
||||
return nullptr;
|
||||
}
|
||||
nsIDocument* doc = top->GetExtantDoc();
|
||||
if (!doc) {
|
||||
return nullptr;
|
||||
}
|
||||
principal = doc->NodePrincipal();
|
||||
return principal.forget();
|
||||
}
|
||||
#endif // MOZ_EME
|
||||
|
||||
NS_IMETHODIMP HTMLMediaElement::WindowVolumeChanged()
|
||||
|
|
|
@ -11,7 +11,9 @@
|
|||
#include "ImageContainer.h"
|
||||
#include "SharedThreadPool.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
#include "mozilla/Base64.h"
|
||||
#include "nsIRandomGenerator.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include <stdint.h>
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -230,4 +232,42 @@ ExtractH264CodecDetails(const nsAString& aCodec,
|
|||
return true;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GenerateRandomPathName(nsCString& aOutSalt, uint32_t aLength)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIRandomGenerator> rg =
|
||||
do_GetService("@mozilla.org/security/random-generator;1", &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// For each three bytes of random data we will get four bytes of
|
||||
// ASCII. Request a bit more to be safe and truncate to the length
|
||||
// we want at the end.
|
||||
const uint32_t requiredBytesLength =
|
||||
static_cast<uint32_t>((aLength + 1) / 4 * 3);
|
||||
|
||||
uint8_t* buffer;
|
||||
rv = rg->GenerateRandomBytes(requiredBytesLength, &buffer);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsAutoCString temp;
|
||||
nsDependentCSubstring randomData(reinterpret_cast<const char*>(buffer),
|
||||
requiredBytesLength);
|
||||
rv = Base64Encode(randomData, temp);
|
||||
NS_Free(buffer);
|
||||
buffer = nullptr;
|
||||
if (NS_FAILED (rv)) return rv;
|
||||
|
||||
temp.Truncate(aLength);
|
||||
|
||||
// Base64 characters are alphanumeric (a-zA-Z0-9) and '+' and '/', so we need
|
||||
// to replace illegal characters -- notably '/'
|
||||
temp.ReplaceChar(FILE_PATH_SEPARATOR FILE_ILLEGAL_CHARACTERS, '_');
|
||||
|
||||
aOutSalt = temp;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
} // end namespace mozilla
|
||||
|
|
|
@ -257,6 +257,12 @@ ExtractH264CodecDetails(const nsAString& aCodecs,
|
|||
int16_t& aProfile,
|
||||
int16_t& aLevel);
|
||||
|
||||
// Use a cryptographic quality PRNG to generate raw random bytes
|
||||
// and convert that to a base64 string suitable for use as a file or URL
|
||||
// path. This is based on code from nsExternalAppHandler::SetUpTempFile.
|
||||
nsresult
|
||||
GenerateRandomPathName(nsCString& aOutSalt, uint32_t aLength);
|
||||
|
||||
} // end namespace mozilla
|
||||
|
||||
#endif
|
||||
|
|
|
@ -438,38 +438,11 @@ AndroidMediaResourceServer::AppendRandomPath(nsCString& aUrl)
|
|||
// and convert that to a base64 string for use as an URL path. This
|
||||
// is based on code from nsExternalAppHandler::SetUpTempFile.
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIRandomGenerator> rg =
|
||||
do_GetService("@mozilla.org/security/random-generator;1", &rv);
|
||||
nsAutoCString salt;
|
||||
rv = GenerateRandomPathName(salt, 16);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// For each three bytes of random data we will get four bytes of
|
||||
// ASCII. Request a bit more to be safe and truncate to the length
|
||||
// we want at the end.
|
||||
const uint32_t wantedFileNameLength = 16;
|
||||
const uint32_t requiredBytesLength =
|
||||
static_cast<uint32_t>((wantedFileNameLength + 1) / 4 * 3);
|
||||
|
||||
uint8_t* buffer;
|
||||
rv = rg->GenerateRandomBytes(requiredBytesLength, &buffer);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsAutoCString tempLeafName;
|
||||
nsDependentCSubstring randomData(reinterpret_cast<const char*>(buffer),
|
||||
requiredBytesLength);
|
||||
rv = Base64Encode(randomData, tempLeafName);
|
||||
NS_Free(buffer);
|
||||
buffer = nullptr;
|
||||
if (NS_FAILED (rv)) return rv;
|
||||
|
||||
tempLeafName.Truncate(wantedFileNameLength);
|
||||
|
||||
// Base64 characters are alphanumeric (a-zA-Z0-9) and '+' and '/', so we need
|
||||
// to replace illegal characters -- notably '/'
|
||||
tempLeafName.ReplaceChar(FILE_PATH_SEPARATOR FILE_ILLEGAL_CHARACTERS, '_');
|
||||
|
||||
aUrl += "/";
|
||||
aUrl += tempLeafName;
|
||||
|
||||
aUrl += salt;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -477,7 +450,7 @@ nsresult
|
|||
AndroidMediaResourceServer::AddResource(mozilla::MediaResource* aResource, nsCString& aUrl)
|
||||
{
|
||||
nsCString url = GetURLPrefix();
|
||||
nsresult rv = AppendRandomPath(url);
|
||||
nsresult rv = GenerateRandomPathName(url, 16);
|
||||
if (NS_FAILED (rv)) return rv;
|
||||
|
||||
{
|
||||
|
|
|
@ -36,18 +36,18 @@ CDMProxy::~CDMProxy()
|
|||
}
|
||||
|
||||
void
|
||||
CDMProxy::Init(PromiseId aPromiseId)
|
||||
CDMProxy::Init(PromiseId aPromiseId,
|
||||
const nsAString& aOrigin,
|
||||
const nsAString& aTopLevelOrigin,
|
||||
bool aInPrivateBrowsing)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
NS_ENSURE_TRUE_VOID(!mKeys.IsNull());
|
||||
|
||||
nsresult rv = mKeys->GetOrigin(mOrigin);
|
||||
if (NS_FAILED(rv)) {
|
||||
RejectPromise(aPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
EME_LOG("Creating CDMProxy for origin='%s'",
|
||||
NS_ConvertUTF16toUTF8(GetOrigin()).get());
|
||||
EME_LOG("CDMProxy::Init (%s, %s) %s",
|
||||
NS_ConvertUTF16toUTF8(aOrigin).get(),
|
||||
NS_ConvertUTF16toUTF8(aTopLevelOrigin).get(),
|
||||
(aInPrivateBrowsing ? "PrivateBrowsing" : "NonPrivateBrowsing"));
|
||||
|
||||
if (!mGMPThread) {
|
||||
nsCOMPtr<mozIGeckoMediaPluginService> mps =
|
||||
|
@ -62,8 +62,15 @@ CDMProxy::Init(PromiseId aPromiseId)
|
|||
return;
|
||||
}
|
||||
}
|
||||
|
||||
nsRefPtr<nsIRunnable> task(NS_NewRunnableMethodWithArg<uint32_t>(this, &CDMProxy::gmp_Init, aPromiseId));
|
||||
nsAutoPtr<InitData> data(new InitData());
|
||||
data->mPromiseId = aPromiseId;
|
||||
data->mOrigin = aOrigin;
|
||||
data->mTopLevelOrigin = aTopLevelOrigin;
|
||||
data->mInPrivateBrowsing = aInPrivateBrowsing;
|
||||
nsRefPtr<nsIRunnable> task(
|
||||
NS_NewRunnableMethodWithArg<nsAutoPtr<InitData>>(this,
|
||||
&CDMProxy::gmp_Init,
|
||||
data));
|
||||
mGMPThread->Dispatch(task, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
|
@ -76,26 +83,45 @@ CDMProxy::IsOnGMPThread()
|
|||
#endif
|
||||
|
||||
void
|
||||
CDMProxy::gmp_Init(uint32_t aPromiseId)
|
||||
CDMProxy::gmp_Init(nsAutoPtr<InitData> aData)
|
||||
{
|
||||
MOZ_ASSERT(IsOnGMPThread());
|
||||
|
||||
nsCOMPtr<mozIGeckoMediaPluginService> mps =
|
||||
do_GetService("@mozilla.org/gecko-media-plugin-service;1");
|
||||
if (!mps) {
|
||||
RejectPromise(aPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
RejectPromise(aData->mPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
nsresult rv = mps->GetNodeId(aData->mOrigin,
|
||||
aData->mTopLevelOrigin,
|
||||
aData->mInPrivateBrowsing,
|
||||
mNodeId);
|
||||
MOZ_ASSERT(!GetNodeId().IsEmpty());
|
||||
if (NS_FAILED(rv)) {
|
||||
RejectPromise(aData->mPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
EME_LOG("CDMProxy::gmp_Init (%s, %s) %s NodeId=%s",
|
||||
NS_ConvertUTF16toUTF8(aData->mOrigin).get(),
|
||||
NS_ConvertUTF16toUTF8(aData->mTopLevelOrigin).get(),
|
||||
(aData->mInPrivateBrowsing ? "PrivateBrowsing" : "NonPrivateBrowsing"),
|
||||
GetNodeId().get());
|
||||
|
||||
nsTArray<nsCString> tags;
|
||||
tags.AppendElement(NS_ConvertUTF16toUTF8(mKeySystem));
|
||||
nsresult rv = mps->GetGMPDecryptor(&tags, GetOrigin(), &mCDM);
|
||||
rv = mps->GetGMPDecryptor(&tags, GetNodeId(), &mCDM);
|
||||
if (NS_FAILED(rv) || !mCDM) {
|
||||
RejectPromise(aPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
RejectPromise(aData->mPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
} else {
|
||||
mCallback = new CDMCallbackProxy(this);
|
||||
mCDM->Init(mCallback);
|
||||
nsRefPtr<nsIRunnable> task(NS_NewRunnableMethodWithArg<uint32_t>(this, &CDMProxy::OnCDMCreated, aPromiseId));
|
||||
nsRefPtr<nsIRunnable> task(
|
||||
NS_NewRunnableMethodWithArg<uint32_t>(this,
|
||||
&CDMProxy::OnCDMCreated,
|
||||
aData->mPromiseId));
|
||||
NS_DispatchToMainThread(task);
|
||||
}
|
||||
}
|
||||
|
@ -107,7 +133,8 @@ CDMProxy::OnCDMCreated(uint32_t aPromiseId)
|
|||
if (mKeys.IsNull()) {
|
||||
return;
|
||||
}
|
||||
mKeys->OnCDMCreated(aPromiseId);
|
||||
MOZ_ASSERT(!GetNodeId().IsEmpty());
|
||||
mKeys->OnCDMCreated(aPromiseId, GetNodeId());
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -356,10 +383,10 @@ CDMProxy::ResolvePromise(PromiseId aId)
|
|||
}
|
||||
}
|
||||
|
||||
const nsAString&
|
||||
CDMProxy::GetOrigin() const
|
||||
const nsCString&
|
||||
CDMProxy::GetNodeId() const
|
||||
{
|
||||
return mOrigin;
|
||||
return mNodeId;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -48,7 +48,10 @@ public:
|
|||
// Main thread only.
|
||||
// Loads the CDM corresponding to mKeySystem.
|
||||
// Calls MediaKeys::OnCDMCreated() when the CDM is created.
|
||||
void Init(PromiseId aPromiseId);
|
||||
void Init(PromiseId aPromiseId,
|
||||
const nsAString& aOrigin,
|
||||
const nsAString& aTopLevelOrigin,
|
||||
bool aInPrivateBrowsing);
|
||||
|
||||
// Main thread only.
|
||||
// Uses the CDM to create a key session.
|
||||
|
@ -102,7 +105,7 @@ public:
|
|||
void Shutdown();
|
||||
|
||||
// Threadsafe.
|
||||
const nsAString& GetOrigin() const;
|
||||
const nsCString& GetNodeId() const;
|
||||
|
||||
// Main thread only.
|
||||
void OnResolveNewSessionPromise(uint32_t aPromiseId,
|
||||
|
@ -165,8 +168,15 @@ public:
|
|||
|
||||
private:
|
||||
|
||||
struct InitData {
|
||||
uint32_t mPromiseId;
|
||||
nsAutoString mOrigin;
|
||||
nsAutoString mTopLevelOrigin;
|
||||
bool mInPrivateBrowsing;
|
||||
};
|
||||
|
||||
// GMP thread only.
|
||||
void gmp_Init(uint32_t aPromiseId);
|
||||
void gmp_Init(nsAutoPtr<InitData> aData);
|
||||
|
||||
// GMP thread only.
|
||||
void gmp_Shutdown();
|
||||
|
@ -286,7 +296,7 @@ private:
|
|||
// EME plugin must come from this thread.
|
||||
nsRefPtr<nsIThread> mGMPThread;
|
||||
|
||||
nsAutoString mOrigin;
|
||||
nsCString mNodeId;
|
||||
|
||||
GMPDecryptorProxy* mCDM;
|
||||
CDMCaps mCapabilites;
|
||||
|
|
|
@ -25,6 +25,7 @@ namespace mozilla {
|
|||
namespace dom {
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(MediaKeys,
|
||||
mElement,
|
||||
mParent,
|
||||
mKeySessions,
|
||||
mPromises,
|
||||
|
@ -224,23 +225,85 @@ MediaKeys::Create(const GlobalObject& aGlobal,
|
|||
// CDMProxy keeps MediaKeys alive until it resolves the promise and thus
|
||||
// returns the MediaKeys object to JS.
|
||||
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
|
||||
if (!window) {
|
||||
if (!window || !window->GetExtantDoc()) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<MediaKeys> keys = new MediaKeys(window, aKeySystem);
|
||||
nsRefPtr<Promise> promise(keys->MakePromise(aRv));
|
||||
return keys->Init(aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
MediaKeys::Init(ErrorResult& aRv)
|
||||
{
|
||||
nsRefPtr<Promise> promise(MakePromise(aRv));
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!IsSupportedKeySystem(aKeySystem)) {
|
||||
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
return nullptr;
|
||||
if (!IsSupportedKeySystem(mKeySystem)) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
keys->mProxy = new CDMProxy(keys, aKeySystem);
|
||||
mProxy = new CDMProxy(this, mKeySystem);
|
||||
|
||||
// Determine principal (at creation time) of the MediaKeys object.
|
||||
nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(GetParentObject());
|
||||
if (!sop) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return promise.forget();
|
||||
}
|
||||
mPrincipal = sop->GetPrincipal();
|
||||
|
||||
// Determine principal of the "top-level" window; the principal of the
|
||||
// page that will display in the URL bar.
|
||||
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(GetParentObject());
|
||||
if (!window) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return promise.forget();
|
||||
}
|
||||
nsCOMPtr<nsIDOMWindow> topWindow;
|
||||
window->GetTop(getter_AddRefs(topWindow));
|
||||
nsCOMPtr<nsPIDOMWindow> top = do_QueryInterface(topWindow);
|
||||
if (!top || !top->GetExtantDoc()) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
mTopLevelPrincipal = top->GetExtantDoc()->NodePrincipal();
|
||||
|
||||
if (!mPrincipal || !mTopLevelPrincipal) {
|
||||
NS_WARNING("Failed to get principals when creating MediaKeys");
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
nsAutoString origin;
|
||||
nsresult rv = nsContentUtils::GetUTFOrigin(mPrincipal, origin);
|
||||
if (NS_FAILED(rv)) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return promise.forget();
|
||||
}
|
||||
nsAutoString topLevelOrigin;
|
||||
rv = nsContentUtils::GetUTFOrigin(mTopLevelPrincipal, topLevelOrigin);
|
||||
if (NS_FAILED(rv)) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
if (!window) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return promise.forget();
|
||||
}
|
||||
nsIDocument* doc = window->GetExtantDoc();
|
||||
const bool inPrivateBrowsing = nsContentUtils::IsInPrivateBrowsing(doc);
|
||||
|
||||
EME_LOG("MediaKeys::Create() (%s, %s), %s",
|
||||
NS_ConvertUTF16toUTF8(origin).get(),
|
||||
NS_ConvertUTF16toUTF8(topLevelOrigin).get(),
|
||||
(inPrivateBrowsing ? "PrivateBrowsing" : "NonPrivateBrowsing"));
|
||||
|
||||
// The CDMProxy's initialization is asynchronous. The MediaKeys is
|
||||
// refcounted, and its instance is returned to JS by promise once
|
||||
|
@ -250,22 +313,26 @@ MediaKeys::Create(const GlobalObject& aGlobal,
|
|||
// or its creation has failed. Store the id of the promise returned
|
||||
// here, and hold a self-reference until that promise is resolved or
|
||||
// rejected.
|
||||
MOZ_ASSERT(!keys->mCreatePromiseId, "Should only be created once!");
|
||||
keys->mCreatePromiseId = keys->StorePromise(promise);
|
||||
keys->AddRef();
|
||||
keys->mProxy->Init(keys->mCreatePromiseId);
|
||||
MOZ_ASSERT(!mCreatePromiseId, "Should only be created once!");
|
||||
mCreatePromiseId = StorePromise(promise);
|
||||
AddRef();
|
||||
mProxy->Init(mCreatePromiseId,
|
||||
origin,
|
||||
topLevelOrigin,
|
||||
inPrivateBrowsing);
|
||||
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
void
|
||||
MediaKeys::OnCDMCreated(PromiseId aId)
|
||||
MediaKeys::OnCDMCreated(PromiseId aId, const nsACString& aNodeId)
|
||||
{
|
||||
nsRefPtr<Promise> promise(RetrievePromise(aId));
|
||||
if (!promise) {
|
||||
NS_WARNING("MediaKeys tried to resolve a non-existent promise");
|
||||
return;
|
||||
}
|
||||
mNodeId = aNodeId;
|
||||
nsRefPtr<MediaKeys> keys(this);
|
||||
promise->MaybeResolve(keys);
|
||||
if (mCreatePromiseId == aId) {
|
||||
|
@ -366,26 +433,58 @@ MediaKeys::GetSession(const nsAString& aSessionId)
|
|||
return session.forget();
|
||||
}
|
||||
|
||||
nsresult
|
||||
MediaKeys::GetOrigin(nsString& aOutOrigin)
|
||||
const nsCString&
|
||||
MediaKeys::GetNodeId() const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
// TODO: Bug 1035637, return a combination of origin and URL bar origin.
|
||||
return mNodeId;
|
||||
}
|
||||
|
||||
nsIPrincipal* principal = nullptr;
|
||||
nsCOMPtr<nsPIDOMWindow> pWindow = do_QueryInterface(GetParentObject());
|
||||
nsCOMPtr<nsIScriptObjectPrincipal> scriptPrincipal =
|
||||
do_QueryInterface(pWindow);
|
||||
if (scriptPrincipal) {
|
||||
principal = scriptPrincipal->GetPrincipal();
|
||||
bool
|
||||
MediaKeys::IsBoundToMediaElement() const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
return mElement != nullptr;
|
||||
}
|
||||
|
||||
nsresult
|
||||
MediaKeys::Bind(HTMLMediaElement* aElement)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (IsBoundToMediaElement()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
NS_ENSURE_TRUE(principal, NS_ERROR_FAILURE);
|
||||
|
||||
nsresult res = nsContentUtils::GetUTFOrigin(principal, aOutOrigin);
|
||||
mElement = aElement;
|
||||
nsresult rv = CheckPrincipals();
|
||||
if (NS_FAILED(rv)) {
|
||||
mElement = nullptr;
|
||||
return rv;
|
||||
}
|
||||
|
||||
EME_LOG("EME Origin = '%s'", NS_ConvertUTF16toUTF8(aOutOrigin).get());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return res;
|
||||
nsresult
|
||||
MediaKeys::CheckPrincipals()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (!IsBoundToMediaElement()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsRefPtr<nsIPrincipal> elementPrincipal(mElement->GetCurrentPrincipal());
|
||||
nsRefPtr<nsIPrincipal> elementTopLevelPrincipal(mElement->GetTopLevelPrincipal());
|
||||
if (!elementPrincipal ||
|
||||
!mPrincipal ||
|
||||
!elementPrincipal->Equals(mPrincipal) ||
|
||||
!elementTopLevelPrincipal ||
|
||||
!mTopLevelPrincipal ||
|
||||
!elementTopLevelPrincipal->Equals(mTopLevelPrincipal)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/MediaKeysBinding.h"
|
||||
#include "mozilla/dom/UnionTypes.h"
|
||||
#include "mozIGeckoMediaPluginService.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -26,6 +27,7 @@ class CDMProxy;
|
|||
namespace dom {
|
||||
|
||||
class MediaKeySession;
|
||||
class HTMLMediaElement;
|
||||
|
||||
typedef nsRefPtrHashtable<nsStringHashKey, MediaKeySession> KeySessionHashMap;
|
||||
typedef nsRefPtrHashtable<nsUint32HashKey, dom::Promise> PromiseHashMap;
|
||||
|
@ -55,6 +57,8 @@ public:
|
|||
|
||||
virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
|
||||
|
||||
nsresult Bind(HTMLMediaElement* aElement);
|
||||
|
||||
// Javascript: readonly attribute DOMString keySystem;
|
||||
void GetKeySystem(nsString& retval) const;
|
||||
|
||||
|
@ -82,7 +86,7 @@ public:
|
|||
already_AddRefed<MediaKeySession> GetSession(const nsAString& aSessionId);
|
||||
|
||||
// Called once a Create() operation succeeds.
|
||||
void OnCDMCreated(PromiseId aId);
|
||||
void OnCDMCreated(PromiseId aId, const nsACString& aNodeId);
|
||||
// Called when GenerateRequest or Load have been called on a MediaKeySession
|
||||
// and we are waiting for its initialisation to finish.
|
||||
void OnSessionPending(PromiseId aId, MediaKeySession* aSession);
|
||||
|
@ -107,12 +111,22 @@ public:
|
|||
// Resolves promise with "undefined".
|
||||
void ResolvePromise(PromiseId aId);
|
||||
|
||||
nsresult GetOrigin(nsString& aOutOrigin);
|
||||
const nsCString& GetNodeId() const;
|
||||
|
||||
void Shutdown();
|
||||
|
||||
// Returns true if this MediaKeys has been bound to a media element.
|
||||
bool IsBoundToMediaElement() const;
|
||||
|
||||
// Return NS_OK if the principals are the same as when the MediaKeys
|
||||
// was created, failure otherwise.
|
||||
nsresult CheckPrincipals();
|
||||
|
||||
private:
|
||||
|
||||
bool IsInPrivateBrowsing();
|
||||
already_AddRefed<Promise> Init(ErrorResult& aRv);
|
||||
|
||||
// Removes promise from mPromises, and returns it.
|
||||
already_AddRefed<Promise> RetrievePromise(PromiseId aId);
|
||||
|
||||
|
@ -120,12 +134,19 @@ private:
|
|||
// and the MediaKeys destructor clears the proxy's reference to the MediaKeys.
|
||||
nsRefPtr<CDMProxy> mProxy;
|
||||
|
||||
nsRefPtr<HTMLMediaElement> mElement;
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> mParent;
|
||||
nsString mKeySystem;
|
||||
nsCString mNodeId;
|
||||
KeySessionHashMap mKeySessions;
|
||||
PromiseHashMap mPromises;
|
||||
PendingKeySessionsHashMap mPendingSessions;
|
||||
PromiseId mCreatePromiseId;
|
||||
|
||||
nsRefPtr<nsIPrincipal> mPrincipal;
|
||||
nsRefPtr<nsIPrincipal> mTopLevelPrincipal;
|
||||
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -242,7 +242,7 @@ EMEAudioDecoder::GmpInit()
|
|||
tags.AppendElement(NS_LITERAL_CSTRING("aac"));
|
||||
tags.AppendElement(NS_ConvertUTF16toUTF8(mProxy->KeySystem()));
|
||||
nsresult rv = mMPS->GetGMPAudioDecoder(&tags,
|
||||
mProxy->GetOrigin(),
|
||||
mProxy->GetNodeId(),
|
||||
&mGMP);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
MOZ_ASSERT(mGMP);
|
||||
|
|
|
@ -233,7 +233,7 @@ EMEH264Decoder::GmpInit()
|
|||
tags.AppendElement(NS_LITERAL_CSTRING("h264"));
|
||||
tags.AppendElement(NS_ConvertUTF16toUTF8(mProxy->KeySystem()));
|
||||
nsresult rv = mMPS->GetGMPVideoDecoder(&tags,
|
||||
mProxy->GetOrigin(),
|
||||
mProxy->GetNodeId(),
|
||||
&mHost,
|
||||
&mGMP);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
|
|
@ -29,6 +29,21 @@ using mozilla::dom::CrashReporterChild;
|
|||
#include <unistd.h> // for _exit()
|
||||
#endif
|
||||
|
||||
#if defined(XP_WIN)
|
||||
// In order to provide EME plugins with a "device binding" capability,
|
||||
// in the parent we generate and store some random bytes as salt for every
|
||||
// (origin, urlBarOrigin) pair that uses EME. We store these bytes so
|
||||
// that every time we revisit the same origin we get the same salt.
|
||||
// We send this salt to the child on startup. The child collects some
|
||||
// device specific data and munges that with the salt to create the
|
||||
// "node id" that we expose to EME plugins. It then overwrites the device
|
||||
// specific data, and activates the sandbox.
|
||||
#define HASH_NODE_ID_WITH_DEVICE_ID 1
|
||||
#include "rlz/lib/machine_id.h"
|
||||
#include "rlz/lib/string_utils.h"
|
||||
#include "mozilla/SHA1.h"
|
||||
#endif
|
||||
|
||||
#if defined(MOZ_SANDBOX) && defined(XP_WIN)
|
||||
#define TARGET_SANDBOX_EXPORTS
|
||||
#include "mozilla/sandboxTarget.h"
|
||||
|
@ -268,20 +283,58 @@ GMPChild::Init(const std::string& aPluginPath,
|
|||
SendPCrashReporterConstructor(CrashReporter::CurrentThreadId());
|
||||
#endif
|
||||
|
||||
#if defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
|
||||
mPluginPath = aPluginPath;
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
GMPChild::RecvSetNodeId(const nsCString& aNodeId)
|
||||
{
|
||||
#ifdef HASH_NODE_ID_WITH_DEVICE_ID
|
||||
if (!aNodeId.IsEmpty() && !aNodeId.EqualsLiteral("null")) {
|
||||
string16 deviceId;
|
||||
int volumeId;
|
||||
if (!rlz_lib::GetRawMachineId(&deviceId, &volumeId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: Switch to SHA256.
|
||||
mozilla::SHA1Sum hash;
|
||||
hash.update(deviceId.c_str(), deviceId.size() * sizeof(string16::value_type));
|
||||
hash.update(aNodeId.get(), aNodeId.Length());
|
||||
hash.update(&volumeId, sizeof(int));
|
||||
uint8_t digest[mozilla::SHA1Sum::kHashSize];
|
||||
hash.finish(digest);
|
||||
if (!rlz_lib::BytesToString(digest, mozilla::SHA1Sum::kHashSize, &mNodeId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Overwrite device id as it could potentially identify the user, so
|
||||
// there's no chance a GMP can read it and use it for identity tracking.
|
||||
volumeId = 0;
|
||||
memset(&deviceId.front(), '*', sizeof(string16::value_type) * deviceId.size());
|
||||
deviceId = L"";
|
||||
} else {
|
||||
mNodeId = "null";
|
||||
}
|
||||
#else
|
||||
mNodeId = std::string(aNodeId.BeginReading(), aNodeId.EndReading());
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GMPChild::RecvStartPlugin()
|
||||
{
|
||||
#ifdef XP_WIN
|
||||
PreLoadLibraries(aPluginPath);
|
||||
PreLoadLibraries(mPluginPath);
|
||||
#endif
|
||||
|
||||
#if defined(MOZ_SANDBOX) && defined(XP_WIN)
|
||||
mozilla::SandboxTarget::Instance()->StartSandbox();
|
||||
#endif
|
||||
|
||||
return LoadPluginLibrary(aPluginPath);
|
||||
return LoadPluginLibrary(mPluginPath);
|
||||
}
|
||||
|
||||
#ifdef XP_WIN
|
||||
|
@ -499,7 +552,7 @@ GMPChild::DeallocPGMPVideoDecoderChild(PGMPVideoDecoderChild* aActor)
|
|||
PGMPDecryptorChild*
|
||||
GMPChild::AllocPGMPDecryptorChild()
|
||||
{
|
||||
GMPDecryptorChild* actor = new GMPDecryptorChild(this);
|
||||
GMPDecryptorChild* actor = new GMPDecryptorChild(this, mNodeId);
|
||||
actor->AddRef();
|
||||
return actor;
|
||||
}
|
||||
|
|
|
@ -50,6 +50,10 @@ public:
|
|||
void ShutdownComplete() MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
|
||||
virtual bool RecvSetNodeId(const nsCString& aNodeId) MOZ_OVERRIDE;
|
||||
virtual bool RecvStartPlugin() MOZ_OVERRIDE;
|
||||
|
||||
virtual PCrashReporterChild* AllocPCrashReporterChild(const NativeThreadId& aThread) MOZ_OVERRIDE;
|
||||
virtual bool DeallocPCrashReporterChild(PCrashReporterChild*) MOZ_OVERRIDE;
|
||||
|
||||
|
@ -88,10 +92,11 @@ private:
|
|||
PRLibrary* mLib;
|
||||
GMPGetAPIFunc mGetAPIFunc;
|
||||
MessageLoop* mGMPMessageLoop;
|
||||
#if defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
|
||||
std::string mPluginPath;
|
||||
#if defined(XP_MACOSX) && defined(MOZ_GMP_SANDBOX)
|
||||
nsCString mPluginBinaryPath;
|
||||
#endif
|
||||
std::string mNodeId;
|
||||
};
|
||||
|
||||
} // namespace gmp
|
||||
|
|
|
@ -26,9 +26,10 @@
|
|||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
||||
GMPDecryptorChild::GMPDecryptorChild(GMPChild* aPlugin)
|
||||
GMPDecryptorChild::GMPDecryptorChild(GMPChild* aPlugin, const std::string& aNodeId)
|
||||
: mSession(nullptr)
|
||||
, mPlugin(aPlugin)
|
||||
, mNodeId(aNodeId)
|
||||
{
|
||||
MOZ_ASSERT(mPlugin);
|
||||
}
|
||||
|
@ -176,9 +177,8 @@ void
|
|||
GMPDecryptorChild::GetNodeId(const char** aOutNodeId,
|
||||
uint32_t* aOutNodeIdLength)
|
||||
{
|
||||
static const char* id = "placeholder_node_id";
|
||||
*aOutNodeId = id;
|
||||
*aOutNodeIdLength = strlen(id);
|
||||
*aOutNodeId = mNodeId.c_str();
|
||||
*aOutNodeIdLength = mNodeId.size();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "gmp-decryption.h"
|
||||
#include "mozilla/gmp/GMPTypes.h"
|
||||
#include "GMPEncryptedBufferDataImpl.h"
|
||||
#include <string>
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
@ -23,7 +24,7 @@ class GMPDecryptorChild : public GMPDecryptorCallback
|
|||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GMPDecryptorChild);
|
||||
|
||||
explicit GMPDecryptorChild(GMPChild* aPlugin);
|
||||
explicit GMPDecryptorChild(GMPChild* aPlugin, const std::string& aNodeId);
|
||||
|
||||
void Init(GMPDecryptor* aSession);
|
||||
|
||||
|
@ -122,6 +123,8 @@ private:
|
|||
// Only call into this on the (GMP process) main thread.
|
||||
GMPDecryptor* mSession;
|
||||
GMPChild* mPlugin;
|
||||
|
||||
const std::string mNodeId;
|
||||
};
|
||||
|
||||
} // namespace gmp
|
||||
|
|
|
@ -150,6 +150,22 @@ GMPParent::LoadProcess()
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
LOGD(("%s::%s: Created new process %p", __CLASS__, __FUNCTION__, (void *)mProcess));
|
||||
|
||||
bool ok = SendSetNodeId(mNodeId);
|
||||
if (!ok) {
|
||||
mProcess->Delete();
|
||||
mProcess = nullptr;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
LOGD(("%s::%s: Failed to send node id %p", __CLASS__, __FUNCTION__, (void *)mProcess));
|
||||
|
||||
ok = SendStartPlugin();
|
||||
if (!ok) {
|
||||
mProcess->Delete();
|
||||
mProcess = nullptr;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
LOGD(("%s::%s: Failed to send start %p", __CLASS__, __FUNCTION__, (void *)mProcess));
|
||||
}
|
||||
|
||||
mState = GMPStateLoaded;
|
||||
|
@ -680,7 +696,7 @@ GMPParent::DeallocPGMPAudioDecoderParent(PGMPAudioDecoderParent* aActor)
|
|||
PGMPStorageParent*
|
||||
GMPParent::AllocPGMPStorageParent()
|
||||
{
|
||||
GMPStorageParent* p = new GMPStorageParent(mOrigin, this);
|
||||
GMPStorageParent* p = new GMPStorageParent(mNodeId, this);
|
||||
mStorage.AppendElement(p); // Addrefs, released in DeallocPGMPStorageParent.
|
||||
return p;
|
||||
}
|
||||
|
@ -695,8 +711,12 @@ GMPParent::DeallocPGMPStorageParent(PGMPStorageParent* aActor)
|
|||
}
|
||||
|
||||
bool
|
||||
GMPParent::RecvPGMPStorageConstructor(PGMPStorageParent* actor)
|
||||
GMPParent::RecvPGMPStorageConstructor(PGMPStorageParent* aActor)
|
||||
{
|
||||
GMPStorageParent* p = (GMPStorageParent*)aActor;
|
||||
if (NS_WARN_IF(NS_FAILED(p->Init()))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -877,24 +897,24 @@ GMPParent::ReadGMPMetaData()
|
|||
}
|
||||
|
||||
bool
|
||||
GMPParent::CanBeSharedCrossOrigin() const
|
||||
GMPParent::CanBeSharedCrossNodeIds() const
|
||||
{
|
||||
return mOrigin.IsEmpty();
|
||||
return mNodeId.IsEmpty();
|
||||
}
|
||||
|
||||
bool
|
||||
GMPParent::CanBeUsedFrom(const nsAString& aOrigin) const
|
||||
GMPParent::CanBeUsedFrom(const nsACString& aNodeId) const
|
||||
{
|
||||
return (mOrigin.IsEmpty() && State() == GMPStateNotLoaded) ||
|
||||
mOrigin.Equals(aOrigin);
|
||||
return (mNodeId.IsEmpty() && State() == GMPStateNotLoaded) ||
|
||||
mNodeId == aNodeId;
|
||||
}
|
||||
|
||||
void
|
||||
GMPParent::SetOrigin(const nsAString& aOrigin)
|
||||
GMPParent::SetNodeId(const nsACString& aNodeId)
|
||||
{
|
||||
MOZ_ASSERT(!aOrigin.IsEmpty());
|
||||
MOZ_ASSERT(CanBeUsedFrom(aOrigin));
|
||||
mOrigin = aOrigin;
|
||||
MOZ_ASSERT(!aNodeId.IsEmpty());
|
||||
MOZ_ASSERT(CanBeUsedFrom(aNodeId));
|
||||
mNodeId = aNodeId;
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -99,26 +99,28 @@ public:
|
|||
GMPState State() const;
|
||||
nsIThread* GMPThread();
|
||||
|
||||
// A GMP can either be a single instance shared across all origins (like
|
||||
// A GMP can either be a single instance shared across all NodeIds (like
|
||||
// in the OpenH264 case), or we can require a new plugin instance for every
|
||||
// origin running the plugin (as in the EME plugin case).
|
||||
// NodeIds running the plugin (as in the EME plugin case).
|
||||
//
|
||||
// Plugins are associated with an origin by calling SetOrigin() before
|
||||
// A NodeId is a hash of the ($urlBarOrigin, $ownerDocOrigin) pair.
|
||||
//
|
||||
// Plugins are associated with an NodeIds by calling SetNodeId() before
|
||||
// loading.
|
||||
//
|
||||
// If a plugin has no origin specified and it is loaded, it is assumed to
|
||||
// be shared across origins.
|
||||
// If a plugin has no NodeId specified and it is loaded, it is assumed to
|
||||
// be shared across NodeIds.
|
||||
|
||||
// Specifies that a GMP can only work with the specified origin.
|
||||
void SetOrigin(const nsAString& aOrigin);
|
||||
// Specifies that a GMP can only work with the specified NodeIds.
|
||||
void SetNodeId(const nsACString& aNodeId);
|
||||
|
||||
// Returns true if a plugin can be or is being used across multiple origins.
|
||||
bool CanBeSharedCrossOrigin() const;
|
||||
// Returns true if a plugin can be or is being used across multiple NodeIds.
|
||||
bool CanBeSharedCrossNodeIds() const;
|
||||
|
||||
// A GMP can be used from an origin if it's already been set to work with
|
||||
// that origin, or if it's not been set to work with any origin and has
|
||||
// not yet been loaded (i.e. it's not shared across origins).
|
||||
bool CanBeUsedFrom(const nsAString& aOrigin) const;
|
||||
// A GMP can be used from a NodeId if it's already been set to work with
|
||||
// that NodeId, or if it's not been set to work with any NodeId and has
|
||||
// not yet been loaded (i.e. it's not shared across NodeIds).
|
||||
bool CanBeUsedFrom(const nsACString& aNodeId) const;
|
||||
|
||||
already_AddRefed<nsIFile> GetDirectory() {
|
||||
return nsCOMPtr<nsIFile>(mDirectory).forget();
|
||||
|
@ -184,9 +186,9 @@ private:
|
|||
nsTArray<nsRefPtr<GMPTimerParent>> mTimers;
|
||||
nsTArray<nsRefPtr<GMPStorageParent>> mStorage;
|
||||
nsCOMPtr<nsIThread> mGMPThread;
|
||||
// Origin the plugin is assigned to, or empty if the the plugin is not
|
||||
// assigned to an origin.
|
||||
nsAutoString mOrigin;
|
||||
// NodeId the plugin is assigned to, or empty if the the plugin is not
|
||||
// assigned to a NodeId.
|
||||
nsAutoCString mNodeId;
|
||||
|
||||
bool mAsyncShutdownRequired;
|
||||
bool mAsyncShutdownInProgress;
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "GMPService.h"
|
||||
#include "prio.h"
|
||||
#include "prlog.h"
|
||||
#include "GMPParent.h"
|
||||
#include "GMPVideoDecoderParent.h"
|
||||
|
@ -22,9 +23,15 @@
|
|||
#include "nsComponentManagerUtils.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "runnable_utils.h"
|
||||
#include "VideoUtils.h"
|
||||
#if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
|
||||
#include "mozilla/Sandbox.h"
|
||||
#endif
|
||||
#include "nsAppDirectoryServiceDefs.h"
|
||||
#include "nsDirectoryServiceUtils.h"
|
||||
#include "nsDirectoryServiceDefs.h"
|
||||
#include "nsHashKeys.h"
|
||||
#include "nsIFile.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -154,7 +161,7 @@ GeckoMediaPluginService::~GeckoMediaPluginService()
|
|||
MOZ_ASSERT(mAsyncShutdownPlugins.IsEmpty());
|
||||
}
|
||||
|
||||
void
|
||||
nsresult
|
||||
GeckoMediaPluginService::Init()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
@ -163,15 +170,37 @@ GeckoMediaPluginService::Init()
|
|||
MOZ_ASSERT(obsService);
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(obsService->AddObserver(this, "profile-change-teardown", false)));
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(obsService->AddObserver(this, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID, false)));
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(obsService->AddObserver(this, "last-pb-context-exited", false)));
|
||||
|
||||
nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
|
||||
if (prefs) {
|
||||
prefs->AddObserver("media.gmp.plugin.crash", this, false);
|
||||
}
|
||||
|
||||
#ifndef MOZ_WIDGET_GONK
|
||||
// Directory service is main thread only, so cache the profile dir here
|
||||
// so that we can use it off main thread.
|
||||
// We only do this on non-B2G, as this fails in multi-process Gecko.
|
||||
// TODO: Make this work in multi-process Gecko.
|
||||
nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(mStorageBaseDir));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = mStorageBaseDir->AppendNative(NS_LITERAL_CSTRING("gmp"));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = mStorageBaseDir->Create(nsIFile::DIRECTORY_TYPE, 0700);
|
||||
if (NS_WARN_IF(NS_FAILED(rv) && rv != NS_ERROR_FILE_ALREADY_EXISTS)) {
|
||||
return rv;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Kick off scanning for plugins
|
||||
nsCOMPtr<nsIThread> thread;
|
||||
unused << GetThread(getter_AddRefs(thread));
|
||||
return GetThread(getter_AddRefs(thread));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -288,6 +317,13 @@ GeckoMediaPluginService::Observe(nsISupports* aSubject,
|
|||
if (gmpThread) {
|
||||
gmpThread->Shutdown();
|
||||
}
|
||||
} else if (!strcmp("last-pb-context-exited", aTopic)) {
|
||||
// When Private Browsing mode exits, all we need to do is clear
|
||||
// mTempNodeIds. This drops all the node ids we've cached in memory
|
||||
// for PB origin-pairs. If we try to open an origin-pair for non-PB
|
||||
// mode, we'll get the NodeId salt stored on-disk, and if we try to
|
||||
// open a PB mode origin-pair, we'll re-generate new salt.
|
||||
mTempNodeIds.Clear();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -324,7 +360,7 @@ GeckoMediaPluginService::GetThread(nsIThread** aThread)
|
|||
|
||||
NS_IMETHODIMP
|
||||
GeckoMediaPluginService::GetGMPAudioDecoder(nsTArray<nsCString>* aTags,
|
||||
const nsAString& aOrigin,
|
||||
const nsACString& aNodeId,
|
||||
GMPAudioDecoderProxy** aGMPAD)
|
||||
{
|
||||
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
|
||||
|
@ -335,7 +371,7 @@ GeckoMediaPluginService::GetGMPAudioDecoder(nsTArray<nsCString>* aTags,
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsRefPtr<GMPParent> gmp = SelectPluginForAPI(aOrigin,
|
||||
nsRefPtr<GMPParent> gmp = SelectPluginForAPI(aNodeId,
|
||||
NS_LITERAL_CSTRING("decode-audio"),
|
||||
*aTags);
|
||||
if (!gmp) {
|
||||
|
@ -355,7 +391,7 @@ GeckoMediaPluginService::GetGMPAudioDecoder(nsTArray<nsCString>* aTags,
|
|||
|
||||
NS_IMETHODIMP
|
||||
GeckoMediaPluginService::GetGMPVideoDecoder(nsTArray<nsCString>* aTags,
|
||||
const nsAString& aOrigin,
|
||||
const nsACString& aNodeId,
|
||||
GMPVideoHost** aOutVideoHost,
|
||||
GMPVideoDecoderProxy** aGMPVD)
|
||||
{
|
||||
|
@ -368,7 +404,7 @@ GeckoMediaPluginService::GetGMPVideoDecoder(nsTArray<nsCString>* aTags,
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsRefPtr<GMPParent> gmp = SelectPluginForAPI(aOrigin,
|
||||
nsRefPtr<GMPParent> gmp = SelectPluginForAPI(aNodeId,
|
||||
NS_LITERAL_CSTRING("decode-video"),
|
||||
*aTags);
|
||||
#ifdef PR_LOGGING
|
||||
|
@ -394,7 +430,7 @@ GeckoMediaPluginService::GetGMPVideoDecoder(nsTArray<nsCString>* aTags,
|
|||
|
||||
NS_IMETHODIMP
|
||||
GeckoMediaPluginService::GetGMPVideoEncoder(nsTArray<nsCString>* aTags,
|
||||
const nsAString& aOrigin,
|
||||
const nsACString& aNodeId,
|
||||
GMPVideoHost** aOutVideoHost,
|
||||
GMPVideoEncoderProxy** aGMPVE)
|
||||
{
|
||||
|
@ -407,7 +443,7 @@ GeckoMediaPluginService::GetGMPVideoEncoder(nsTArray<nsCString>* aTags,
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsRefPtr<GMPParent> gmp = SelectPluginForAPI(aOrigin,
|
||||
nsRefPtr<GMPParent> gmp = SelectPluginForAPI(aNodeId,
|
||||
NS_LITERAL_CSTRING("encode-video"),
|
||||
*aTags);
|
||||
#ifdef PR_LOGGING
|
||||
|
@ -432,7 +468,7 @@ GeckoMediaPluginService::GetGMPVideoEncoder(nsTArray<nsCString>* aTags,
|
|||
|
||||
NS_IMETHODIMP
|
||||
GeckoMediaPluginService::GetGMPDecryptor(nsTArray<nsCString>* aTags,
|
||||
const nsAString& aOrigin,
|
||||
const nsACString& aNodeId,
|
||||
GMPDecryptorProxy** aDecryptor)
|
||||
{
|
||||
#if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
|
||||
|
@ -451,7 +487,7 @@ GeckoMediaPluginService::GetGMPDecryptor(nsTArray<nsCString>* aTags,
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsRefPtr<GMPParent> gmp = SelectPluginForAPI(aOrigin,
|
||||
nsRefPtr<GMPParent> gmp = SelectPluginForAPI(aNodeId,
|
||||
NS_LITERAL_CSTRING("eme-decrypt"),
|
||||
*aTags);
|
||||
if (!gmp) {
|
||||
|
@ -658,7 +694,7 @@ GeckoMediaPluginService::RemovePluginDirectory(const nsAString& aDirectory)
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
GeckoMediaPluginService::HasPluginForAPI(const nsAString& aOrigin,
|
||||
GeckoMediaPluginService::HasPluginForAPI(const nsACString& aNodeId,
|
||||
const nsACString& aAPI,
|
||||
nsTArray<nsCString>* aTags,
|
||||
bool* aResult)
|
||||
|
@ -667,19 +703,19 @@ GeckoMediaPluginService::HasPluginForAPI(const nsAString& aOrigin,
|
|||
NS_ENSURE_ARG(aResult);
|
||||
|
||||
nsCString temp(aAPI);
|
||||
GMPParent *parent = SelectPluginForAPI(aOrigin, temp, *aTags, false);
|
||||
GMPParent *parent = SelectPluginForAPI(aNodeId, temp, *aTags, false);
|
||||
*aResult = !!parent;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
GMPParent*
|
||||
GeckoMediaPluginService::SelectPluginForAPI(const nsAString& aOrigin,
|
||||
GeckoMediaPluginService::SelectPluginForAPI(const nsACString& aNodeId,
|
||||
const nsCString& aAPI,
|
||||
const nsTArray<nsCString>& aTags,
|
||||
bool aCloneCrossOrigin)
|
||||
bool aCloneCrossNodeIds)
|
||||
{
|
||||
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread || !aCloneCrossOrigin,
|
||||
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread || !aCloneCrossNodeIds,
|
||||
"Can't clone GMP plugins on non-GMP threads.");
|
||||
|
||||
GMPParent* gmpToClone = nullptr;
|
||||
|
@ -698,14 +734,13 @@ GeckoMediaPluginService::SelectPluginForAPI(const nsAString& aOrigin,
|
|||
if (!supportsAllTags) {
|
||||
continue;
|
||||
}
|
||||
if (aOrigin.IsEmpty()) {
|
||||
if (gmp->CanBeSharedCrossOrigin()) {
|
||||
if (aNodeId.IsEmpty()) {
|
||||
if (gmp->CanBeSharedCrossNodeIds()) {
|
||||
return gmp;
|
||||
}
|
||||
} else if (gmp->CanBeUsedFrom(aOrigin)) {
|
||||
if (!aOrigin.IsEmpty()) {
|
||||
gmp->SetOrigin(aOrigin);
|
||||
}
|
||||
} else if (gmp->CanBeUsedFrom(aNodeId)) {
|
||||
MOZ_ASSERT(!aNodeId.IsEmpty());
|
||||
gmp->SetNodeId(aNodeId);
|
||||
return gmp;
|
||||
}
|
||||
|
||||
|
@ -717,10 +752,10 @@ GeckoMediaPluginService::SelectPluginForAPI(const nsAString& aOrigin,
|
|||
|
||||
// Plugin exists, but we can't use it due to cross-origin separation. Create a
|
||||
// new one.
|
||||
if (aCloneCrossOrigin && gmpToClone) {
|
||||
if (aCloneCrossNodeIds && gmpToClone) {
|
||||
GMPParent* clone = ClonePlugin(gmpToClone);
|
||||
if (!aOrigin.IsEmpty()) {
|
||||
clone->SetOrigin(aOrigin);
|
||||
if (!aNodeId.IsEmpty()) {
|
||||
clone->SetNodeId(aNodeId);
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
|
@ -855,5 +890,256 @@ GeckoMediaPluginService::ReAddOnGMPThread(nsRefPtr<GMPParent>& aOld)
|
|||
NS_DispatchToCurrentThread(WrapRunnableNM(&Dummy, aOld));
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
GeckoMediaPluginService::GetStorageDir(nsIFile** aOutFile)
|
||||
{
|
||||
#ifndef MOZ_WIDGET_GONK
|
||||
if (NS_WARN_IF(!mStorageBaseDir)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return mStorageBaseDir->Clone(aOutFile);
|
||||
#else
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
#endif
|
||||
}
|
||||
|
||||
static nsresult
|
||||
WriteToFile(nsIFile* aPath,
|
||||
const nsCString& aFileName,
|
||||
const nsCString& aData)
|
||||
{
|
||||
nsCOMPtr<nsIFile> path;
|
||||
nsresult rv = aPath->Clone(getter_AddRefs(path));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = path->AppendNative(aFileName);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
PRFileDesc* f = nullptr;
|
||||
rv = path->OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE, PR_IRWXU, &f);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
int32_t len = PR_Write(f, aData.get(), aData.Length());
|
||||
PR_Close(f);
|
||||
if (NS_WARN_IF(len < 0 || (size_t)len != aData.Length())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static nsresult
|
||||
ReadFromFile(nsIFile* aPath,
|
||||
const nsCString& aFileName,
|
||||
nsCString& aOutData,
|
||||
int32_t aMaxLength)
|
||||
{
|
||||
nsCOMPtr<nsIFile> path;
|
||||
nsresult rv = aPath->Clone(getter_AddRefs(path));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = path->AppendNative(aFileName);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
PRFileDesc* f = nullptr;
|
||||
rv = path->OpenNSPRFileDesc(PR_RDONLY | PR_CREATE_FILE, PR_IRWXU, &f);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
auto size = PR_Seek(f, 0, PR_SEEK_END);
|
||||
PR_Seek(f, 0, PR_SEEK_SET);
|
||||
|
||||
if (size > aMaxLength) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
aOutData.SetLength(size);
|
||||
|
||||
auto len = PR_Read(f, aOutData.BeginWriting(), size);
|
||||
PR_Close(f);
|
||||
if (NS_WARN_IF(len != size)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
GeckoMediaPluginService::IsPersistentStorageAllowed(const nsACString& aNodeId,
|
||||
bool* aOutAllowed)
|
||||
{
|
||||
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
|
||||
NS_ENSURE_ARG(aOutAllowed);
|
||||
*aOutAllowed = mPersistentStorageAllowed.Get(aNodeId);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
GeckoMediaPluginService::GetNodeId(const nsAString& aOrigin,
|
||||
const nsAString& aTopLevelOrigin,
|
||||
bool aInPrivateBrowsing,
|
||||
nsACString& aOutId)
|
||||
{
|
||||
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
|
||||
LOGD(("%s::%s: (%s, %s), %s", __CLASS__, __FUNCTION__,
|
||||
NS_ConvertUTF16toUTF8(aOrigin).get(),
|
||||
NS_ConvertUTF16toUTF8(aTopLevelOrigin).get(),
|
||||
(aInPrivateBrowsing ? "PrivateBrowsing" : "NonPrivateBrowsing")));
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
NS_WARNING("GeckoMediaPluginService::GetNodeId Not implemented on B2G");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
#endif
|
||||
|
||||
nsresult rv;
|
||||
const uint32_t NodeIdSaltLength = 32;
|
||||
|
||||
if (aOrigin.EqualsLiteral("null") ||
|
||||
aOrigin.IsEmpty() ||
|
||||
aTopLevelOrigin.EqualsLiteral("null") ||
|
||||
aTopLevelOrigin.IsEmpty()) {
|
||||
// At least one of the (origin, topLevelOrigin) is null or empty;
|
||||
// probably a local file. Generate a random node id, and don't store
|
||||
// it so that the GMP's storage is temporary and not shared.
|
||||
nsAutoCString salt;
|
||||
rv = GenerateRandomPathName(salt, NodeIdSaltLength);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
aOutId = salt;
|
||||
mPersistentStorageAllowed.Put(salt, false);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
const uint32_t hash = AddToHash(HashString(aOrigin),
|
||||
HashString(aTopLevelOrigin));
|
||||
|
||||
if (aInPrivateBrowsing) {
|
||||
// For PB mode, we store the node id, indexed by the origin pair,
|
||||
// so that if the same origin pair is opened in this session, it gets
|
||||
// the same node id.
|
||||
nsCString* salt = nullptr;
|
||||
if (!(salt = mTempNodeIds.Get(hash))) {
|
||||
// No salt stored, generate and temporarily store some for this id.
|
||||
nsAutoCString newSalt;
|
||||
rv = GenerateRandomPathName(newSalt, NodeIdSaltLength);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
salt = new nsCString(newSalt);
|
||||
mTempNodeIds.Put(hash, salt);
|
||||
mPersistentStorageAllowed.Put(*salt, false);
|
||||
}
|
||||
aOutId = *salt;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Otherwise, try to see if we've previously generated and stored salt
|
||||
// for this origin pair.
|
||||
nsCOMPtr<nsIFile> path; // $profileDir/gmp/
|
||||
rv = GetStorageDir(getter_AddRefs(path));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = path->AppendNative(NS_LITERAL_CSTRING("id"));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// $profileDir/gmp/id/
|
||||
rv = path->Create(nsIFile::DIRECTORY_TYPE, 0700);
|
||||
if (rv != NS_ERROR_FILE_ALREADY_EXISTS && NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsAutoCString hashStr;
|
||||
hashStr.AppendInt((int64_t)hash);
|
||||
|
||||
// $profileDir/gmp/id/$hash
|
||||
rv = path->AppendNative(hashStr);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = path->Create(nsIFile::DIRECTORY_TYPE, 0700);
|
||||
if (rv != NS_ERROR_FILE_ALREADY_EXISTS && NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> saltFile;
|
||||
rv = path->Clone(getter_AddRefs(saltFile));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = saltFile->AppendNative(NS_LITERAL_CSTRING("salt"));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsAutoCString salt;
|
||||
bool exists = false;
|
||||
rv = saltFile->Exists(&exists);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
if (!exists) {
|
||||
// No stored salt for this origin. Generate salt, and store it and
|
||||
// the origin on disk.
|
||||
nsresult rv = GenerateRandomPathName(salt, NodeIdSaltLength);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
MOZ_ASSERT(salt.Length() == NodeIdSaltLength);
|
||||
|
||||
// $profileDir/gmp/id/$hash/salt
|
||||
rv = WriteToFile(path, NS_LITERAL_CSTRING("salt"), salt);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// $profileDir/gmp/id/$hash/origin
|
||||
rv = WriteToFile(path,
|
||||
NS_LITERAL_CSTRING("origin"),
|
||||
NS_ConvertUTF16toUTF8(aOrigin));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// $profileDir/gmp/id/$hash/topLevelOrigin
|
||||
rv = WriteToFile(path,
|
||||
NS_LITERAL_CSTRING("topLevelOrigin"),
|
||||
NS_ConvertUTF16toUTF8(aTopLevelOrigin));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
} else {
|
||||
rv = ReadFromFile(path,
|
||||
NS_LITERAL_CSTRING("salt"),
|
||||
salt,
|
||||
NodeIdSaltLength);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
aOutId = salt;
|
||||
mPersistentStorageAllowed.Put(salt, true);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace gmp
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
#include "nsIThread.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsClassHashtable.h"
|
||||
#include "nsDataHashtable.h"
|
||||
|
||||
template <class> struct already_AddRefed;
|
||||
|
||||
|
@ -32,7 +34,7 @@ public:
|
|||
static already_AddRefed<GeckoMediaPluginService> GetGeckoMediaPluginService();
|
||||
|
||||
GeckoMediaPluginService();
|
||||
void Init();
|
||||
nsresult Init();
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_MOZIGECKOMEDIAPLUGINSERVICE
|
||||
|
@ -45,10 +47,10 @@ public:
|
|||
private:
|
||||
~GeckoMediaPluginService();
|
||||
|
||||
GMPParent* SelectPluginForAPI(const nsAString& aOrigin,
|
||||
GMPParent* SelectPluginForAPI(const nsACString& aNodeId,
|
||||
const nsCString& aAPI,
|
||||
const nsTArray<nsCString>& aTags,
|
||||
bool aCloneCrossOrigin = true);
|
||||
bool aCloneCrossNodeIds = true);
|
||||
|
||||
void UnloadPlugins();
|
||||
void CrashPlugins();
|
||||
|
@ -111,6 +113,18 @@ private:
|
|||
|
||||
nsTArray<nsRefPtr<GMPParent>> mAsyncShutdownPlugins; // GMP Thread only.
|
||||
nsCOMPtr<nsITimer> mAsyncShutdownTimeout; // GMP Thread only.
|
||||
|
||||
#ifndef MOZ_WIDGET_GONK
|
||||
nsCOMPtr<nsIFile> mStorageBaseDir;
|
||||
#endif
|
||||
|
||||
// Hashes of (origin,topLevelOrigin) to the node id for
|
||||
// non-persistent sessions.
|
||||
nsClassHashtable<nsUint32HashKey, nsCString> mTempNodeIds;
|
||||
|
||||
// Hashes node id to whether that node id is allowed to store data
|
||||
// persistently on disk.
|
||||
nsDataHashtable<nsCStringHashKey, bool> mPersistentStorageAllowed;
|
||||
};
|
||||
|
||||
} // namespace gmp
|
||||
|
|
|
@ -8,9 +8,16 @@
|
|||
#include "plhash.h"
|
||||
#include "nsDirectoryServiceUtils.h"
|
||||
#include "nsDirectoryServiceDefs.h"
|
||||
#include "nsAppDirectoryServiceDefs.h"
|
||||
#include "GMPParent.h"
|
||||
#include "gmp-storage.h"
|
||||
#include "mozilla/unused.h"
|
||||
#include "nsTHashtable.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "prio.h"
|
||||
#include "mozIGeckoMediaPluginService.h"
|
||||
#include "nsContentCID.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -35,55 +42,38 @@ extern PRLogModuleInfo* GetGMPLog();
|
|||
|
||||
namespace gmp {
|
||||
|
||||
class GetTempDirTask : public nsRunnable
|
||||
{
|
||||
public:
|
||||
NS_IMETHOD Run() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsCOMPtr<nsIFile> tmpFile;
|
||||
nsresult rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(tmpFile));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
tmpFile->GetPath(mPath);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsString mPath;
|
||||
};
|
||||
|
||||
// We store the records in files in the system temp dir.
|
||||
// We store the records in files in the profile dir.
|
||||
// $profileDir/gmp/storage/$nodeId/
|
||||
static nsresult
|
||||
GetGMPStorageDir(nsIFile** aTempDir, const nsString& aOrigin)
|
||||
GetGMPStorageDir(nsIFile** aTempDir, const nsCString& aNodeId)
|
||||
{
|
||||
if (NS_WARN_IF(!aTempDir)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
// Directory service is main thread only...
|
||||
nsRefPtr<GetTempDirTask> task = new GetTempDirTask();
|
||||
nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
|
||||
mozilla::SyncRunnable::DispatchToThread(mainThread, task);
|
||||
nsCOMPtr<mozIGeckoMediaPluginService> mps =
|
||||
do_GetService("@mozilla.org/gecko-media-plugin-service;1");
|
||||
if (NS_WARN_IF(!mps)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> tmpFile;
|
||||
nsresult rv = NS_NewLocalFile(task->mPath, false, getter_AddRefs(tmpFile));
|
||||
nsresult rv = mps->GetStorageDir(getter_AddRefs(tmpFile));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = tmpFile->AppendNative(nsDependentCString("mozilla-gmp-storage"));
|
||||
rv = tmpFile->AppendNative(NS_LITERAL_CSTRING("storage"));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// TODO: When aOrigin is the same node-id as the GMP sees in the child
|
||||
// process (a UUID or somesuch), we can just append it un-hashed here.
|
||||
// This should reduce the chance of hash collsions exposing data.
|
||||
nsAutoString nodeIdHash;
|
||||
nodeIdHash.AppendInt(HashString(static_cast<const char16_t*>(aOrigin.get())));
|
||||
rv = tmpFile->Append(nodeIdHash);
|
||||
rv = tmpFile->Create(nsIFile::DIRECTORY_TYPE, 0700);
|
||||
if (rv != NS_ERROR_FILE_ALREADY_EXISTS && NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = tmpFile->AppendNative(aNodeId);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -98,19 +88,11 @@ GetGMPStorageDir(nsIFile** aTempDir, const nsString& aOrigin)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
GMPStorageParent::GMPStorageParent(const nsString& aOrigin,
|
||||
GMPParent* aPlugin)
|
||||
: mOrigin(aOrigin)
|
||||
, mPlugin(aPlugin)
|
||||
, mShutdown(false)
|
||||
{
|
||||
}
|
||||
|
||||
enum OpenFileMode { ReadWrite, Truncate };
|
||||
|
||||
nsresult
|
||||
OpenStorageFile(const nsCString& aRecordName,
|
||||
const nsString& aNodeId,
|
||||
const nsCString& aNodeId,
|
||||
const OpenFileMode aMode,
|
||||
PRFileDesc** aOutFD)
|
||||
{
|
||||
|
@ -134,36 +116,231 @@ OpenStorageFile(const nsCString& aRecordName,
|
|||
return f->OpenNSPRFileDesc(mode, PR_IRWXU, aOutFD);
|
||||
}
|
||||
|
||||
PLDHashOperator
|
||||
CloseFile(const nsACString& key, PRFileDesc*& entry, void* cx)
|
||||
{
|
||||
if (PR_Close(entry) != PR_SUCCESS) {
|
||||
NS_WARNING("GMPDiskStorage Failed to clsose file.");
|
||||
}
|
||||
return PL_DHASH_REMOVE;
|
||||
}
|
||||
|
||||
class GMPDiskStorage : public GMPStorage {
|
||||
public:
|
||||
GMPDiskStorage(const nsCString& aNodeId)
|
||||
: mNodeId(aNodeId)
|
||||
{
|
||||
}
|
||||
~GMPDiskStorage() {
|
||||
mFiles.Enumerate(CloseFile, nullptr);
|
||||
MOZ_ASSERT(!mFiles.Count());
|
||||
}
|
||||
|
||||
virtual GMPErr Open(const nsCString& aRecordName) MOZ_OVERRIDE
|
||||
{
|
||||
MOZ_ASSERT(!IsOpen(aRecordName));
|
||||
PRFileDesc* fd = nullptr;
|
||||
if (NS_FAILED(OpenStorageFile(aRecordName, mNodeId, ReadWrite, &fd))) {
|
||||
NS_WARNING("Failed to open storage file.");
|
||||
return GMPGenericErr;
|
||||
}
|
||||
mFiles.Put(aRecordName, fd);
|
||||
return GMPNoErr;
|
||||
}
|
||||
|
||||
virtual bool IsOpen(const nsCString& aRecordName) MOZ_OVERRIDE {
|
||||
return mFiles.Contains(aRecordName);
|
||||
}
|
||||
|
||||
virtual GMPErr Read(const nsCString& aRecordName,
|
||||
nsTArray<uint8_t>& aOutBytes) MOZ_OVERRIDE
|
||||
{
|
||||
PRFileDesc* fd = mFiles.Get(aRecordName);
|
||||
if (!fd) {
|
||||
return GMPGenericErr;
|
||||
}
|
||||
|
||||
int32_t len = PR_Seek(fd, 0, PR_SEEK_END);
|
||||
PR_Seek(fd, 0, PR_SEEK_SET);
|
||||
|
||||
if (len > GMP_MAX_RECORD_SIZE) {
|
||||
// Refuse to read big records.
|
||||
return GMPQuotaExceededErr;
|
||||
}
|
||||
aOutBytes.SetLength(len);
|
||||
auto bytesRead = PR_Read(fd, aOutBytes.Elements(), len);
|
||||
return (bytesRead == len) ? GMPNoErr : GMPGenericErr;
|
||||
}
|
||||
|
||||
virtual GMPErr Write(const nsCString& aRecordName,
|
||||
const nsTArray<uint8_t>& aBytes) MOZ_OVERRIDE
|
||||
{
|
||||
PRFileDesc* fd = mFiles.Get(aRecordName);
|
||||
if (!fd) {
|
||||
return GMPGenericErr;
|
||||
}
|
||||
|
||||
// Write operations overwrite the entire record. So re-open the file
|
||||
// in truncate mode, to clear its contents.
|
||||
PR_Close(fd);
|
||||
mFiles.Remove(aRecordName);
|
||||
if (NS_FAILED(OpenStorageFile(aRecordName, mNodeId, Truncate, &fd))) {
|
||||
return GMPGenericErr;
|
||||
}
|
||||
mFiles.Put(aRecordName, fd);
|
||||
|
||||
int32_t bytesWritten = PR_Write(fd, aBytes.Elements(), aBytes.Length());
|
||||
return (bytesWritten == (int32_t)aBytes.Length()) ? GMPNoErr : GMPGenericErr;
|
||||
}
|
||||
|
||||
virtual void Close(const nsCString& aRecordName) MOZ_OVERRIDE
|
||||
{
|
||||
PRFileDesc* fd = mFiles.Get(aRecordName);
|
||||
if (fd) {
|
||||
if (PR_Close(fd) == PR_SUCCESS) {
|
||||
mFiles.Remove(aRecordName);
|
||||
} else {
|
||||
NS_WARNING("GMPDiskStorage Failed to clsose file.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
nsDataHashtable<nsCStringHashKey, PRFileDesc*> mFiles;
|
||||
const nsAutoCString mNodeId;
|
||||
};
|
||||
|
||||
class GMPMemoryStorage : public GMPStorage {
|
||||
public:
|
||||
virtual GMPErr Open(const nsCString& aRecordName) MOZ_OVERRIDE
|
||||
{
|
||||
MOZ_ASSERT(!IsOpen(aRecordName));
|
||||
|
||||
Record* record = nullptr;
|
||||
if (!mRecords.Get(aRecordName, &record)) {
|
||||
record = new Record();
|
||||
mRecords.Put(aRecordName, record);
|
||||
}
|
||||
record->mIsOpen = true;
|
||||
return GMPNoErr;
|
||||
}
|
||||
|
||||
virtual bool IsOpen(const nsCString& aRecordName) MOZ_OVERRIDE {
|
||||
Record* record = nullptr;
|
||||
if (!mRecords.Get(aRecordName, &record)) {
|
||||
return false;
|
||||
}
|
||||
return record->mIsOpen;
|
||||
}
|
||||
|
||||
virtual GMPErr Read(const nsCString& aRecordName,
|
||||
nsTArray<uint8_t>& aOutBytes) MOZ_OVERRIDE
|
||||
{
|
||||
Record* record = nullptr;
|
||||
if (!mRecords.Get(aRecordName, &record)) {
|
||||
return GMPGenericErr;
|
||||
}
|
||||
aOutBytes = record->mData;
|
||||
return GMPNoErr;
|
||||
}
|
||||
|
||||
virtual GMPErr Write(const nsCString& aRecordName,
|
||||
const nsTArray<uint8_t>& aBytes) MOZ_OVERRIDE
|
||||
{
|
||||
Record* record = nullptr;
|
||||
if (!mRecords.Get(aRecordName, &record)) {
|
||||
return GMPClosedErr;
|
||||
}
|
||||
record->mData = aBytes;
|
||||
return GMPNoErr;
|
||||
}
|
||||
|
||||
virtual void Close(const nsCString& aRecordName) MOZ_OVERRIDE
|
||||
{
|
||||
Record* record = nullptr;
|
||||
if (!mRecords.Get(aRecordName, &record)) {
|
||||
return;
|
||||
}
|
||||
if (!record->mData.Length()) {
|
||||
// Record is empty, delete.
|
||||
mRecords.Remove(aRecordName);
|
||||
} else {
|
||||
record->mIsOpen = false;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
struct Record {
|
||||
Record() : mIsOpen(false) {}
|
||||
nsTArray<uint8_t> mData;
|
||||
bool mIsOpen;
|
||||
};
|
||||
|
||||
nsClassHashtable<nsCStringHashKey, Record> mRecords;
|
||||
};
|
||||
|
||||
GMPStorageParent::GMPStorageParent(const nsCString& aNodeId,
|
||||
GMPParent* aPlugin)
|
||||
: mNodeId(aNodeId)
|
||||
, mPlugin(aPlugin)
|
||||
, mShutdown(false)
|
||||
{
|
||||
}
|
||||
|
||||
nsresult
|
||||
GMPStorageParent::Init()
|
||||
{
|
||||
if (NS_WARN_IF(mNodeId.IsEmpty())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
nsCOMPtr<mozIGeckoMediaPluginService> mps =
|
||||
do_GetService("@mozilla.org/gecko-media-plugin-service;1");
|
||||
if (NS_WARN_IF(!mps)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
bool persistent = false;
|
||||
if (NS_WARN_IF(NS_FAILED(mps->IsPersistentStorageAllowed(mNodeId, &persistent)))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
if (persistent) {
|
||||
mStorage = MakeUnique<GMPDiskStorage>(mNodeId);
|
||||
} else {
|
||||
mStorage = MakeUnique<GMPMemoryStorage>();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
GMPStorageParent::RecvOpen(const nsCString& aRecordName)
|
||||
{
|
||||
if (mShutdown) {
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mOrigin.EqualsASCII("null")) {
|
||||
// Refuse to open storage if the page is the "null" origin; if the page
|
||||
// is opened from disk.
|
||||
NS_WARNING("Refusing to open storage for null origin");
|
||||
if (mNodeId.EqualsLiteral("null")) {
|
||||
// Refuse to open storage if the page is opened from local disk,
|
||||
// or shared across origin.
|
||||
NS_WARNING("Refusing to open storage for null NodeId");
|
||||
unused << SendOpenComplete(aRecordName, GMPGenericErr);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (aRecordName.IsEmpty() || mFiles.Contains(aRecordName)) {
|
||||
if (aRecordName.IsEmpty()) {
|
||||
unused << SendOpenComplete(aRecordName, GMPGenericErr);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mStorage->IsOpen(aRecordName)) {
|
||||
unused << SendOpenComplete(aRecordName, GMPRecordInUse);
|
||||
return true;
|
||||
}
|
||||
|
||||
PRFileDesc* fd = nullptr;
|
||||
nsresult rv = OpenStorageFile(aRecordName, mOrigin, ReadWrite, &fd);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Failed to open storage file.");
|
||||
unused << SendOpenComplete(aRecordName, GMPGenericErr);
|
||||
return true;
|
||||
}
|
||||
|
||||
mFiles.Put(aRecordName, fd);
|
||||
unused << SendOpenComplete(aRecordName, GMPNoErr);
|
||||
auto err = mStorage->Open(aRecordName);
|
||||
MOZ_ASSERT(GMP_FAILED(err) || mStorage->IsOpen(aRecordName));
|
||||
unused << SendOpenComplete(aRecordName, err);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -174,29 +351,16 @@ GMPStorageParent::RecvRead(const nsCString& aRecordName)
|
|||
LOGD(("%s::%s: %p record=%s", __CLASS__, __FUNCTION__, this, aRecordName.get()));
|
||||
|
||||
if (mShutdown) {
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
PRFileDesc* fd = mFiles.Get(aRecordName);
|
||||
nsTArray<uint8_t> data;
|
||||
if (!fd) {
|
||||
if (!mStorage->IsOpen(aRecordName)) {
|
||||
unused << SendReadComplete(aRecordName, GMPClosedErr, data);
|
||||
return true;
|
||||
} else {
|
||||
unused << SendReadComplete(aRecordName, mStorage->Read(aRecordName, data), data);
|
||||
}
|
||||
|
||||
int32_t len = PR_Seek(fd, 0, PR_SEEK_END);
|
||||
PR_Seek(fd, 0, PR_SEEK_SET);
|
||||
|
||||
if (len > GMP_MAX_RECORD_SIZE) {
|
||||
// Refuse to read big records.
|
||||
unused << SendReadComplete(aRecordName, GMPQuotaExceededErr, data);
|
||||
return true;
|
||||
}
|
||||
data.SetLength(len);
|
||||
auto bytesRead = PR_Read(fd, data.Elements(), len);
|
||||
auto res = (bytesRead == len) ? GMPNoErr : GMPGenericErr;
|
||||
unused << SendReadComplete(aRecordName, res, data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -207,32 +371,21 @@ GMPStorageParent::RecvWrite(const nsCString& aRecordName,
|
|||
LOGD(("%s::%s: %p record=%s", __CLASS__, __FUNCTION__, this, aRecordName.get()));
|
||||
|
||||
if (mShutdown) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mStorage->IsOpen(aRecordName)) {
|
||||
unused << SendWriteComplete(aRecordName, GMPClosedErr);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (aBytes.Length() > GMP_MAX_RECORD_SIZE) {
|
||||
unused << SendWriteComplete(aRecordName, GMPQuotaExceededErr);
|
||||
return true;
|
||||
}
|
||||
|
||||
PRFileDesc* fd = mFiles.Get(aRecordName);
|
||||
if (!fd) {
|
||||
unused << SendWriteComplete(aRecordName, GMPGenericErr);
|
||||
return true;
|
||||
}
|
||||
unused << SendWriteComplete(aRecordName, mStorage->Write(aRecordName, aBytes));
|
||||
|
||||
// Write operations overwrite the entire record. So re-open the file
|
||||
// in truncate mode, to clear its contents.
|
||||
PR_Close(fd);
|
||||
mFiles.Remove(aRecordName);
|
||||
if (NS_FAILED(OpenStorageFile(aRecordName, mOrigin, Truncate, &fd))) {
|
||||
unused << SendWriteComplete(aRecordName, GMPGenericErr);
|
||||
return true;
|
||||
}
|
||||
mFiles.Put(aRecordName, fd);
|
||||
|
||||
int32_t bytesWritten = PR_Write(fd, aBytes.Elements(), aBytes.Length());
|
||||
auto res = (bytesWritten == (int32_t)aBytes.Length()) ? GMPNoErr : GMPGenericErr;
|
||||
unused << SendWriteComplete(aRecordName, res);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -245,12 +398,8 @@ GMPStorageParent::RecvClose(const nsCString& aRecordName)
|
|||
return true;
|
||||
}
|
||||
|
||||
PRFileDesc* fd = mFiles.Get(aRecordName);
|
||||
if (!fd) {
|
||||
return true;
|
||||
}
|
||||
PR_Close(fd);
|
||||
mFiles.Remove(aRecordName);
|
||||
mStorage->Close(aRecordName);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -261,13 +410,6 @@ GMPStorageParent::ActorDestroy(ActorDestroyReason aWhy)
|
|||
Shutdown();
|
||||
}
|
||||
|
||||
PLDHashOperator
|
||||
CloseFile(const nsACString& key, PRFileDesc*& entry, void* cx)
|
||||
{
|
||||
PR_Close(entry);
|
||||
return PL_DHASH_REMOVE;
|
||||
}
|
||||
|
||||
void
|
||||
GMPStorageParent::Shutdown()
|
||||
{
|
||||
|
@ -279,8 +421,8 @@ GMPStorageParent::Shutdown()
|
|||
mShutdown = true;
|
||||
unused << SendShutdown();
|
||||
|
||||
mFiles.Enumerate(CloseFile, nullptr);
|
||||
MOZ_ASSERT(!mFiles.Count());
|
||||
mStorage = nullptr;
|
||||
|
||||
}
|
||||
|
||||
} // namespace gmp
|
||||
|
|
|
@ -8,20 +8,33 @@
|
|||
|
||||
#include "mozilla/gmp/PGMPStorageParent.h"
|
||||
#include "gmp-storage.h"
|
||||
#include "nsTHashtable.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "prio.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
||||
class GMPParent;
|
||||
|
||||
class GMPStorage {
|
||||
public:
|
||||
virtual ~GMPStorage() {}
|
||||
|
||||
virtual GMPErr Open(const nsCString& aRecordName) = 0;
|
||||
virtual bool IsOpen(const nsCString& aRecordName) = 0;
|
||||
virtual GMPErr Read(const nsCString& aRecordName,
|
||||
nsTArray<uint8_t>& aOutBytes) = 0;
|
||||
virtual GMPErr Write(const nsCString& aRecordName,
|
||||
const nsTArray<uint8_t>& aBytes) = 0;
|
||||
virtual void Close(const nsCString& aRecordName) = 0;
|
||||
};
|
||||
|
||||
class GMPStorageParent : public PGMPStorageParent {
|
||||
public:
|
||||
NS_INLINE_DECL_REFCOUNTING(GMPStorageParent)
|
||||
GMPStorageParent(const nsString& aOrigin, GMPParent* aPlugin);
|
||||
GMPStorageParent(const nsCString& aNodeId,
|
||||
GMPParent* aPlugin);
|
||||
|
||||
nsresult Init();
|
||||
void Shutdown();
|
||||
|
||||
protected:
|
||||
|
@ -35,8 +48,9 @@ protected:
|
|||
private:
|
||||
~GMPStorageParent() {}
|
||||
|
||||
nsDataHashtable<nsCStringHashKey, PRFileDesc*> mFiles;
|
||||
const nsString mOrigin;
|
||||
UniquePtr<GMPStorage> mStorage;
|
||||
|
||||
const nsCString mNodeId;
|
||||
nsRefPtr<GMPParent> mPlugin;
|
||||
bool mShutdown;
|
||||
};
|
||||
|
|
|
@ -40,6 +40,8 @@ child:
|
|||
async PGMPVideoDecoder();
|
||||
async PGMPVideoEncoder();
|
||||
|
||||
async SetNodeId(nsCString nodeId);
|
||||
async StartPlugin();
|
||||
async BeginAsyncShutdown();
|
||||
async CrashPluginNow();
|
||||
};
|
||||
|
|
|
@ -90,6 +90,11 @@ UNIFIED_SOURCES += [
|
|||
'GMPVideoPlaneImpl.cpp',
|
||||
]
|
||||
|
||||
if CONFIG['OS_TARGET'] == 'WINNT':
|
||||
DIRS += [
|
||||
'rlz',
|
||||
]
|
||||
|
||||
IPDL_SOURCES += [
|
||||
'GMPTypes.ipdlh',
|
||||
'PGMP.ipdl',
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "nsISupports.idl"
|
||||
#include "nsIThread.idl"
|
||||
#include "nsIPrincipal.idl"
|
||||
#include "nsIFile.idl"
|
||||
|
||||
%{C++
|
||||
#include "nsTArray.h"
|
||||
|
@ -25,9 +26,10 @@ class GMPVideoHost;
|
|||
[ptr] native GMPDecryptorProxy(GMPDecryptorProxy);
|
||||
[ptr] native GMPAudioDecoderProxy(GMPAudioDecoderProxy);
|
||||
|
||||
[scriptable, uuid(6ea374fc-32ad-46f6-ae9d-80b668f4fd49)]
|
||||
[scriptable, uuid(b350d3b6-00c9-4602-bdfe-84c2be8d1e7a)]
|
||||
interface mozIGeckoMediaPluginService : nsISupports
|
||||
{
|
||||
|
||||
/**
|
||||
* The GMP thread. Callable from any thread.
|
||||
*/
|
||||
|
@ -38,7 +40,7 @@ interface mozIGeckoMediaPluginService : nsISupports
|
|||
* Callable on any thread
|
||||
*/
|
||||
[noscript]
|
||||
boolean hasPluginForAPI([optional] in AString origin,
|
||||
boolean hasPluginForAPI([optional] in ACString nodeId,
|
||||
in ACString api,
|
||||
in TagArray tags);
|
||||
|
||||
|
@ -50,7 +52,7 @@ interface mozIGeckoMediaPluginService : nsISupports
|
|||
*/
|
||||
[noscript]
|
||||
GMPVideoDecoderProxy getGMPVideoDecoder(in TagArray tags,
|
||||
[optional] in AString origin,
|
||||
[optional] in ACString nodeId,
|
||||
out GMPVideoHost outVideoHost);
|
||||
|
||||
/**
|
||||
|
@ -61,7 +63,7 @@ interface mozIGeckoMediaPluginService : nsISupports
|
|||
*/
|
||||
[noscript]
|
||||
GMPVideoEncoderProxy getGMPVideoEncoder(in TagArray tags,
|
||||
[optional] in AString origin,
|
||||
[optional] in ACString nodeId,
|
||||
out GMPVideoHost outVideoHost);
|
||||
|
||||
// Returns an audio decoder that supports the specified tags.
|
||||
|
@ -69,13 +71,13 @@ interface mozIGeckoMediaPluginService : nsISupports
|
|||
// other tags such as for EME keysystem.
|
||||
// Callable only on GMP thread.
|
||||
GMPAudioDecoderProxy getGMPAudioDecoder(in TagArray tags,
|
||||
[optional] in AString origin);
|
||||
[optional] in ACString nodeId);
|
||||
|
||||
// Returns a decryption session manager that supports the specified tags.
|
||||
// The array of tags should at least contain a key system tag, and optionally
|
||||
// other tags.
|
||||
// Callable only on GMP thread.
|
||||
GMPDecryptorProxy getGMPDecryptor(in TagArray tags, in AString origin);
|
||||
GMPDecryptorProxy getGMPDecryptor(in TagArray tags, in ACString nodeId);
|
||||
|
||||
/**
|
||||
* Add a directory to scan for gecko media plugins.
|
||||
|
@ -88,4 +90,24 @@ interface mozIGeckoMediaPluginService : nsISupports
|
|||
* @note Main-thread API.
|
||||
*/
|
||||
void removePluginDirectory(in AString directory);
|
||||
|
||||
/**
|
||||
* Gets the NodeId for a (origin, urlbarOrigin, isInprivateBrowsing) tuple.
|
||||
*/
|
||||
ACString getNodeId(in AString origin,
|
||||
in AString topLevelOrigin,
|
||||
in bool inPrivateBrowsingMode);
|
||||
|
||||
/**
|
||||
* Returns true if the given node id is allowed to store things
|
||||
* persistently on disk. Private Browsing and local content are not
|
||||
* allowed to store persistent data.
|
||||
*/
|
||||
bool isPersistentStorageAllowed(in ACString nodeId);
|
||||
|
||||
/**
|
||||
* Returns the directory to use as the base for storing data about GMPs.
|
||||
*/
|
||||
nsIFile getStorageDir();
|
||||
|
||||
};
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
Copyright 2010 Google Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
Code taken from rlz project: https://code.google.com/p/rlz/
|
||||
|
||||
Revision: 134, then with unused code stripped out.
|
||||
|
||||
Note: base/ contains wrappers/dummies to provide implementations of the
|
||||
Chromium APIs that this code relies upon.
|
|
@ -0,0 +1,27 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// The scoped_ptr.h our IPC copy of Chromium's code does not include
|
||||
// scoped_array, so adapt it to nsAutoArrayPtr here.
|
||||
|
||||
#ifndef FAKE_SCOPED_PTR_H_
|
||||
#define FAKE_SCOPED_PTR_H_
|
||||
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "nsAutoPtr.h"
|
||||
|
||||
template<class T>
|
||||
class scoped_array : public nsAutoArrayPtr<T> {
|
||||
public:
|
||||
scoped_array(T* t) : nsAutoArrayPtr<T>(t) {}
|
||||
void reset(T* t) {
|
||||
scoped_array<T> other(t);
|
||||
operator=(other);
|
||||
}
|
||||
};
|
||||
|
||||
#define arraysize mozilla::ArrayLength
|
||||
|
||||
#endif
|
|
@ -0,0 +1,12 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef FAKE_STRING16_H
|
||||
#define FAKE_STRING16_H
|
||||
|
||||
#include <string>
|
||||
typedef std::wstring string16;
|
||||
|
||||
#endif
|
|
@ -0,0 +1,14 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef FAKE_ASSERT_H_
|
||||
#define FAKE_ASSERT_H_
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#define ASSERT_STRING(x) { assert(false); }
|
||||
#define VERIFY(x) { assert(x); };
|
||||
|
||||
#endif
|
|
@ -0,0 +1,21 @@
|
|||
// Copyright 2012 Google Inc. All Rights Reserved.
|
||||
// Use of this source code is governed by an Apache-style license that can be
|
||||
// found in the COPYING file.
|
||||
|
||||
#ifndef RLZ_LIB_MACHINE_ID_H_
|
||||
#define RLZ_LIB_MACHINE_ID_H_
|
||||
|
||||
#include "base/string16.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace rlz_lib {
|
||||
|
||||
// Retrieves a raw machine identifier string and a machine-specific
|
||||
// 4 byte value. GetMachineId() will SHA1 |data|, append |more_data|, compute
|
||||
// the Crc8 of that, and return a hex-encoded string of that data.
|
||||
bool GetRawMachineId(string16* data, int* more_data);
|
||||
|
||||
} // namespace rlz_lib
|
||||
|
||||
#endif // RLZ_LIB_MACHINE_ID_H_
|
|
@ -0,0 +1,34 @@
|
|||
// Copyright 2010 Google Inc. All Rights Reserved.
|
||||
// Use of this source code is governed by an Apache-style license that can be
|
||||
// found in the COPYING file.
|
||||
//
|
||||
// String manipulation functions used in the RLZ library.
|
||||
|
||||
#include "rlz/lib/string_utils.h"
|
||||
|
||||
namespace rlz_lib {
|
||||
|
||||
bool BytesToString(const unsigned char* data,
|
||||
int data_len,
|
||||
std::string* string) {
|
||||
if (!string)
|
||||
return false;
|
||||
|
||||
string->clear();
|
||||
if (data_len < 1 || !data)
|
||||
return false;
|
||||
|
||||
static const char kHex[] = "0123456789ABCDEF";
|
||||
|
||||
// Fix the buffer size to begin with to avoid repeated re-allocation.
|
||||
string->resize(data_len * 2);
|
||||
int index = data_len;
|
||||
while (index--) {
|
||||
string->at(2 * index) = kHex[data[index] >> 4]; // high digit
|
||||
string->at(2 * index + 1) = kHex[data[index] & 0x0F]; // low digit
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace rlz_lib
|
|
@ -0,0 +1,20 @@
|
|||
// Copyright 2010 Google Inc. All Rights Reserved.
|
||||
// Use of this source code is governed by an Apache-style license that can be
|
||||
// found in the COPYING file.
|
||||
//
|
||||
// String manipulation functions used in the RLZ library.
|
||||
|
||||
#ifndef RLZ_LIB_STRING_UTILS_H_
|
||||
#define RLZ_LIB_STRING_UTILS_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace rlz_lib {
|
||||
|
||||
bool BytesToString(const unsigned char* data,
|
||||
int data_len,
|
||||
std::string* string);
|
||||
|
||||
}; // namespace
|
||||
|
||||
#endif // RLZ_LIB_STRING_UTILS_H_
|
|
@ -0,0 +1,20 @@
|
|||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
# Note: build rlz in its own moz.build, so it doesn't pickup any of
|
||||
# Chromium IPC's headers used in the moz.build of the parent file.
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'lib/string_utils.cc',
|
||||
'win/lib/machine_id_win.cc',
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
'..',
|
||||
]
|
|
@ -0,0 +1,131 @@
|
|||
// Copyright 2011 Google Inc. All Rights Reserved.
|
||||
// Use of this source code is governed by an Apache-style license that can be
|
||||
// found in the COPYING file.
|
||||
|
||||
#include <windows.h>
|
||||
#include <Sddl.h> // For ConvertSidToStringSidW.
|
||||
#include <string>
|
||||
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "base/string16.h"
|
||||
#include "rlz/lib/assert.h"
|
||||
|
||||
namespace rlz_lib {
|
||||
|
||||
namespace {
|
||||
|
||||
bool GetSystemVolumeSerialNumber(int* number) {
|
||||
if (!number)
|
||||
return false;
|
||||
|
||||
*number = 0;
|
||||
|
||||
// Find the system root path (e.g: C:\).
|
||||
wchar_t system_path[MAX_PATH + 1];
|
||||
if (!GetSystemDirectoryW(system_path, MAX_PATH))
|
||||
return false;
|
||||
|
||||
wchar_t* first_slash = wcspbrk(system_path, L"\\/");
|
||||
if (first_slash != NULL)
|
||||
*(first_slash + 1) = 0;
|
||||
|
||||
DWORD number_local = 0;
|
||||
if (!GetVolumeInformationW(system_path, NULL, 0, &number_local, NULL, NULL,
|
||||
NULL, 0))
|
||||
return false;
|
||||
|
||||
*number = (int)number_local;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetComputerSid(const wchar_t* account_name, SID* sid, DWORD sid_size) {
|
||||
static const DWORD kStartDomainLength = 128; // reasonable to start with
|
||||
|
||||
scoped_array<wchar_t> domain_buffer(new wchar_t[kStartDomainLength]);
|
||||
DWORD domain_size = kStartDomainLength;
|
||||
DWORD sid_dword_size = sid_size;
|
||||
SID_NAME_USE sid_name_use;
|
||||
|
||||
BOOL success = ::LookupAccountNameW(NULL, account_name, sid,
|
||||
&sid_dword_size, domain_buffer.get(),
|
||||
&domain_size, &sid_name_use);
|
||||
if (!success && ::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
|
||||
// We could have gotten the insufficient buffer error because
|
||||
// one or both of sid and szDomain was too small. Check for that
|
||||
// here.
|
||||
if (sid_dword_size > sid_size)
|
||||
return false;
|
||||
|
||||
if (domain_size > kStartDomainLength)
|
||||
domain_buffer.reset(new wchar_t[domain_size]);
|
||||
|
||||
success = ::LookupAccountNameW(NULL, account_name, sid, &sid_dword_size,
|
||||
domain_buffer.get(), &domain_size,
|
||||
&sid_name_use);
|
||||
}
|
||||
|
||||
return success != FALSE;
|
||||
}
|
||||
|
||||
std::wstring ConvertSidToString(SID* sid) {
|
||||
std::wstring sid_string;
|
||||
#if _WIN32_WINNT >= 0x500
|
||||
wchar_t* sid_buffer = NULL;
|
||||
if (ConvertSidToStringSidW(sid, &sid_buffer)) {
|
||||
sid_string = sid_buffer;
|
||||
LocalFree(sid_buffer);
|
||||
}
|
||||
#else
|
||||
SID_IDENTIFIER_AUTHORITY* sia = ::GetSidIdentifierAuthority(sid);
|
||||
|
||||
if(sia->Value[0] || sia->Value[1]) {
|
||||
base::SStringPrintf(
|
||||
&sid_string, L"S-%d-0x%02hx%02hx%02hx%02hx%02hx%02hx",
|
||||
SID_REVISION, (USHORT)sia->Value[0], (USHORT)sia->Value[1],
|
||||
(USHORT)sia->Value[2], (USHORT)sia->Value[3], (USHORT)sia->Value[4],
|
||||
(USHORT)sia->Value[5]);
|
||||
} else {
|
||||
ULONG authority = 0;
|
||||
for (int i = 2; i < 6; ++i) {
|
||||
authority <<= 8;
|
||||
authority |= sia->Value[i];
|
||||
}
|
||||
base::SStringPrintf(&sid_string, L"S-%d-%lu", SID_REVISION, authority);
|
||||
}
|
||||
|
||||
int sub_auth_count = *::GetSidSubAuthorityCount(sid);
|
||||
for(int i = 0; i < sub_auth_count; ++i)
|
||||
base::StringAppendF(&sid_string, L"-%lu", *::GetSidSubAuthority(sid, i));
|
||||
#endif
|
||||
|
||||
return sid_string;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool GetRawMachineId(string16* sid_string, int* volume_id) {
|
||||
// Calculate the Windows SID.
|
||||
|
||||
wchar_t computer_name[MAX_COMPUTERNAME_LENGTH + 1] = {0};
|
||||
DWORD size = arraysize(computer_name);
|
||||
|
||||
if (!GetComputerNameW(computer_name, &size)) {
|
||||
return false;
|
||||
}
|
||||
char sid_buffer[SECURITY_MAX_SID_SIZE];
|
||||
SID* sid = reinterpret_cast<SID*>(sid_buffer);
|
||||
if (GetComputerSid(computer_name, sid, SECURITY_MAX_SID_SIZE)) {
|
||||
*sid_string = ConvertSidToString(sid);
|
||||
}
|
||||
|
||||
// Get the system drive volume serial number.
|
||||
*volume_id = 0;
|
||||
if (!GetSystemVolumeSerialNumber(volume_id)) {
|
||||
ASSERT_STRING("GetMachineId: Failed to retrieve volume serial number");
|
||||
*volume_id = 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace rlz_lib
|
|
@ -350,7 +350,7 @@ skip-if = toolkit == 'gonk' && debug
|
|||
[test_delay_load.html]
|
||||
skip-if = buildapp == 'b2g' # bug 1021676
|
||||
[test_encryptedMediaExtensions.html]
|
||||
skip-if = buildapp == 'b2g' || toolkit == 'android' # bug 1043403
|
||||
skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s # bug 1043403, bug 1057908
|
||||
[test_error_in_video_document.html]
|
||||
skip-if = toolkit == 'android' # bug 608634
|
||||
[test_error_on_404.html]
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
#include "mozilla/dom/DOMException.h"
|
||||
|
||||
#include "jsprf.h"
|
||||
#include "js/OldDebugAPI.h"
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/HoldDropJSObjects.h"
|
||||
#include "mozilla/dom/Exceptions.h"
|
||||
|
|
|
@ -45,7 +45,6 @@
|
|||
// Helper Classes
|
||||
#include "nsJSUtils.h"
|
||||
#include "jsapi.h" // for JSAutoRequest
|
||||
#include "js/OldDebugAPI.h" // for JS_ClearWatchPointsForObject
|
||||
#include "jswrapper.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include "nsDOMClassInfo.h"
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
|
||||
#include "xpcpublic.h"
|
||||
|
||||
#include "js/OldDebugAPI.h"
|
||||
#include "jsapi.h"
|
||||
#include "jswrapper.h"
|
||||
#include "nsIArray.h"
|
||||
#include "nsIObjectInputStream.h"
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
|
||||
#include "nsJSUtils.h"
|
||||
#include "jsapi.h"
|
||||
#include "js/OldDebugAPI.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "nsIScriptContext.h"
|
||||
#include "nsIScriptGlobalObject.h"
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
|
||||
#include "AccessCheck.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "js/OldDebugAPI.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsGlobalWindow.h"
|
||||
#include "nsIDOMGlobalPropertyInitializer.h"
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
#include "mozilla/dom/Exceptions.h"
|
||||
|
||||
#include "js/GCAPI.h"
|
||||
#include "js/OldDebugAPI.h"
|
||||
#include "jsapi.h"
|
||||
#include "jsprf.h"
|
||||
#include "mozilla/CycleCollectedJSRuntime.h"
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
#include "jsapi.h"
|
||||
#include "js/CharacterEncoding.h"
|
||||
#include "js/OldDebugAPI.h"
|
||||
#include "nsJSON.h"
|
||||
#include "nsIXPConnect.h"
|
||||
#include "nsIXPCScriptable.h"
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/PromiseNativeHandler.h"
|
||||
|
||||
#include "js/OldDebugAPI.h"
|
||||
#include "jsapi.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
#include "RuntimeService.h"
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "js/OldDebugAPI.h"
|
||||
#include "mozilla/dom/RegisterWorkerBindings.h"
|
||||
#include "mozilla/OSFileConstants.h"
|
||||
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
#include <algorithm>
|
||||
#include "BackgroundChild.h"
|
||||
#include "GeckoProfiler.h"
|
||||
#include "js/OldDebugAPI.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/CycleCollectedJSRuntime.h"
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
|
||||
#include <algorithm>
|
||||
#include "jsfriendapi.h"
|
||||
#include "js/OldDebugAPI.h"
|
||||
#include "js/MemoryMetrics.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
#include "nsXBLSerialize.h"
|
||||
|
||||
#include "jsfriendapi.h"
|
||||
#include "js/OldDebugAPI.h"
|
||||
#include "nsXBLPrototypeBinding.h"
|
||||
#include "nsIXPConnect.h"
|
||||
#include "nsContentUtils.h"
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
#include "base/basictypes.h"
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "js/OldDebugAPI.h"
|
||||
|
||||
#include "xpcpublic.h"
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
#include "jsapi.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "jswrapper.h"
|
||||
#include "js/OldDebugAPI.h"
|
||||
#include "mozilla/ModuleUtils.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsMemory.h"
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
#include "nsString.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "js/OldDebugAPI.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace jsipc {
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef js_OldDebugAPI_h
|
||||
#define js_OldDebugAPI_h
|
||||
|
||||
/*
|
||||
* JS debugger API.
|
||||
*/
|
||||
|
||||
#include "mozilla/NullPtr.h"
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "jsbytecode.h"
|
||||
|
||||
#include "js/CallArgs.h"
|
||||
#include "js/TypeDecls.h"
|
||||
|
||||
typedef enum JSTrapStatus {
|
||||
JSTRAP_ERROR,
|
||||
JSTRAP_CONTINUE,
|
||||
JSTRAP_RETURN,
|
||||
JSTRAP_THROW,
|
||||
JSTRAP_LIMIT
|
||||
} JSTrapStatus;
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
extern JS_PUBLIC_API(JSScript *)
|
||||
JS_GetFunctionScript(JSContext *cx, JS::HandleFunction fun);
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
extern JS_PUBLIC_API(const char *)
|
||||
JS_GetScriptFilename(JSScript *script);
|
||||
|
||||
extern JS_PUBLIC_API(unsigned)
|
||||
JS_GetScriptBaseLineNumber(JSContext *cx, JSScript *script);
|
||||
|
||||
#endif /* js_OldDebugAPI_h */
|
|
@ -75,14 +75,7 @@ EvalCacheHashPolicy::match(const EvalCacheEntry &cacheEntry, const EvalCacheLook
|
|||
cacheEntry.pc == l.pc;
|
||||
}
|
||||
|
||||
// There are two things we want to do with each script executed in EvalKernel:
|
||||
// 1. notify OldDebugAPI about script creation/destruction
|
||||
// 2. add the script to the eval cache when EvalKernel is finished
|
||||
//
|
||||
// NB: Although the eval cache keeps a script alive wrt to the JS engine, from
|
||||
// an OldDebugAPI user's perspective, we want each eval() to create and
|
||||
// destroy a script. This hides implementation details and means we don't have
|
||||
// to deal with calls to JS_GetScriptObject for scripts in the eval cache.
|
||||
// Add the script to the eval cache when EvalKernel is finished
|
||||
class EvalScriptGuard
|
||||
{
|
||||
JSContext *cx_;
|
||||
|
|
|
@ -92,7 +92,7 @@ LBlock::init(TempAllocator &alloc)
|
|||
|
||||
// Allocate space for the LPhis.
|
||||
if (!phis_.init(alloc, numLPhis))
|
||||
return nullptr;
|
||||
return false;
|
||||
|
||||
// For each MIR phi, set up LIR phis as appropriate. We'll fill in their
|
||||
// operands on each incoming edge, and set their definitions at the start of
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "jsfriendapi.h"
|
||||
#include "js/OldDebugAPI.h"
|
||||
#include "jsapi-tests/tests.h"
|
||||
|
||||
BEGIN_TEST(test_cloneScript)
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
#include "jscntxt.h"
|
||||
|
||||
#include "js/OldDebugAPI.h"
|
||||
#include "jsapi-tests/tests.h"
|
||||
|
||||
using namespace js;
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
#include "jsfriendapi.h"
|
||||
|
||||
#include "js/OldDebugAPI.h"
|
||||
#include "jsapi-tests/tests.h"
|
||||
|
||||
using namespace js;
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
#include "js/Id.h"
|
||||
/* LegacyIntTypes.h is deliberately exempted from this requirement */
|
||||
#include "js/MemoryMetrics.h"
|
||||
#include "js/OldDebugAPI.h"
|
||||
#include "js/ProfilingStack.h"
|
||||
#include "js/PropertyKey.h"
|
||||
#include "js/RequiredDefines.h"
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "jsfriendapi.h"
|
||||
#include "js/OldDebugAPI.h"
|
||||
#include "jsapi-tests/tests.h"
|
||||
|
||||
static bool sErrorReportMuted = false;
|
||||
|
|
|
@ -5,7 +5,8 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "js/OldDebugAPI.h"
|
||||
#include "jsapi.h"
|
||||
|
||||
#include "jsapi-tests/tests.h"
|
||||
|
||||
const char code[] =
|
||||
|
|
|
@ -4593,6 +4593,36 @@ JS_GetGlobalFromScript(JSScript *script)
|
|||
return &script->global();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(const char *)
|
||||
JS_GetScriptFilename(JSScript *script)
|
||||
{
|
||||
// This is called from ThreadStackHelper which can be called from another
|
||||
// thread or inside a signal hander, so we need to be careful in case a
|
||||
// copmacting GC is currently moving things around.
|
||||
return script->maybeForwardedFilename();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(unsigned)
|
||||
JS_GetScriptBaseLineNumber(JSContext *cx, JSScript *script)
|
||||
{
|
||||
return script->lineno();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSScript *)
|
||||
JS_GetFunctionScript(JSContext *cx, HandleFunction fun)
|
||||
{
|
||||
if (fun->isNative())
|
||||
return nullptr;
|
||||
if (fun->isInterpretedLazy()) {
|
||||
AutoCompartment funCompartment(cx, fun);
|
||||
JSScript *script = fun->getOrCreateScript(cx);
|
||||
if (!script)
|
||||
MOZ_CRASH();
|
||||
return script;
|
||||
}
|
||||
return fun->nonLazyScript();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::CompileFunction(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &options,
|
||||
const char *name, unsigned nargs, const char *const *argnames,
|
||||
|
|
|
@ -3473,6 +3473,15 @@ JS_CompileUCScript(JSContext *cx, JS::HandleObject obj,
|
|||
extern JS_PUBLIC_API(JSObject *)
|
||||
JS_GetGlobalFromScript(JSScript *script);
|
||||
|
||||
extern JS_PUBLIC_API(const char *)
|
||||
JS_GetScriptFilename(JSScript *script);
|
||||
|
||||
extern JS_PUBLIC_API(unsigned)
|
||||
JS_GetScriptBaseLineNumber(JSContext *cx, JSScript *script);
|
||||
|
||||
extern JS_PUBLIC_API(JSScript *)
|
||||
JS_GetFunctionScript(JSContext *cx, JS::HandleFunction fun);
|
||||
|
||||
/*
|
||||
* |fun| will always be set. On failure, it will be set to nullptr.
|
||||
*/
|
||||
|
|
|
@ -41,7 +41,6 @@
|
|||
#include "gc/Marking.h"
|
||||
#include "jit/Ion.h"
|
||||
#include "js/CharacterEncoding.h"
|
||||
#include "js/OldDebugAPI.h"
|
||||
#include "vm/Debugger.h"
|
||||
#include "vm/HelperThreads.h"
|
||||
#include "vm/Shape.h"
|
||||
|
|
|
@ -44,7 +44,6 @@
|
|||
#include "gc/Marking.h"
|
||||
#include "jit/BaselineJIT.h"
|
||||
#include "js/MemoryMetrics.h"
|
||||
#include "js/OldDebugAPI.h"
|
||||
#include "vm/ArgumentsObject.h"
|
||||
#include "vm/Interpreter.h"
|
||||
#include "vm/ProxyObject.h"
|
||||
|
|
|
@ -37,7 +37,6 @@
|
|||
#include "jit/Ion.h"
|
||||
#include "jit/IonCode.h"
|
||||
#include "js/MemoryMetrics.h"
|
||||
#include "js/OldDebugAPI.h"
|
||||
#include "js/Utility.h"
|
||||
#include "vm/ArgumentsObject.h"
|
||||
#include "vm/Compression.h"
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
|
||||
#include "gc/Barrier.h"
|
||||
#include "js/HashTable.h"
|
||||
#include "js/OldDebugAPI.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
|
|
|
@ -75,7 +75,6 @@ EXPORTS.js += [
|
|||
'../public/Id.h',
|
||||
'../public/LegacyIntTypes.h',
|
||||
'../public/MemoryMetrics.h',
|
||||
'../public/OldDebugAPI.h',
|
||||
'../public/Principals.h',
|
||||
'../public/ProfilingFrameIterator.h',
|
||||
'../public/ProfilingStack.h',
|
||||
|
@ -252,7 +251,6 @@ UNIFIED_SOURCES += [
|
|||
'vm/MemoryMetrics.cpp',
|
||||
'vm/Monitor.cpp',
|
||||
'vm/NativeObject.cpp',
|
||||
'vm/OldDebugAPI.cpp',
|
||||
'vm/PIC.cpp',
|
||||
'vm/Probes.cpp',
|
||||
'vm/PropertyKey.cpp',
|
||||
|
|
|
@ -64,7 +64,6 @@
|
|||
#include "jit/arm/Simulator-arm.h"
|
||||
#include "jit/Ion.h"
|
||||
#include "js/Debug.h"
|
||||
#include "js/OldDebugAPI.h"
|
||||
#include "js/StructuredClone.h"
|
||||
#include "perf/jsperf.h"
|
||||
#include "shell/jsheaptools.h"
|
||||
|
|
|
@ -21,6 +21,14 @@
|
|||
#include "vm/GlobalObject.h"
|
||||
#include "vm/SavedStacks.h"
|
||||
|
||||
typedef enum JSTrapStatus {
|
||||
JSTRAP_ERROR,
|
||||
JSTRAP_CONTINUE,
|
||||
JSTRAP_RETURN,
|
||||
JSTRAP_THROW,
|
||||
JSTRAP_LIMIT
|
||||
} JSTrapStatus;
|
||||
|
||||
namespace js {
|
||||
|
||||
class Breakpoint;
|
||||
|
|
|
@ -34,7 +34,6 @@
|
|||
#include "jit/BaselineJIT.h"
|
||||
#include "jit/Ion.h"
|
||||
#include "jit/IonAnalysis.h"
|
||||
#include "js/OldDebugAPI.h"
|
||||
#include "vm/Debugger.h"
|
||||
#include "vm/Opcodes.h"
|
||||
#include "vm/Shape.h"
|
||||
|
|
|
@ -1,72 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/*
|
||||
* JS debugging API.
|
||||
*/
|
||||
|
||||
#include "js/OldDebugAPI.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "jscntxt.h"
|
||||
#include "jsfun.h"
|
||||
#include "jsgc.h"
|
||||
#include "jsobj.h"
|
||||
#include "jsopcode.h"
|
||||
#include "jsprf.h"
|
||||
#include "jsscript.h"
|
||||
#include "jsstr.h"
|
||||
#include "jstypes.h"
|
||||
|
||||
#include "frontend/SourceNotes.h"
|
||||
#include "vm/Debugger.h"
|
||||
#include "vm/Shape.h"
|
||||
|
||||
#include "jsatominlines.h"
|
||||
#include "jsinferinlines.h"
|
||||
#include "jsscriptinlines.h"
|
||||
|
||||
#include "vm/Debugger-inl.h"
|
||||
#include "vm/Interpreter-inl.h"
|
||||
#include "vm/Stack-inl.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::gc;
|
||||
|
||||
using mozilla::PodZero;
|
||||
|
||||
JS_PUBLIC_API(JSScript *)
|
||||
JS_GetFunctionScript(JSContext *cx, HandleFunction fun)
|
||||
{
|
||||
if (fun->isNative())
|
||||
return nullptr;
|
||||
if (fun->isInterpretedLazy()) {
|
||||
AutoCompartment funCompartment(cx, fun);
|
||||
JSScript *script = fun->getOrCreateScript(cx);
|
||||
if (!script)
|
||||
MOZ_CRASH();
|
||||
return script;
|
||||
}
|
||||
return fun->nonLazyScript();
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
JS_PUBLIC_API(const char *)
|
||||
JS_GetScriptFilename(JSScript *script)
|
||||
{
|
||||
// This is called from ThreadStackHelper which can be called from another
|
||||
// thread or inside a signal hander, so we need to be careful in case a
|
||||
// copmacting GC is currently moving things around.
|
||||
return script->maybeForwardedFilename();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(unsigned)
|
||||
JS_GetScriptBaseLineNumber(JSContext *cx, JSScript *script)
|
||||
{
|
||||
return script->lineno();
|
||||
}
|
|
@ -17,7 +17,6 @@
|
|||
#ifdef CHECK_OSIPOINT_REGISTERS
|
||||
#include "jit/Registers.h" // for RegisterDump
|
||||
#endif
|
||||
#include "js/OldDebugAPI.h"
|
||||
|
||||
struct JSCompartment;
|
||||
struct JSGenerator;
|
||||
|
|
|
@ -45,8 +45,6 @@
|
|||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
|
||||
#include "js/OldDebugAPI.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::scache;
|
||||
using namespace xpc;
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
|
||||
#include "jsapi.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "js/OldDebugAPI.h"
|
||||
|
||||
#include "nsJSPrincipals.h"
|
||||
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
|
||||
#include "jsapi.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "js/OldDebugAPI.h"
|
||||
#include "nsJSPrincipals.h"
|
||||
#include "xpcprivate.h" // For xpc::OptionsBase
|
||||
#include "jswrapper.h"
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
#include "AccessCheck.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "jsproxy.h"
|
||||
#include "js/OldDebugAPI.h"
|
||||
#include "js/StructuredClone.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsGlobalWindow.h"
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
#include "xpcprivate.h"
|
||||
#include "jsprf.h"
|
||||
#include "js/OldDebugAPI.h"
|
||||
|
||||
#ifdef XP_WIN
|
||||
#include <windows.h>
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
#include "jsfriendapi.h"
|
||||
#include "jsprf.h"
|
||||
#include "js/MemoryMetrics.h"
|
||||
#include "js/OldDebugAPI.h"
|
||||
#include "mozilla/dom/GeneratedAtomList.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
#include "jsapi.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "jsprf.h"
|
||||
#include "js/OldDebugAPI.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#include "xpcprivate.h"
|
||||
#include "XPCWrapper.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "js/OldDebugAPI.h"
|
||||
#include "nsJSEnvironment.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsDOMJSUtils.h"
|
||||
|
|
|
@ -171,7 +171,7 @@ WebrtcGmpVideoEncoder::InitEncode_g(const webrtc::VideoCodec* aCodecSettings,
|
|||
nsTArray<nsCString> tags;
|
||||
tags.AppendElement(NS_LITERAL_CSTRING("h264"));
|
||||
if (NS_WARN_IF(NS_FAILED(mMPS->GetGMPVideoEncoder(&tags,
|
||||
NS_LITERAL_STRING(""),
|
||||
NS_LITERAL_CSTRING(""),
|
||||
&mHost,
|
||||
&mGMP)))) {
|
||||
mMPS = nullptr;
|
||||
|
@ -255,7 +255,7 @@ WebrtcGmpVideoEncoder::Encode_g(const webrtc::I420VideoFrame* aInputImage,
|
|||
nsTArray<nsCString> tags;
|
||||
tags.AppendElement(NS_LITERAL_CSTRING("h264"));
|
||||
if (NS_WARN_IF(NS_FAILED(mMPS->GetGMPVideoEncoder(&tags,
|
||||
NS_LITERAL_STRING(""),
|
||||
NS_LITERAL_CSTRING(""),
|
||||
&mHost,
|
||||
&mGMP)))) {
|
||||
mGMP = nullptr;
|
||||
|
@ -558,7 +558,7 @@ WebrtcGmpVideoDecoder::InitDecode_g(const webrtc::VideoCodec* aCodecSettings,
|
|||
nsTArray<nsCString> tags;
|
||||
tags.AppendElement(NS_LITERAL_CSTRING("h264"));
|
||||
if (NS_WARN_IF(NS_FAILED(mMPS->GetGMPVideoDecoder(&tags,
|
||||
NS_LITERAL_STRING(""),
|
||||
NS_LITERAL_CSTRING(""),
|
||||
&mHost,
|
||||
&mGMP)))) {
|
||||
mMPS = nullptr;
|
||||
|
|
|
@ -203,7 +203,7 @@ int VcmSIPCCBinding::getVideoCodecsGmp()
|
|||
// H.264 only for now
|
||||
bool has_gmp;
|
||||
nsresult rv;
|
||||
rv = gSelf->mGMPService->HasPluginForAPI(NS_LITERAL_STRING(""),
|
||||
rv = gSelf->mGMPService->HasPluginForAPI(NS_LITERAL_CSTRING(""),
|
||||
NS_LITERAL_CSTRING("encode-video"),
|
||||
&tags,
|
||||
&has_gmp);
|
||||
|
@ -211,7 +211,7 @@ int VcmSIPCCBinding::getVideoCodecsGmp()
|
|||
return 0;
|
||||
}
|
||||
|
||||
rv = gSelf->mGMPService->HasPluginForAPI(NS_LITERAL_STRING(""),
|
||||
rv = gSelf->mGMPService->HasPluginForAPI(NS_LITERAL_CSTRING(""),
|
||||
NS_LITERAL_CSTRING("decode-video"),
|
||||
&tags,
|
||||
&has_gmp);
|
||||
|
|
|
@ -261,4 +261,4 @@ user_pref("browser.uitour.url", "http://%(server)s/uitour-dummy/tour");
|
|||
user_pref("media.eme.enabled", true);
|
||||
|
||||
// Don't prompt about e10s
|
||||
user_pref("browser.displayedE10SPrompt", 5);
|
||||
user_pref("browser.displayedE10SPrompt.1", 5);
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#include "nsIXPConnect.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "js/OldDebugAPI.h"
|
||||
#include "mozilla/HoldDropJSObjects.h"
|
||||
#include "mozilla/ModuleUtils.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
|
|
|
@ -1,113 +0,0 @@
|
|||
Gross Dynamic Footprint Reports
|
||||
Chris Waterson <waterson@netscape.com>
|
||||
November 16, 2000
|
||||
|
||||
This is a short primer on how to run the ``gross dynamic footprint''
|
||||
reports.
|
||||
|
||||
Win32
|
||||
-----
|
||||
|
||||
I've tried this on Win2K. Should work on NT, probably not 98.
|
||||
|
||||
1. Configure your machine with a ``standard'' mozilla build
|
||||
environment, as described at:
|
||||
|
||||
http://www.mozilla.org/build/win32.html
|
||||
|
||||
Specifically, you'll need the Cygnus tools (GNU make, awk, sed), which
|
||||
can be downloaded from:
|
||||
|
||||
http://sourceware.cygnus.com/cygwin/download.html
|
||||
|
||||
2. Install the Win32 version of GNUplot, avaialable from:
|
||||
|
||||
ftp://ftp.dartmouth.edu/pub/gnuplot/gnuplot3.7cyg.zip
|
||||
|
||||
3. Configure a web server with the ``buster.cgi'' CGI script contained
|
||||
in this directory.
|
||||
|
||||
4. Pull and build a ``release'' build. Besides the normal Win32 flags
|
||||
described on the Win32 build instructions, be sure that you've set the
|
||||
following:
|
||||
|
||||
set BUILD_OPT=1
|
||||
set MOZ_DEBUG=
|
||||
|
||||
That is, MOZ_DEBUG should be unset.
|
||||
|
||||
5. To collect data and build the dynamic footprint graph, type the
|
||||
following command from the mozilla/tools/footprint directory:
|
||||
|
||||
make --unix -fwin32-gdf.mk \
|
||||
BUSTER_URL="http://myserver/cgi-bin/buster.cgi?refresh=10"
|
||||
|
||||
(Replace ``myserver'' with the name of the webserver where you
|
||||
installed ``buster.cgi'' in step 3, above.)
|
||||
|
||||
This should:
|
||||
|
||||
- Build ``wm.exe'', which will spy on memory usage.
|
||||
- Run the winEmbed program over the top 100 URLs (from top100.txt)
|
||||
to generate a file called ``winEmbed.dat''
|
||||
- Run mozilla over the top 100 URLs to generate a file called
|
||||
``mozilla.dat''
|
||||
- Use gnuplot to create a PNG image file called win32-gdf.png
|
||||
|
||||
Linux
|
||||
-----
|
||||
|
||||
1. Configure your machine with a ``standard'' mozilla build
|
||||
environment, as described at:
|
||||
|
||||
http://www.mozilla.org/build/unix.html
|
||||
|
||||
2. Install GNUplot, which is available as an RPM on RedHat-6.2 CDs
|
||||
(probably others, as well).
|
||||
|
||||
3. Configure a web server with the ``buster.cgi'' CGI script contained
|
||||
in this directory.
|
||||
|
||||
4. Pull and build a ``release build''. Here are the settings you
|
||||
should use in your .mozconfig file:
|
||||
|
||||
ac_add_options --enable-optimize
|
||||
ac_add_options --disable-debug
|
||||
ac_add_options --enable-strip-libs
|
||||
|
||||
5. To collect data and build the dynamic footprint graph, type the
|
||||
following command from the mozilla/tools/footprint directory:
|
||||
|
||||
make -flinux-gdf.mk \
|
||||
BUSTER_URL="http://myserver/cgi-bin/buster.cgi?refresh=10"
|
||||
|
||||
(Replace ``myserver'' with the name of the webserver where you
|
||||
installed ``buster.cgi'' in step 3, above.)
|
||||
|
||||
Details, details, details
|
||||
-------------------------
|
||||
|
||||
1. When running these tests, you'll probably want to use predictable
|
||||
cache settings. You can modify $(DIST)/bin/defaults/pref/all.js to
|
||||
tweak settings that will be used by [win|gtk]Embed (these programs
|
||||
ignore profile-specific settings AFAIK). For example, I've used these
|
||||
to try to cull out cache usage altogether:
|
||||
|
||||
pref("browser.cache.disk_cache_size", 0);
|
||||
pref("browser.cache.enable", false);
|
||||
pref("browser.cache.disk.enable", false);
|
||||
pref("browser.cache.memory_cache_size", 0);
|
||||
pref("browser.cache.disk_cache_ssl", false);
|
||||
|
||||
I think the image cache has a pref that you can use to shut it off as
|
||||
well. Haven't found it yet.
|
||||
|
||||
2. If you collect data using Mozilla (as Win32 will do, by default), I
|
||||
recommend using a clean profile for consistency's sake. Otherwise,
|
||||
results will vary based on random stuff like how big your bookmarks
|
||||
are, how big your global history is, whether or not you've started
|
||||
mail, etc.
|
||||
|
||||
3. I removed the ``plugin downloader plugin'' libnullplugin.so, as
|
||||
well as all other plugins, from $(DIST)/bin/plugins so that no plugins
|
||||
would be loaded.
|
|
@ -1,117 +0,0 @@
|
|||
#!/usr/bin/perl
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
# This is a modified version of Chris Hofmann's <chofmann@netscape.com>
|
||||
# infamous "browser buster" test harness. It's a bit simpler (CGI
|
||||
# instead of using cookies; IFRAME instead of FRAMESET), and has some
|
||||
# extra parameters that make it a bit easier to test with, but it's
|
||||
# pretty faithful otherwise.
|
||||
#
|
||||
# It accepts a couple of parameters, including
|
||||
#
|
||||
# file=<filename> Set this to the name of the file containing
|
||||
# the URLs that you want the buster to cycle through. This
|
||||
# might be a security hole, so don't run this script on a
|
||||
# server with s3kret stuff on it, mmkay?
|
||||
#
|
||||
# page=<number> This is used to maintain state, and is the line
|
||||
# number in the file that the buster will pull up in the
|
||||
# IFRAME. Set if by hand if you need to for some reason.
|
||||
#
|
||||
# last=<number> The buster will run until it's exhausted all
|
||||
# the URLs in the file, or until it reaches this line in the
|
||||
# file; e.g., setting it to "5" will load five URLs.
|
||||
#
|
||||
# refresh=<number> The timeout (in seconds) to wait before doing
|
||||
# a page refresh, and thus loading the next URL. Defaults to
|
||||
# thirty.
|
||||
|
||||
use CGI;
|
||||
|
||||
# Find the page'th URL in the file with the specified name
|
||||
sub FindURL($$)
|
||||
{
|
||||
my ($file, $page) = @_;
|
||||
|
||||
open URLS, $file
|
||||
|| die("can't open $::File");
|
||||
|
||||
LINE: while (<URLS>) {
|
||||
next LINE if /^#/;
|
||||
last LINE unless --$page;
|
||||
}
|
||||
|
||||
close URLS;
|
||||
|
||||
chomp;
|
||||
return $_;
|
||||
}
|
||||
|
||||
# Scrape parameters
|
||||
$::Query = new CGI;
|
||||
|
||||
$::File = $::Query->param("file");
|
||||
$::File = "top100.txt" unless $::File;
|
||||
|
||||
$::Page = $::Query->param("page");
|
||||
$::Page = 0 unless $::Page;
|
||||
$::URL = FindURL($::File, ++$::Page);
|
||||
|
||||
$::Last = $::Query->param("last");
|
||||
$::Last = -1 unless $::Last;
|
||||
|
||||
$::Refresh = $::Query->param("refresh");
|
||||
$::Refresh = 30 unless $::Refresh;
|
||||
|
||||
# Header
|
||||
print qq{Content-type: text/html
|
||||
|
||||
<html>
|
||||
<head>
|
||||
};
|
||||
|
||||
# Meat
|
||||
if ($::URL && ($::Page <= $::Last || $::Last == -1)) {
|
||||
# Make a web page that'll load $::URL in an IFRAME, with
|
||||
# a meta-refresh that'll reload us again in short order.
|
||||
print qq{<meta http-equiv="Pragma" content="no-cache">
|
||||
<meta http-equiv="refresh" content="$::Refresh;url=buster.cgi?file=$::File&page=$::Page&last=$::Last&refresh=$::Refresh">
|
||||
<title>BrowserBuster II: $::URL</title>
|
||||
<style type="text/css">
|
||||
body {
|
||||
overflow: hidden;
|
||||
border: 0;
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<script>
|
||||
dump("+++ loading $::URL\\n");
|
||||
</script>
|
||||
<body>
|
||||
};
|
||||
print "$::File: $::URL";
|
||||
if ($::Last != -1) {
|
||||
print " ($::Page of $::Last)<br>";
|
||||
}
|
||||
print qq{
|
||||
<iframe width="100%" height="100%" src="$::URL">
|
||||
};
|
||||
}
|
||||
else {
|
||||
# Make a web page that'll close the current browser
|
||||
# window, terminating the test app.
|
||||
print qq{<head>
|
||||
<title>BrowserBuster II: Done!</title>
|
||||
<body onload="window.close();">
|
||||
All done!
|
||||
};
|
||||
}
|
||||
|
||||
# Footer
|
||||
print qq{</body>
|
||||
</html>
|
||||
};
|
|
@ -1,21 +0,0 @@
|
|||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
BEGIN { COUNT = 1
|
||||
if (TYPE == "") TYPE = "vms";
|
||||
}
|
||||
|
||||
/^[0-9]/ { if (TYPE == "vms") print COUNT, $1;
|
||||
else if (TYPE == "vmd") print COUNT, $4;
|
||||
else if (TYPE == "vmx") print COUNT, $2 + $3;
|
||||
else if (TYPE == "rss") print COUNT, $6;
|
||||
|
||||
COUNT = COUNT + 1;
|
||||
}
|
||||
|
||||
/^ / { print COUNT, "0";
|
||||
COUNT = COUNT + 1; \
|
||||
}
|
||||
|
||||
|
|
@ -1,319 +0,0 @@
|
|||
/* -*- Mode: C++; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/* This program reads an ELF file and computes information about
|
||||
* redundancies.
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <elf.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
char* opt_type = "func";
|
||||
char* opt_section = ".text";
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
static void
|
||||
hexdump(ostream& out, const char* bytes, size_t count)
|
||||
{
|
||||
hex(out);
|
||||
|
||||
size_t off = 0;
|
||||
while (off < count) {
|
||||
out.form("%08lx: ", off);
|
||||
|
||||
const char* p = bytes + off;
|
||||
|
||||
int j = 0;
|
||||
while (j < 16) {
|
||||
out.form("%02x", p[j++] & 0xff);
|
||||
if (j + off >= count)
|
||||
break;
|
||||
|
||||
out.form("%02x ", p[j++] & 0xff);
|
||||
if (j + off >= count)
|
||||
break;
|
||||
}
|
||||
|
||||
// Pad
|
||||
for (; j < 16; ++j)
|
||||
out << ((j%2) ? " " : " ");
|
||||
|
||||
for (j = 0; j < 16; ++j) {
|
||||
if (j + off < count)
|
||||
out.put(isprint(p[j]) ? p[j] : '.');
|
||||
}
|
||||
|
||||
out << endl;
|
||||
off += 16;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
int
|
||||
verify_elf_header(const Elf32_Ehdr* hdr)
|
||||
{
|
||||
if (hdr->e_ident[EI_MAG0] != ELFMAG0
|
||||
|| hdr->e_ident[EI_MAG1] != ELFMAG1
|
||||
|| hdr->e_ident[EI_MAG2] != ELFMAG2
|
||||
|| hdr->e_ident[EI_MAG3] != ELFMAG3) {
|
||||
cerr << "not an elf file" << endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hdr->e_ident[EI_CLASS] != ELFCLASS32) {
|
||||
cerr << "not a 32-bit elf file" << endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hdr->e_ident[EI_DATA] != ELFDATA2LSB) {
|
||||
cerr << "not a little endian elf file" << endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hdr->e_ident[EI_VERSION] != EV_CURRENT) {
|
||||
cerr << "incompatible version" << endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
class elf_symbol : public Elf32_Sym
|
||||
{
|
||||
public:
|
||||
elf_symbol(const Elf32_Sym& sym)
|
||||
{ ::memcpy(static_cast<Elf32_Sym*>(this), &sym, sizeof(Elf32_Sym)); }
|
||||
|
||||
friend bool operator==(const elf_symbol& lhs, const elf_symbol& rhs) {
|
||||
return 0 == ::memcmp(static_cast<const Elf32_Sym*>(&lhs),
|
||||
static_cast<const Elf32_Sym*>(&rhs),
|
||||
sizeof(Elf32_Sym)); }
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
static const char*
|
||||
st_bind(unsigned char info)
|
||||
{
|
||||
switch (ELF32_ST_BIND(info)) {
|
||||
case STB_LOCAL: return "local";
|
||||
case STB_GLOBAL: return "global";
|
||||
case STB_WEAK: return "weak";
|
||||
default: return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static const char*
|
||||
st_type(unsigned char info)
|
||||
{
|
||||
switch (ELF32_ST_TYPE(info)) {
|
||||
case STT_NOTYPE: return "none";
|
||||
case STT_OBJECT: return "object";
|
||||
case STT_FUNC: return "func";
|
||||
case STT_SECTION: return "section";
|
||||
case STT_FILE: return "file";
|
||||
default: return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned char
|
||||
st_type(const char* type)
|
||||
{
|
||||
if (strcmp(type, "none") == 0) {
|
||||
return STT_NOTYPE;
|
||||
}
|
||||
else if (strcmp(type, "object") == 0) {
|
||||
return STT_OBJECT;
|
||||
}
|
||||
else if (strcmp(type, "func") == 0) {
|
||||
return STT_FUNC;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
typedef vector<elf_symbol> elf_symbol_table;
|
||||
typedef map< basic_string<char>, elf_symbol_table > elf_text_map;
|
||||
|
||||
void
|
||||
process_mapping(char* mapping, size_t size)
|
||||
{
|
||||
const Elf32_Ehdr* ehdr = reinterpret_cast<Elf32_Ehdr*>(mapping);
|
||||
if (verify_elf_header(ehdr) < 0)
|
||||
return;
|
||||
|
||||
// find the section headers
|
||||
const Elf32_Shdr* shdrs = reinterpret_cast<Elf32_Shdr*>(mapping + ehdr->e_shoff);
|
||||
|
||||
// find the section header string table, .shstrtab
|
||||
const Elf32_Shdr* shstrtabsh = shdrs + ehdr->e_shstrndx;
|
||||
const char* shstrtab = mapping + shstrtabsh->sh_offset;
|
||||
|
||||
// find the sections we care about
|
||||
const Elf32_Shdr *symtabsh, *strtabsh, *textsh;
|
||||
int textndx;
|
||||
|
||||
for (int i = 0; i < ehdr->e_shnum; ++i) {
|
||||
basic_string<char> name(shstrtab + shdrs[i].sh_name);
|
||||
if (name == opt_section) {
|
||||
textsh = shdrs + i;
|
||||
textndx = i;
|
||||
}
|
||||
else if (name == ".symtab") {
|
||||
symtabsh = shdrs + i;
|
||||
}
|
||||
else if (name == ".strtab") {
|
||||
strtabsh = shdrs + i;
|
||||
}
|
||||
}
|
||||
|
||||
// find the .strtab
|
||||
char* strtab = mapping + strtabsh->sh_offset;
|
||||
|
||||
// find the .text
|
||||
char* text = mapping + textsh->sh_offset;
|
||||
int textaddr = textsh->sh_addr;
|
||||
|
||||
// find the symbol table
|
||||
int nentries = symtabsh->sh_size / sizeof(Elf32_Sym);
|
||||
Elf32_Sym* symtab = reinterpret_cast<Elf32_Sym*>(mapping + symtabsh->sh_offset);
|
||||
|
||||
// look for symbols in the .text section
|
||||
elf_text_map textmap;
|
||||
|
||||
for (int i = 0; i < nentries; ++i) {
|
||||
const Elf32_Sym* sym = symtab + i;
|
||||
if (sym->st_shndx == textndx &&
|
||||
ELF32_ST_TYPE(sym->st_info) == st_type(opt_type) &&
|
||||
sym->st_size) {
|
||||
basic_string<char> functext(text + sym->st_value - textaddr, sym->st_size);
|
||||
|
||||
elf_symbol_table& syms = textmap[functext];
|
||||
if (syms.end() == find(syms.begin(), syms.end(), elf_symbol(*sym)))
|
||||
syms.insert(syms.end(), *sym);
|
||||
}
|
||||
}
|
||||
|
||||
int uniquebytes = 0, totalbytes = 0;
|
||||
int uniquecount = 0, totalcount = 0;
|
||||
|
||||
for (elf_text_map::const_iterator entry = textmap.begin();
|
||||
entry != textmap.end();
|
||||
++entry) {
|
||||
const elf_symbol_table& syms = entry->second;
|
||||
|
||||
if (syms.size() <= 1)
|
||||
continue;
|
||||
|
||||
int sz = syms.begin()->st_size;
|
||||
uniquebytes += sz;
|
||||
totalbytes += sz * syms.size();
|
||||
uniquecount += 1;
|
||||
totalcount += syms.size();
|
||||
|
||||
for (elf_symbol_table::const_iterator sym = syms.begin(); sym != syms.end(); ++sym)
|
||||
cout << strtab + sym->st_name << endl;
|
||||
|
||||
dec(cout);
|
||||
cout << syms.size() << " copies of " << sz << " bytes";
|
||||
cout << " (" << ((syms.size() - 1) * sz) << " redundant bytes)" << endl;
|
||||
|
||||
hexdump(cout, entry->first.data(), entry->first.size());
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
dec(cout);
|
||||
cout << "bytes unique=" << uniquebytes << ", total=" << totalbytes << endl;
|
||||
cout << "entries unique=" << uniquecount << ", total=" << totalcount << endl;
|
||||
}
|
||||
|
||||
void
|
||||
process_file(const char* name)
|
||||
{
|
||||
int fd = open(name, O_RDWR);
|
||||
if (fd >= 0) {
|
||||
struct stat statbuf;
|
||||
if (fstat(fd, &statbuf) >= 0) {
|
||||
size_t size = statbuf.st_size;
|
||||
|
||||
void* mapping = mmap(0, size, PROT_READ, MAP_SHARED, fd, 0);
|
||||
if (mapping != MAP_FAILED) {
|
||||
process_mapping(static_cast<char*>(mapping), size);
|
||||
munmap(mapping, size);
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
usage()
|
||||
{
|
||||
cerr << "foldelf [--section=<section>] [--type=<type>] [file ...]\n\
|
||||
--section, -s the section of the ELF file to scan; defaults\n\
|
||||
to ``.text''. Valid values include any section\n\
|
||||
of the ELF file.\n\
|
||||
--type, -t the type of object to examine in the section;\n\
|
||||
defaults to ``func''. Valid values include\n\
|
||||
``none'', ``func'', or ``object''.\n";
|
||||
|
||||
}
|
||||
|
||||
static struct option opts[] = {
|
||||
{ "type", required_argument, 0, 't' },
|
||||
{ "section", required_argument, 0, 's' },
|
||||
{ "help", no_argument, 0, '?' },
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
while (1) {
|
||||
int option_index = 0;
|
||||
int c = getopt_long(argc, argv, "t:s:", opts, &option_index);
|
||||
|
||||
if (c < 0) break;
|
||||
|
||||
switch (c) {
|
||||
case 't':
|
||||
opt_type = optarg;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
opt_section = optarg;
|
||||
break;
|
||||
|
||||
case '?':
|
||||
usage();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = optind; i < argc; ++i)
|
||||
process_file(argv[i]);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
foldelf: foldelf.cpp
|
||||
$(CXX) -O -o foldelf foldelf.cpp
|
||||
|
||||
clean:
|
||||
rm -f *.o test *.test foldelf *~
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
function regress(DATAPOINTS,SX,SY,SXY,SX2)
|
||||
{
|
||||
b1 = (DATAPOINTS * SXY - SX * SY) / (DATAPOINTS * SX2 - SX * SX);
|
||||
b0 = (SY - b1 * SX ) / DATAPOINTS;
|
||||
return b1 " * x + " b0;
|
||||
}
|
||||
|
||||
BEGIN {
|
||||
if (!Skip) Skip = 0;
|
||||
if (Interval)
|
||||
{
|
||||
Count = 0;
|
||||
IntervalCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
NR>Skip {
|
||||
sx += $1;
|
||||
sy += $2;
|
||||
sxy += $1 * $2;
|
||||
sx2 += $1 * $1;
|
||||
#print NR " " sx " " sy " " sxy " " sx2
|
||||
|
||||
if (Interval)
|
||||
{
|
||||
if(Count == Interval-1)
|
||||
{
|
||||
IntervalCount += 1;
|
||||
|
||||
print NR-Count, "-", NR, ": ", regress(Count,isx,isy,isxy,isx2);
|
||||
|
||||
Count = 0;
|
||||
isx = 0;
|
||||
isy = 0;
|
||||
isxy = 0;
|
||||
isx2 = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
Count += 1;
|
||||
isx += $1;
|
||||
isy += $2;
|
||||
isxy += $1 * $2;
|
||||
isx2 += $1 * $1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
END {
|
||||
if(Interval) {
|
||||
print NR-Count, "-", NR, ": ", regress(Count,isx,isy,isxy,isx2);
|
||||
}
|
||||
print regress(NR-Skip, sx, sy, sxy, sx2);
|
||||
}
|
|
@ -1,93 +0,0 @@
|
|||
# -*- Mode: Makefile -*-
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
# This makefile will run Mozilla (or the program you specify), observe
|
||||
# the program's memory status using the /proc filesystem, and generate
|
||||
# a ``gross dynamic footprint'' graph using gnuplot.
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# make MOZILLA_DIR=<mozilla-dir> PROGRAM=<program> URL=<url>
|
||||
#
|
||||
# e.g.,
|
||||
#
|
||||
# make -flinux-gdf.mk \
|
||||
# MOZILLA_DIR=/export2/waterson/seamonkey-opt/mozilla/dist/bin \
|
||||
# PROGRAM=gtkEmbed \
|
||||
# BUSTER_URL="http://localhost/cgi-bin/buster.cgi?refresh=10"
|
||||
#
|
||||
# To use this program, you'll need to:
|
||||
#
|
||||
# 1. Install gnuplot, e.g., using your RedHat distro.
|
||||
# 2. Install the "buster.cgi" script onto a webserver somewhere
|
||||
# 3. Have a mozilla build.
|
||||
#
|
||||
# You can tweak ``linux.gnuplot.in'' to change the graph's output.
|
||||
|
||||
# This script computes a line using linear regression; its output is
|
||||
# of the form:
|
||||
#
|
||||
# <b1> * x + <b0>
|
||||
#
|
||||
# Where <b1> is the slope and <b0> is the y-intercept.
|
||||
LINEAR_REGRESSION=awk -f linear-regression.awk Skip=5
|
||||
|
||||
INTERVAL=10
|
||||
WATCH=./watch.sh
|
||||
|
||||
MOZILLA_DIR=../../dist/bin
|
||||
PROGRAM=gtkEmbed
|
||||
BUSTER_URL=http://localhost/cgi-bin/buster.cgi?refresh=$(INTERVAL)
|
||||
OUTFILE=linux.dat
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
# Top-level target
|
||||
#
|
||||
all: gdf.png
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
# gtkEmbed
|
||||
#
|
||||
|
||||
.INTERMEDIATE: linux.gnuplot vms.dat vmd.dat vmx.dat rss.dat
|
||||
|
||||
# Create a PNG image using the generated ``linux.gnuplot'' script
|
||||
gdf.png: vms.dat vmd.dat vmx.dat rss.dat linux.gnuplot
|
||||
gnuplot linux.gnuplot
|
||||
|
||||
# Generate a ``gnuplot'' script from ``linux.gnuplot.in'', making
|
||||
# appropriate substitutions as necessary.
|
||||
linux.gnuplot: linux.gnuplot.in vms.dat
|
||||
sed -e "s/@PROGRAM@/$(PROGRAM)/" \
|
||||
-e "s/@VMS-LINE@/`$(LINEAR_REGRESSION) vms.dat`/" \
|
||||
-e "s/@GROWTH-RATE@/`$(LINEAR_REGRESSION) vms.dat | awk '{ printf \"%0.1lf\\n\", $$1; }'`/" \
|
||||
-e "s/@BASE-SIZE@/`$(LINEAR_REGRESSION) vms.dat | awk '{ print $$5 + 2000; }'`/" \
|
||||
linux.gnuplot.in > linux.gnuplot
|
||||
|
||||
# Break the raw data file into temporary files that can be processed
|
||||
# by gnuplot directly.
|
||||
vms.dat: $(OUTFILE)
|
||||
awk -f create_dat.awk TYPE=vms $? > $@
|
||||
|
||||
vmd.dat: $(OUTFILE)
|
||||
awk -f create_dat.awk TYPE=vmd $? > $@
|
||||
|
||||
vmx.dat: $(OUTFILE)
|
||||
awk -f create_dat.awk TYPE=vmx $? > $@
|
||||
|
||||
rss.dat: $(OUTFILE)
|
||||
awk -f create_dat.awk TYPE=rss $? > $@
|
||||
|
||||
# Run $(PROGRAM) to produce $(OUTFILE)
|
||||
$(OUTFILE):
|
||||
LD_LIBRARY_PATH=$(MOZILLA_DIR) \
|
||||
MOZILLA_FIVE_HOME=$(MOZILLA_DIR) \
|
||||
$(WATCH) -i $(INTERVAL) -o $@ $(MOZILLA_DIR)/$(PROGRAM) "$(BUSTER_URL)"
|
||||
|
||||
# Clean up the mess.
|
||||
clean:
|
||||
rm -f $(OUTFILE) gdf.png *~
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
set term png color
|
||||
set output 'gdf.png'
|
||||
set title '@PROGRAM@ - Gross Dynamic Footprint'
|
||||
set xlabel 'Time (sec)'
|
||||
set ylabel 'KB'
|
||||
set key bottom right
|
||||
set label '@GROWTH-RATE@KB/sec' at 5, @BASE-SIZE@
|
||||
plot 'vms.dat' title 'Total VM Size' with line 1,\
|
||||
@VMS-LINE@ notitle with line 1,\
|
||||
'vmd.dat' title 'Data Size' with line 3,\
|
||||
'vmx.dat' title 'Code Size' with line 5,\
|
||||
'rss.dat' title 'Resident Set Size' with line 7
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче