This commit is contained in:
Wes Kocher 2014-10-12 21:28:12 -07:00
Родитель 11e9c2c186 2809edb97f
Коммит f85451e616
123 изменённых файлов: 1561 добавлений и 3413 удалений

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

@ -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

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше