зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to fx-team a=merge
This commit is contained in:
Коммит
f85451e616
|
@ -61,6 +61,7 @@ this.EventManager.prototype = {
|
|||
this.addEventListener('wheel', this, true);
|
||||
this.addEventListener('scroll', this, true);
|
||||
this.addEventListener('resize', this, true);
|
||||
this._preDialogPosition = new WeakMap();
|
||||
}
|
||||
this.present(Presentation.tabStateChanged(null, 'newtab'));
|
||||
|
||||
|
@ -78,6 +79,7 @@ this.EventManager.prototype = {
|
|||
Logger.debug('EventManager.stop');
|
||||
AccessibilityEventObserver.removeListener(this);
|
||||
try {
|
||||
this._preDialogPosition.clear();
|
||||
this.webProgress.removeProgressListener(this);
|
||||
this.removeEventListener('wheel', this, true);
|
||||
this.removeEventListener('scroll', this, true);
|
||||
|
@ -272,8 +274,8 @@ this.EventManager.prototype = {
|
|||
// positioned inside it.
|
||||
break;
|
||||
}
|
||||
this.contentControl.autoMove(
|
||||
aEvent.accessible, { delay: 500 });
|
||||
this._preDialogPosition.set(aEvent.accessible.DOMNode, position);
|
||||
this.contentControl.autoMove(aEvent.accessible, { delay: 500 });
|
||||
break;
|
||||
}
|
||||
case Events.VALUE_CHANGE:
|
||||
|
@ -366,7 +368,8 @@ this.EventManager.prototype = {
|
|||
if (vc.position &&
|
||||
(Utils.getState(vc.position).contains(States.DEFUNCT) ||
|
||||
Utils.isInSubtree(vc.position, acc))) {
|
||||
let position = aEvent.targetPrevSibling || aEvent.targetParent;
|
||||
let position = this._preDialogPosition.get(aEvent.accessible.DOMNode) ||
|
||||
aEvent.targetPrevSibling || aEvent.targetParent;
|
||||
if (!position) {
|
||||
try {
|
||||
position = acc.previousSibling;
|
||||
|
|
|
@ -75,13 +75,13 @@
|
|||
<div>Phone status bar</div>
|
||||
<div id="windows">
|
||||
<button id="back">Back</button>
|
||||
<div id="appframe"></div>
|
||||
<div role="dialog" id="alert" hidden>
|
||||
<h1>This is an alert!</h1>
|
||||
<p>Do you agree?</p>
|
||||
<button onclick="hideAlert()">Yes</button>
|
||||
<button onclick="setTimeout(hideAlert, 500)">Yes</button>
|
||||
<button onclick="hideAlert()">No</button>
|
||||
</div>
|
||||
<div id="appframe"></div>
|
||||
</div>
|
||||
<button id="home">Home</button>
|
||||
</body>
|
||||
|
|
|
@ -179,16 +179,15 @@
|
|||
[ContentMessages.clearCursor, 'AccessFu:CursorCleared'],
|
||||
|
||||
// Open dialog in outer doc, while cursor is also in outer doc
|
||||
[ContentMessages.simpleMoveNext,
|
||||
new ExpectedCursorChange(['Phone status bar', 'Traversal Rule test document'])],
|
||||
[ContentMessages.simpleMoveLast,
|
||||
new ExpectedCursorChange(['Home', {'string': 'pushbutton'}])],
|
||||
[doc.defaultView.showAlert,
|
||||
new ExpectedCursorChange(['This is an alert!',
|
||||
{'string': 'headingLevel', 'args': [1]},
|
||||
{'string': 'dialog'}])],
|
||||
|
||||
[doc.defaultView.hideAlert,
|
||||
new ExpectedCursorChange(["wow",
|
||||
{"string": "headingLevel", "args": [1]}, "such app"])],
|
||||
new ExpectedCursorChange(['Home', {'string': 'pushbutton'}])],
|
||||
|
||||
[ContentMessages.clearCursor, 'AccessFu:CursorCleared'],
|
||||
|
||||
|
@ -204,8 +203,12 @@
|
|||
{'string': 'headingLevel', 'args': [1]},
|
||||
{'string': 'dialog'}])],
|
||||
|
||||
// XXX: Place cursor back where it was.
|
||||
[doc.defaultView.hideAlert,
|
||||
[ContentMessages.simpleMoveNext,
|
||||
new ExpectedCursorChange(['Do you agree?'])],
|
||||
[ContentMessages.simpleMoveNext,
|
||||
new ExpectedCursorChange(['Yes', {'string': 'pushbutton'}])],
|
||||
[ContentMessages.activateCurrent(),
|
||||
new ExpectedClickAction(),
|
||||
new ExpectedCursorChange(
|
||||
['wow', {'string': 'headingLevel', 'args': [1]}, 'such app'])],
|
||||
|
||||
|
|
|
@ -59,3 +59,9 @@
|
|||
<label id="pointerLock-cancel" value="&pointerLock.notification.message;"/>
|
||||
</popupnotificationcontent>
|
||||
</popupnotification>
|
||||
|
||||
#ifdef E10S_TESTING_ONLY
|
||||
<popupnotification id="enable-e10s-notification" hidden="true">
|
||||
<popupnotificationcontent orient="vertical"/>
|
||||
</popupnotification>
|
||||
#endif
|
||||
|
|
|
@ -107,6 +107,11 @@ XPCOMUtils.defineLazyModuleGetter(this, "SignInToWebsiteUX",
|
|||
XPCOMUtils.defineLazyModuleGetter(this, "ContentSearch",
|
||||
"resource:///modules/ContentSearch.jsm");
|
||||
|
||||
#ifdef E10S_TESTING_ONLY
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "UpdateChannel",
|
||||
"resource://gre/modules/UpdateChannel.jsm");
|
||||
#endif
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "ShellService", function() {
|
||||
try {
|
||||
return Cc["@mozilla.org/browser/shell-service;1"].
|
||||
|
@ -2261,12 +2266,15 @@ let DefaultBrowserCheck = {
|
|||
let E10SUINotification = {
|
||||
// Increase this number each time we want to roll out an
|
||||
// e10s testing period to Nightly users.
|
||||
CURRENT_NOTICE_COUNT: 0,
|
||||
CURRENT_NOTICE_COUNT: 1,
|
||||
CURRENT_PROMPT_PREF: "browser.displayedE10SPrompt.1",
|
||||
PREVIOUS_PROMPT_PREF: "browser.displayedE10SPrompt",
|
||||
|
||||
checkStatus: function() {
|
||||
let skipE10sChecks = false;
|
||||
try {
|
||||
skipE10sChecks = Services.prefs.getBoolPref("browser.tabs.remote.autostart.disabled-because-using-a11y");
|
||||
skipE10sChecks = (UpdateChannel.get() != "nightly") ||
|
||||
Services.prefs.getBoolPref("browser.tabs.remote.autostart.disabled-because-using-a11y");
|
||||
} catch(e) {}
|
||||
|
||||
if (skipE10sChecks) {
|
||||
|
@ -2312,17 +2320,26 @@ let E10SUINotification = {
|
|||
|
||||
let e10sPromptShownCount = 0;
|
||||
try {
|
||||
e10sPromptShownCount = Services.prefs.getIntPref("browser.displayedE10SPrompt");
|
||||
e10sPromptShownCount = Services.prefs.getIntPref(this.CURRENT_PROMPT_PREF);
|
||||
} catch(e) {}
|
||||
|
||||
let isHardwareAccelerated = true;
|
||||
try {
|
||||
let win = RecentWindow.getMostRecentBrowserWindow();
|
||||
let winutils = win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
|
||||
isHardwareAccelerated = winutils.layerManagerType != "Basic";
|
||||
} catch (e) {}
|
||||
|
||||
if (!Services.appinfo.inSafeMode &&
|
||||
!Services.appinfo.accessibilityEnabled &&
|
||||
!Services.appinfo.keyboardMayHaveIME &&
|
||||
isHardwareAccelerated &&
|
||||
e10sPromptShownCount < 5) {
|
||||
Services.tm.mainThread.dispatch(() => {
|
||||
try {
|
||||
this._showE10SPrompt();
|
||||
Services.prefs.setIntPref("browser.displayedE10SPrompt", e10sPromptShownCount + 1);
|
||||
Services.prefs.setIntPref(this.CURRENT_PROMPT_PREF, e10sPromptShownCount + 1);
|
||||
Services.prefs.clearUserPref(this.PREVIOUS_PROMPT_PREF);
|
||||
} catch (ex) {
|
||||
Cu.reportError("Failed to show e10s prompt: " + ex);
|
||||
}
|
||||
|
@ -2369,7 +2386,7 @@ let E10SUINotification = {
|
|||
|
||||
let browser = win.gBrowser.selectedBrowser;
|
||||
|
||||
let promptMessage = "Would you like to help us test multiprocess Nightly (e10s)? You can also enable e10s in Nightly preferences.";
|
||||
let promptMessage = "Would you like to help us test multiprocess Nightly (e10s)? You can also enable e10s in Nightly preferences. Notable fixes:";
|
||||
let mainAction = {
|
||||
label: "Enable and Restart",
|
||||
accessKey: "E",
|
||||
|
@ -2389,7 +2406,7 @@ let E10SUINotification = {
|
|||
label: "No thanks",
|
||||
accessKey: "N",
|
||||
callback: function () {
|
||||
Services.prefs.setIntPref("browser.displayedE10SPrompt", 5);
|
||||
Services.prefs.setIntPref(E10SUINotification.CURRENT_PROMPT_PREF, 5);
|
||||
}
|
||||
}
|
||||
];
|
||||
|
@ -2399,7 +2416,21 @@ let E10SUINotification = {
|
|||
persistWhileVisible: true
|
||||
};
|
||||
|
||||
win.PopupNotifications.show(browser, "enable_e10s", promptMessage, null, mainAction, secondaryActions, options);
|
||||
win.PopupNotifications.show(browser, "enable-e10s", promptMessage, null, mainAction, secondaryActions, options);
|
||||
|
||||
let highlights = [
|
||||
"Less crashing!",
|
||||
"Improved add-on compatibility and DevTools",
|
||||
"PDF.js, Web Console, Spellchecking, WebRTC now work"
|
||||
];
|
||||
|
||||
let doorhangerExtraContent = win.document.getElementById("enable-e10s-notification")
|
||||
.querySelector("popupnotificationcontent");
|
||||
for (let highlight of highlights) {
|
||||
let highlightLabel = win.document.createElement("label");
|
||||
highlightLabel.setAttribute("value", highlight);
|
||||
doorhangerExtraContent.appendChild(highlightLabel);
|
||||
}
|
||||
},
|
||||
|
||||
_warnedAboutAccessibility: false,
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
|
||||
#include "js/OldDebugAPI.h"
|
||||
#include "xpcprivate.h"
|
||||
#include "XPCWrapper.h"
|
||||
#include "nsIAppsService.h"
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#include "mozilla/dom/MessageEvent.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
|
||||
#include "js/OldDebugAPI.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsMimeTypes.h"
|
||||
#include "nsIPromptFactory.h"
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
|
||||
#include "jsapi.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "js/OldDebugAPI.h"
|
||||
#include "mozilla/DOMEventTargetHelper.h"
|
||||
#include "mozilla/net/WebSocketChannel.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#include "imgRequestProxy.h"
|
||||
#include "jsapi.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "js/OldDebugAPI.h"
|
||||
#include "js/Value.h"
|
||||
#include "Layers.h"
|
||||
#include "MediaDecoder.h"
|
||||
|
|
|
@ -545,6 +545,11 @@ public:
|
|||
|
||||
|
||||
bool IsEventAttributeName(nsIAtom* aName) MOZ_OVERRIDE;
|
||||
|
||||
// Returns the principal of the "top level" document; the origin displayed
|
||||
// in the URL bar of the browser window.
|
||||
already_AddRefed<nsIPrincipal> GetTopLevelPrincipal();
|
||||
|
||||
#endif // MOZ_EME
|
||||
|
||||
bool MozAutoplayEnabled() const
|
||||
|
|
|
@ -3407,6 +3407,11 @@ void HTMLMediaElement::NotifyDecoderPrincipalChanged()
|
|||
OutputMediaStream* ms = &mOutputStreams[i];
|
||||
ms->mStream->CombineWithPrincipal(principal);
|
||||
}
|
||||
#ifdef MOZ_EME
|
||||
if (mMediaKeys && NS_FAILED(mMediaKeys->CheckPrincipals())) {
|
||||
mMediaKeys->Shutdown();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void HTMLMediaElement::UpdateMediaSize(nsIntSize size)
|
||||
|
@ -4008,16 +4013,34 @@ 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) {
|
||||
mMediaKeys = aMediaKeys;
|
||||
if (mMediaKeys == aMediaKeys) {
|
||||
promise->MaybeResolve(JS::UndefinedHandleValue);
|
||||
return promise.forget();
|
||||
}
|
||||
if (mDecoder) {
|
||||
mDecoder->SetCDMProxy(mMediaKeys->GetCDMProxy());
|
||||
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()
|
||||
|
|
|
@ -142,12 +142,12 @@ nsresult FileBlockCache::ReadFromFile(int64_t aOffset,
|
|||
|
||||
nsresult res = Seek(aOffset);
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
|
||||
aBytesRead = PR_Read(mFD, aDest, aBytesToRead);
|
||||
if (aBytesRead <= 0)
|
||||
return NS_ERROR_FAILURE;
|
||||
mFDCurrentPos += aBytesRead;
|
||||
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -327,7 +327,7 @@ nsresult FileBlockCache::MoveBlock(int32_t aSourceBlockIndex, int32_t aDestBlock
|
|||
// the block to file yet.
|
||||
mChangeIndexList.PushBack(aDestBlockIndex);
|
||||
}
|
||||
|
||||
|
||||
// If the source block hasn't yet been written to file then the dest block
|
||||
// simply contains that same write. Resolve this as a write instead.
|
||||
if (sourceBlock && sourceBlock->IsWrite()) {
|
||||
|
|
|
@ -21,7 +21,7 @@ namespace mozilla {
|
|||
// Manages file I/O for the media cache. Data comes in over the network
|
||||
// via callbacks on the main thread, however we don't want to write the
|
||||
// incoming data to the media cache on the main thread, as this could block
|
||||
// causing UI jank.
|
||||
// causing UI jank.
|
||||
//
|
||||
// So FileBlockCache provides an abstraction for a temporary file accessible
|
||||
// as an array of blocks, which supports a block move operation, and
|
||||
|
|
|
@ -31,7 +31,7 @@ class ReentrantMonitorAutoEnter;
|
|||
* and you don't have much control over the rate. Also, transferring data
|
||||
* over the Internet can be slow and/or unpredictable, so we want to read
|
||||
* ahead to buffer and cache as much data as possible.
|
||||
*
|
||||
*
|
||||
* The job of the media cache is to resolve this impedance mismatch.
|
||||
* The media cache reads data from Necko channels into file-backed storage,
|
||||
* and offers a random-access file-like API to the stream data
|
||||
|
@ -56,25 +56,25 @@ class ReentrantMonitorAutoEnter;
|
|||
* can distribute data to any thread
|
||||
* -- The cache exposes APIs so clients can detect what data is
|
||||
* currently held
|
||||
*
|
||||
*
|
||||
* Note that although HTTP is the most important transport and we only
|
||||
* support transport-level seeking via HTTP byte-ranges, the media cache
|
||||
* works with any kind of Necko channels and provides random access to
|
||||
* cached data even for, e.g., FTP streams.
|
||||
*
|
||||
*
|
||||
* The media cache is not persistent. It does not currently allow
|
||||
* data from one load to be used by other loads, either within the same
|
||||
* browser session or across browser sessions. The media cache file
|
||||
* is marked "delete on close" so it will automatically disappear in the
|
||||
* event of a browser crash or shutdown.
|
||||
*
|
||||
*
|
||||
* The media cache is block-based. Streams are divided into blocks of a
|
||||
* fixed size (currently 4K) and we cache blocks. A single cache contains
|
||||
* blocks for all streams.
|
||||
*
|
||||
*
|
||||
* The cache size is controlled by the media.cache_size preference
|
||||
* (which is in KB). The default size is 500MB.
|
||||
*
|
||||
*
|
||||
* The replacement policy predicts a "time of next use" for each block
|
||||
* in the cache. When we need to free a block, the block with the latest
|
||||
* "time of next use" will be evicted. Blocks are divided into
|
||||
|
@ -108,19 +108,19 @@ class ReentrantMonitorAutoEnter;
|
|||
* next use. READAHEAD_BLOCKS have one linked list per stream, since their
|
||||
* time of next use depends on stream parameters, but the other lists
|
||||
* are global.
|
||||
*
|
||||
*
|
||||
* A block containing a current decoder read point can contain data
|
||||
* both behind and ahead of the read point. It will be classified as a
|
||||
* PLAYED_BLOCK but we will give it special treatment so it is never
|
||||
* evicted --- it actually contains the highest-priority readahead data
|
||||
* as well as played data.
|
||||
*
|
||||
*
|
||||
* "Time of next use" estimates are also used for flow control. When
|
||||
* reading ahead we can predict the time of next use for the data that
|
||||
* will be read. If the predicted time of next use is later then the
|
||||
* prediction for all currently cached blocks, and the cache is full, then
|
||||
* we should suspend reading from the Necko channel.
|
||||
*
|
||||
*
|
||||
* Unfortunately suspending the Necko channel can't immediately stop the
|
||||
* flow of data from the server. First our desire to suspend has to be
|
||||
* transmitted to the server (in practice, Necko stops reading from the
|
||||
|
@ -132,7 +132,7 @@ class ReentrantMonitorAutoEnter;
|
|||
* moving overflowing blocks back into the body of the cache, replacing
|
||||
* less valuable blocks as they become available. We try to avoid simply
|
||||
* discarding overflowing readahead data.
|
||||
*
|
||||
*
|
||||
* All changes to the actual contents of the cache happen on the main
|
||||
* thread, since that's where Necko's notifications happen.
|
||||
*
|
||||
|
@ -142,7 +142,7 @@ class ReentrantMonitorAutoEnter;
|
|||
* the loading of data from the beginning of the file.) The Necko channel
|
||||
* is managed through ChannelMediaResource; MediaCache does not
|
||||
* depend on Necko directly.
|
||||
*
|
||||
*
|
||||
* Every time something changes that might affect whether we want to
|
||||
* read from a Necko channel, or whether we want to seek on the Necko
|
||||
* channel --- such as data arriving or data being consumed by the
|
||||
|
@ -152,20 +152,20 @@ class ReentrantMonitorAutoEnter;
|
|||
* offset we should seek to, if any. It is also responsible for trimming
|
||||
* back the cache size to its desired limit by moving overflowing blocks
|
||||
* into the main part of the cache.
|
||||
*
|
||||
*
|
||||
* Streams can be opened in non-seekable mode. In non-seekable mode,
|
||||
* the cache will only call ChannelMediaResource::CacheClientSeek with
|
||||
* a 0 offset. The cache tries hard not to discard readahead data
|
||||
* for non-seekable streams, since that could trigger a potentially
|
||||
* disastrous re-read of the entire stream. It's up to cache clients
|
||||
* to try to avoid requesting seeks on such streams.
|
||||
*
|
||||
*
|
||||
* MediaCache has a single internal monitor for all synchronization.
|
||||
* This is treated as the lowest level monitor in the media code. So,
|
||||
* we must not acquire any MediaDecoder locks or MediaResource locks
|
||||
* while holding the MediaCache lock. But it's OK to hold those locks
|
||||
* and then get the MediaCache lock.
|
||||
*
|
||||
*
|
||||
* MediaCache associates a principal with each stream. CacheClientSeek
|
||||
* can trigger new HTTP requests; due to redirects to other domains,
|
||||
* each HTTP load can return data with a different principal. This
|
||||
|
@ -178,7 +178,7 @@ class MediaCache;
|
|||
/**
|
||||
* If the cache fails to initialize then Init will fail, so nonstatic
|
||||
* methods of this class can assume gMediaCache is non-null.
|
||||
*
|
||||
*
|
||||
* This class can be directly embedded as a value.
|
||||
*/
|
||||
class MediaCacheStream {
|
||||
|
@ -357,7 +357,7 @@ private:
|
|||
* constant time. We declare this here so that a stream can contain a
|
||||
* BlockList of its read-ahead blocks. Blocks are referred to by index
|
||||
* into the MediaCache::mIndex array.
|
||||
*
|
||||
*
|
||||
* Blocks can belong to more than one list at the same time, because
|
||||
* the next/prev pointers are not stored in the block.
|
||||
*/
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -242,7 +242,7 @@ bool AndroidMediaReader::DecodeVideoFrame(bool &aKeyframeSkip,
|
|||
-1,
|
||||
picture);
|
||||
}
|
||||
|
||||
|
||||
if (!v) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
|
|
@ -1,34 +1,34 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
include protocol PGMP;
|
||||
include GMPTypes;
|
||||
|
||||
using GMPErr from "gmp-errors.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
||||
async protocol PGMPStorage
|
||||
{
|
||||
manager PGMP;
|
||||
|
||||
child:
|
||||
OpenComplete(nsCString aRecordName, GMPErr aStatus);
|
||||
ReadComplete(nsCString aRecordName, GMPErr aStatus, uint8_t[] aBytes);
|
||||
WriteComplete(nsCString aRecordName, GMPErr aStatus);
|
||||
Shutdown();
|
||||
|
||||
parent:
|
||||
Open(nsCString aRecordName);
|
||||
Read(nsCString aRecordName);
|
||||
Write(nsCString aRecordName, uint8_t[] aBytes);
|
||||
Close(nsCString aRecordName);
|
||||
__delete__();
|
||||
|
||||
};
|
||||
|
||||
} // namespace gmp
|
||||
} // namespace mozilla
|
||||
/* -*- 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/. */
|
||||
|
||||
include protocol PGMP;
|
||||
include GMPTypes;
|
||||
|
||||
using GMPErr from "gmp-errors.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace gmp {
|
||||
|
||||
async protocol PGMPStorage
|
||||
{
|
||||
manager PGMP;
|
||||
|
||||
child:
|
||||
OpenComplete(nsCString aRecordName, GMPErr aStatus);
|
||||
ReadComplete(nsCString aRecordName, GMPErr aStatus, uint8_t[] aBytes);
|
||||
WriteComplete(nsCString aRecordName, GMPErr aStatus);
|
||||
Shutdown();
|
||||
|
||||
parent:
|
||||
Open(nsCString aRecordName);
|
||||
Read(nsCString aRecordName);
|
||||
Write(nsCString aRecordName, uint8_t[] aBytes);
|
||||
Close(nsCString aRecordName);
|
||||
__delete__();
|
||||
|
||||
};
|
||||
|
||||
} // namespace gmp
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -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
|
|
@ -297,7 +297,7 @@ TheoraState::DecodeHeader(ogg_packet* aPacket)
|
|||
&mComment,
|
||||
&mSetup,
|
||||
aPacket);
|
||||
|
||||
|
||||
// We must determine when we've read the last header packet.
|
||||
// th_decode_headerin() does not tell us when it's read the last header, so
|
||||
// we must keep track of the headers externally.
|
||||
|
@ -350,7 +350,7 @@ int64_t TheoraState::Time(th_info* aInfo, int64_t aGranulepos)
|
|||
}
|
||||
// Implementation of th_granule_frame inlined here to operate
|
||||
// on the th_info structure instead of the theora_state.
|
||||
int shift = aInfo->keyframe_granule_shift;
|
||||
int shift = aInfo->keyframe_granule_shift;
|
||||
ogg_int64_t iframe = aGranulepos >> shift;
|
||||
ogg_int64_t pframe = aGranulepos - (iframe << shift);
|
||||
int64_t frameno = iframe + pframe - TH_VERSION_CHECK(aInfo, 3, 2, 1);
|
||||
|
@ -380,7 +380,7 @@ TheoraState::MaxKeyframeOffset()
|
|||
// Therefore the maximum possible time by which any frame could be offset
|
||||
// from a keyframe is the duration of (1 << granule_shift) - 1) frames.
|
||||
int64_t frameDuration;
|
||||
|
||||
|
||||
// Max number of frames keyframe could possibly be offset.
|
||||
int64_t keyframeDiff = (1 << mInfo.keyframe_granule_shift) - 1;
|
||||
|
||||
|
@ -492,7 +492,7 @@ void TheoraState::ReconstructTheoraGranulepos()
|
|||
// Theora 3.2.1+ granulepos store frame number [1..N], so granulepos
|
||||
// should be > 0.
|
||||
// Theora 3.2.0 granulepos store the frame index [0..(N-1)], so
|
||||
// granulepos should be >= 0.
|
||||
// granulepos should be >= 0.
|
||||
NS_ASSERTION(granulepos >= version_3_2_1,
|
||||
"Invalid granulepos for Theora version");
|
||||
|
||||
|
@ -724,7 +724,7 @@ nsresult VorbisState::ReconstructVorbisGranulepos()
|
|||
if (packet->e_o_s && packet->granulepos >= mGranulepos) {
|
||||
samples = packet->granulepos - mGranulepos;
|
||||
}
|
||||
|
||||
|
||||
mGranulepos = packet->granulepos;
|
||||
RecordVorbisPacketSamples(packet, samples);
|
||||
return NS_OK;
|
||||
|
@ -1088,7 +1088,7 @@ SkeletonState::SkeletonState(ogg_page* aBosPage) :
|
|||
{
|
||||
MOZ_COUNT_CTOR(SkeletonState);
|
||||
}
|
||||
|
||||
|
||||
SkeletonState::~SkeletonState()
|
||||
{
|
||||
MOZ_COUNT_DTOR(SkeletonState);
|
||||
|
@ -1223,11 +1223,11 @@ bool SkeletonState::DecodeIndex(ogg_packet* aPacket)
|
|||
{
|
||||
return (mActive = false);
|
||||
}
|
||||
|
||||
|
||||
int64_t sizeofIndex = aPacket->bytes - INDEX_KEYPOINT_OFFSET;
|
||||
int64_t maxNumKeyPoints = sizeofIndex / MIN_KEY_POINT_SIZE;
|
||||
if (aPacket->bytes < minPacketSize.value() ||
|
||||
numKeyPoints > maxNumKeyPoints ||
|
||||
numKeyPoints > maxNumKeyPoints ||
|
||||
numKeyPoints < 0)
|
||||
{
|
||||
// Packet size is less than the theoretical minimum size, or the packet is
|
||||
|
@ -1244,7 +1244,7 @@ bool SkeletonState::DecodeIndex(ogg_packet* aPacket)
|
|||
}
|
||||
|
||||
nsAutoPtr<nsKeyFrameIndex> keyPoints(new nsKeyFrameIndex(startTime, endTime));
|
||||
|
||||
|
||||
p = aPacket->packet + INDEX_KEYPOINT_OFFSET;
|
||||
const unsigned char* limit = aPacket->packet + aPacket->bytes;
|
||||
int64_t numKeyPointsRead = 0;
|
||||
|
|
|
@ -65,7 +65,7 @@ nsresult RawReader::ReadMetadata(MediaInfo* aInfo,
|
|||
return NS_ERROR_FAILURE; // Invalid data
|
||||
|
||||
// Determine and verify frame display size.
|
||||
float pixelAspectRatio = static_cast<float>(mMetadata.aspectNumerator) /
|
||||
float pixelAspectRatio = static_cast<float>(mMetadata.aspectNumerator) /
|
||||
mMetadata.aspectDenominator;
|
||||
nsIntSize display(mMetadata.frameWidth, mMetadata.frameHeight);
|
||||
ScaleDisplayByAspectRatio(display, pixelAspectRatio);
|
||||
|
@ -126,7 +126,7 @@ RawReader::IsMediaSeekable()
|
|||
return false;
|
||||
}
|
||||
|
||||
// Helper method that either reads until it gets aLength bytes
|
||||
// Helper method that either reads until it gets aLength bytes
|
||||
// or returns false
|
||||
bool RawReader::ReadFromResource(MediaResource *aResource, uint8_t* aBuf,
|
||||
uint32_t aLength)
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -265,7 +265,7 @@ nsresult WaveReader::Seek(int64_t aTarget, int64_t aStartTime, int64_t aEndTime,
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
double d = BytesToTime(GetDataLength());
|
||||
NS_ASSERTION(d < INT64_MAX / USECS_PER_S, "Duration overflow");
|
||||
NS_ASSERTION(d < INT64_MAX / USECS_PER_S, "Duration overflow");
|
||||
int64_t duration = static_cast<int64_t>(d * USECS_PER_S);
|
||||
double seekTime = std::min(aTarget, duration) / static_cast<double>(USECS_PER_S);
|
||||
int64_t position = RoundDownToFrame(static_cast<int64_t>(TimeToBytes(seekTime)));
|
||||
|
@ -291,7 +291,7 @@ nsresult WaveReader::GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime)
|
|||
NS_ASSERTION(endOffset >= mWavePCMOffset, "Integer underflow in GetBuffered");
|
||||
|
||||
// We need to round the buffered ranges' times to microseconds so that they
|
||||
// have the same precision as the currentTime and duration attribute on
|
||||
// have the same precision as the currentTime and duration attribute on
|
||||
// the media element.
|
||||
aBuffered->Add(RoundToUsecs(BytesToTime(startOffset - mWavePCMOffset)),
|
||||
RoundToUsecs(BytesToTime(endOffset - mWavePCMOffset)));
|
||||
|
|
|
@ -71,20 +71,20 @@ class WebMPacketQueue : private nsDeque {
|
|||
WebMPacketQueue()
|
||||
: nsDeque(new PacketQueueDeallocator())
|
||||
{}
|
||||
|
||||
|
||||
~WebMPacketQueue() {
|
||||
Reset();
|
||||
}
|
||||
|
||||
inline int32_t GetSize() {
|
||||
inline int32_t GetSize() {
|
||||
return nsDeque::GetSize();
|
||||
}
|
||||
|
||||
|
||||
inline void Push(NesteggPacketHolder* aItem) {
|
||||
NS_ASSERTION(aItem, "NULL pushed to WebMPacketQueue");
|
||||
nsDeque::Push(aItem);
|
||||
}
|
||||
|
||||
|
||||
inline void PushFront(NesteggPacketHolder* aItem) {
|
||||
NS_ASSERTION(aItem, "NULL pushed to WebMPacketQueue");
|
||||
nsDeque::PushFront(aItem);
|
||||
|
@ -93,7 +93,7 @@ class WebMPacketQueue : private nsDeque {
|
|||
inline NesteggPacketHolder* PopFront() {
|
||||
return static_cast<NesteggPacketHolder*>(nsDeque::PopFront());
|
||||
}
|
||||
|
||||
|
||||
void Reset() {
|
||||
while (GetSize() > 0) {
|
||||
delete PopFront();
|
||||
|
@ -116,7 +116,7 @@ public:
|
|||
|
||||
// If the Theora granulepos has not been captured, it may read several packets
|
||||
// until one with a granulepos has been captured, to ensure that all packets
|
||||
// read have valid time info.
|
||||
// read have valid time info.
|
||||
virtual bool DecodeVideoFrame(bool &aKeyframeSkip,
|
||||
int64_t aTimeThreshold);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче