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

- Bug 936092, initial DnD support for e10s, r=enndeakin,karlt (3cde556cf)
- Bug 1152066 - Remove ugly dynamic loading code now that we can assume this symbol exists. r=roc (04813dd18)
- Bug 966395 - Correctly propagate the input language's direction on OSX. r=masayuki/mrbkap (14a21fa0c)
- Bug 1158791 - Try harder to avoid Gtk-Critical errors in xpcshell tests. r=karlt (f6cec3b99)
- Bug 1153922 - Add a SandboxOptions option for creating the sandbox in a fresh JS::Zone. r=mrbkap (f99b17726)
- Bug 968520 - Always use fallible allocator with nsTArray_base::ShrinkCapacity. r=froydnj (b7cf63063)
- Bug 1160027 - Move ResourceQueue implementation from header file - r=cpearce (5fabd8c8f)
- Bug 1119277 - Remove the process CPU priority parameter and simplify all the associated code. r=khuey, r=dhylands (32d2b0df2)
- Goanna -> Gecko (2b16bec4c)
- Bug 892371 - Adjust oom_score_adj values for foreground processes according to an LRU policy. r=dhylands, r=khuey (61cdfc3db)
- Bug 892371 - Add mochitests covering LRU priority adjustments for both foreground and background processes. r=khuey (46676e34f)
- Bug 1164297 - tweaks to logging modules of MediaDecoderStateMachine to remove accessing to env vars. r=cpearce. (e9dc910da)
- Bug 1150539: log getUserMedia constraints used in MediaManager:5. r=jesup (161853b66)
- Bug 1139027 - Permit running of camera mochitests on B2G desktop. r=mikeh (8bb265db2)
- Bug 1145403 - Don't open MediaManager on shutdown. r=jesup (9338eef82)
- Bug 1046245 - enumerateDevices w/non-blocking e10s, nsICryptoHMAC, clear cookies, lambdas. r=keeler, florian, billm, jesup (ce9d684a0)
- remove StopWebRtcLoc() to be readded in Bug 1219339 - Part2 (7a0c901fc)
- Bug 1046245 - IO on STS thread + cleanup BackgroundChild on shutdown r=jesup (e85dd7716)
- Bug 579517 follow-up: Remove NSPR types that crept in (35aee15a6)
- Bug 1152443 - Fix broken validation which prevented reading of enumerate_devices.txt. r=jesup (4e135355b)
- Bug 1143562 - use /data/b2g/mozilla/gmp as the gmp storage folder on B2G. r=cpearce. (ddc07f09a)
- Bug 1143562. Part2 - only init |mStorageBaseDir| in the chrome process. r=cpearce (3039a4f44)
- remove specific hack, this code is going away anyway (34aed4d6b)
- Bug 1057908 - GeckoMediaPluginService needs to be proxied from Content processes to parent process. Part 0 - Make mozIGeckoMediaPluginService::GetPluginVersionForAPI return whether we even have the plugin. r=cpearce. (e6ac61630)
- Bug 1057908 - GeckoMediaPluginService needs to be proxied from Content processes to parent process. Part 1 - split GeckoMediaPluginService into a part for chrome and a part for both content and chrome. r=jwwang. (09f8c4a83)
- Bug 1057908 - GeckoMediaPluginService needs to be proxied from Content processes to parent process. Part 2 - support asynchronous GMP API getters. r=jwwang,rjesup. (e33266976)
- Bug 1143532 - Include pid in the log messages of GMPParent. r=edwin (8486ebc50)
- Bug 1057908 - GeckoMediaPluginService needs to be proxied from Content processes to parent process. Part 3 - split the GMP IPDL actors in 2 parts (and use opens to open the second in non-e10s). r=billm. (d17fa36ff)
- Bug 1057908 - GeckoMediaPluginService needs to be proxied from Content processes to parent process. Part 4 - make GetNodeId asynchronous. r=jwwang. (db7a21e4a)
- Bug 1150049 - tidy up nsImageBoxFrame::Init a little bit; r=dholbert (41c258a71)
- Bug 1150266 - fix IPDL thinko for never-inline method declarations; r=bent (445d3420b)
- Bug 1150207 - Convert a focus() call to use SpecialPowers to avoid out-of-order focusing behaviour. r=mwargers (4d134848c)
- Bug 1148641 - Guard against null parameters to SendSetTargetAPZCNotification. r=botond (8c5f4bb6d)
- Bug 1096172 - Fix position reporting of bad charrefs in RCDATA. r=hsivonen. (77100d26d)
- Bug 1149971 Part 2: Cet rid of kCurrentProcessId as it makes lots of static initializers. r=dvander (3efaefdba)
- remove android widgets (0c2565418)
- Bug 1129991 - Remove QuotaManager::SetCurrentWindow(); r=bent (7ccabf88c)
- Bug 1133748 - Fix ipdl code for bridged protocols that are also opened. r=billm. (402751d09)
- Bug 1057908 - GeckoMediaPluginService needs to be proxied from Content processes to parent process. Part 5 - use bridging for GMP in e10s. r=billm. (e45a87c5f)
- Bug 1057908 followup: Add missing 'override' annotation on GMPServiceParent::ActorDestroy method decl. rs=ehsan (48f53b28a)
- Bug 1057908 - GeckoMediaPluginService needs to be proxied from Content processes to parent process. Add nsServiceManagerUtils.h include to WMFDecoderModule.cpp. (67cddb4da)
- kill android widgets better (bec243c8d)
This commit is contained in:
2020-05-30 09:39:20 +08:00
parent 19a820a48c
commit 4ac9bef80d
259 changed files with 8481 additions and 23525 deletions
+5 -4
View File
@@ -640,10 +640,11 @@ pref("dom.ipc.processPriorityManager.backgroundGracePeriodMS", 1000);
pref("dom.ipc.processPriorityManager.backgroundPerceivableGracePeriodMS", 5000);
pref("dom.ipc.processPriorityManager.temporaryPriorityLockMS", 5000);
// Number of different background levels for background processes. We use
// these different levels to force the low-memory killer to kill processes in
// a LRU order.
pref("dom.ipc.processPriorityManager.backgroundLRUPoolLevels", 5);
// Number of different background/foreground levels for background/foreground
// processes. We use these different levels to force the low-memory killer to
// kill processes in a LRU order.
pref("dom.ipc.processPriorityManager.BACKGROUND.LRUPoolLevels", 5);
pref("dom.ipc.processPriorityManager.FOREGROUND.LRUPoolLevels", 3);
// Kernel parameters for process priorities. These affect how processes are
// killed on low-memory and their relative CPU priorities.
+5
View File
@@ -156,6 +156,11 @@ Sanitizer.prototype = {
cookieMgr.removeAll();
}
// Clear deviceIds. Done asynchronously (returns before complete).
let mediaMgr = Components.classes["@mozilla.org/mediaManagerService;1"]
.getService(Ci.nsIMediaManagerService);
mediaMgr.sanitizeDeviceIds(this.range && this.range[0]);
// Clear plugin data.
const phInterface = Ci.nsIPluginHost;
const FLAG_CLEAR_ALL = phInterface.FLAG_CLEAR_ALL;
+2 -2
View File
@@ -1983,8 +1983,8 @@ Navigator::OnNavigation()
}
#ifdef MOZ_MEDIA_NAVIGATOR
// Inform MediaManager in case there are live streams or pending callbacks.
MediaManager *manager = MediaManager::Get();
// If MediaManager is open let it inform any live streams or pending callbacks
MediaManager *manager = MediaManager::GetIfExists();
if (manager) {
manager->OnNavigation(mWindow->WindowID());
}
+16 -1
View File
@@ -32,6 +32,7 @@
#include "nsServiceManagerUtils.h"
#include "nsNetUtil.h"
#include "nsIFile.h"
#include "nsFrameLoader.h"
#include "nsIWebNavigation.h"
#include "nsIDocShell.h"
#include "nsIContent.h"
@@ -52,6 +53,7 @@
#include "mozilla/dom/DataTransfer.h"
#include "nsIMIMEInfo.h"
#include "nsRange.h"
#include "TabParent.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/HTMLAreaElement.h"
@@ -414,8 +416,21 @@ DragDataProducer::Produce(DataTransfer* aDataTransfer,
dsti && dsti->ItemType() == nsIDocShellTreeItem::typeChrome;
// In chrome shells, only allow dragging inside editable areas.
if (isChromeShell && !editingElement)
if (isChromeShell && !editingElement) {
nsCOMPtr<nsIFrameLoaderOwner> flo = do_QueryInterface(mTarget);
if (flo) {
nsRefPtr<nsFrameLoader> fl = flo->GetFrameLoader();
if (fl) {
TabParent* tp = static_cast<TabParent*>(fl->GetRemoteBrowser());
if (tp) {
// We have a TabParent, so it may have data for dnd in case the child
// process started a dnd session.
tp->AddInitialDnDDataTo(aDataTransfer);
}
}
}
return NS_OK;
}
if (isChromeShell && textControl) {
// Only use the selection if the target node is in the selection.
+94
View File
@@ -35,11 +35,14 @@
#include "mozilla/DebugOnly.h"
#include "mozilla/LoadInfo.h"
#include "mozilla/dom/DocumentFragment.h"
#include "mozilla/dom/DOMTypes.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/HTMLMediaElement.h"
#include "mozilla/dom/HTMLTemplateElement.h"
#include "mozilla/dom/HTMLContentElement.h"
#include "mozilla/dom/HTMLShadowElement.h"
#include "mozilla/dom/ipc/BlobChild.h"
#include "mozilla/dom/ipc/BlobParent.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/TabParent.h"
@@ -7365,3 +7368,94 @@ nsContentUtils::InternalContentPolicyTypeToExternalOrCSPInternal(nsContentPolicy
}
void
nsContentUtils::TransferablesToIPCTransferables(nsISupportsArray* aTransferables,
nsTArray<IPCDataTransfer>& aIPC,
mozilla::dom::nsIContentChild* aChild,
mozilla::dom::nsIContentParent* aParent)
{
aIPC.Clear();
MOZ_ASSERT((aChild && !aParent) || (!aChild && aParent));
if (aTransferables) {
uint32_t transferableCount = 0;
aTransferables->Count(&transferableCount);
for (uint32_t i = 0; i < transferableCount; ++i) {
IPCDataTransfer* dt = aIPC.AppendElement();
nsCOMPtr<nsISupports> genericItem;
aTransferables->GetElementAt(i, getter_AddRefs(genericItem));
nsCOMPtr<nsITransferable> item(do_QueryInterface(genericItem));
if (item) {
nsCOMPtr<nsISupportsArray> flavorList;
item->FlavorsTransferableCanExport(getter_AddRefs(flavorList));
if (flavorList) {
uint32_t flavorCount = 0;
flavorList->Count(&flavorCount);
for (uint32_t j = 0; j < flavorCount; ++j) {
nsCOMPtr<nsISupportsCString> flavor = do_QueryElementAt(flavorList, j);
if (!flavor) {
continue;
}
nsAutoCString flavorStr;
flavor->GetData(flavorStr);
if (!flavorStr.Length()) {
continue;
}
nsCOMPtr<nsISupports> data;
uint32_t dataLen = 0;
item->GetTransferData(flavorStr.get(), getter_AddRefs(data), &dataLen);
nsCOMPtr<nsISupportsString> text = do_QueryInterface(data);
if (text) {
nsAutoString dataAsString;
text->GetData(dataAsString);
IPCDataTransferItem* item = dt->items().AppendElement();
item->flavor() = nsCString(flavorStr);
item->data() = nsString(dataAsString);
} else {
nsCOMPtr<nsISupportsInterfacePointer> sip =
do_QueryInterface(data);
if (sip) {
sip->GetData(getter_AddRefs(data));
}
nsCOMPtr<FileImpl> fileImpl;
nsCOMPtr<nsIFile> file = do_QueryInterface(data);
if (file) {
fileImpl = new FileImplFile(file, false);
ErrorResult rv;
fileImpl->GetSize(rv);
fileImpl->GetLastModified(rv);
} else {
fileImpl = do_QueryInterface(data);
}
if (fileImpl) {
IPCDataTransferItem* item = dt->items().AppendElement();
item->flavor() = nsCString(flavorStr);
if (aChild) {
item->data() =
mozilla::dom::BlobChild::GetOrCreate(aChild,
static_cast<FileImpl*>(fileImpl.get()));
} else if (aParent) {
item->data() =
mozilla::dom::BlobParent::GetOrCreate(aParent,
static_cast<FileImpl*>(fileImpl.get()));
}
} else {
// This is a hack to support kFilePromiseMime.
// On Windows there just needs to be an entry for it,
// and for OSX we need to create
// nsContentAreaDragDropDataProvider as nsIFlavorDataProvider.
if (flavorStr.EqualsLiteral(kFilePromiseMime)) {
IPCDataTransferItem* item = dt->items().AppendElement();
item->flavor() = nsCString(flavorStr);
item->data() = NS_ConvertUTF8toUTF16(flavorStr);
}
}
}
}
}
}
}
}
}
+8
View File
@@ -87,6 +87,7 @@ class nsIScriptGlobalObject;
class nsIScriptSecurityManager;
class nsIStringBundle;
class nsIStringBundleService;
class nsISupportsArray;
class nsISupportsHashKey;
class nsIURI;
class nsIWidget;
@@ -120,7 +121,10 @@ namespace dom {
class DocumentFragment;
class Element;
class EventTarget;
class IPCDataTransfer;
class NodeInfo;
class nsIContentChild;
class nsIContentParent;
class Selection;
class TabParent;
} // namespace dom
@@ -2373,6 +2377,10 @@ public:
CallOnRemoteChildFunction aCallback,
void* aArg);
static void TransferablesToIPCTransferables(nsISupportsArray* aTransferables,
nsTArray<mozilla::dom::IPCDataTransfer>& aIPC,
mozilla::dom::nsIContentChild* aChild,
mozilla::dom::nsIContentParent* aParent);
private:
static bool InitializeEventTable();
@@ -1117,9 +1117,9 @@ PackPDU(const BluetoothAvrcpElementAttribute& aIn, BluetoothDaemonPDU& aPDU)
return NS_ERROR_ILLEGAL_VALUE; /* integer overflow detected */
}
PRUint32 clen = cstr.Length() + 1; /* include \0 character */
uint32_t clen = cstr.Length() + 1; /* include \0 character */
rv = PackPDU(PackConversion<PRUint32, uint8_t>(clen), aPDU);
rv = PackPDU(PackConversion<uint32_t, uint8_t>(clen), aPDU);
if (NS_FAILED(rv)) {
return rv;
}
@@ -1070,9 +1070,9 @@ PackPDU(const BluetoothAvrcpElementAttribute& aIn, BluetoothDaemonPDU& aPDU)
return NS_ERROR_ILLEGAL_VALUE; /* integer overflow detected */
}
PRUint32 clen = cstr.Length() + 1; /* include \0 character */
uint32_t clen = cstr.Length() + 1; /* include \0 character */
rv = PackPDU(PackConversion<PRUint32, uint8_t>(clen), aPDU);
rv = PackPDU(PackConversion<uint32_t, uint8_t>(clen), aPDU);
if (NS_FAILED(rv)) {
return rv;
}
@@ -50,9 +50,10 @@ const browserElementTestHelpers = {
enableProcessPriorityManager: function() {
this._setPrefs(
['dom.ipc.processPriorityManager.BACKGROUND.LRUPoolLevels', 2],
['dom.ipc.processPriorityManager.FOREGROUND.LRUPoolLevels', 2],
['dom.ipc.processPriorityManager.testMode', true],
['dom.ipc.processPriorityManager.enabled', true],
['dom.ipc.processPriorityManager.backgroundLRUPoolLevels', 2]
['dom.ipc.processPriorityManager.enabled', true]
);
},
@@ -111,8 +112,7 @@ const browserElementTestHelpers = {
// Returns a promise which is resolved when a subprocess is created. The
// argument to resolve() is the childID of the subprocess.
function expectProcessCreated(/* optional */ initialPriority,
/* optional */ initialCPUPriority) {
function expectProcessCreated(/* optional */ initialPriority) {
return new Promise(function(resolve, reject) {
var observed = false;
browserElementTestHelpers.addProcessPriorityObserver(
@@ -128,7 +128,7 @@ function expectProcessCreated(/* optional */ initialPriority,
var childID = parseInt(data);
ok(true, 'Got new process, id=' + childID);
if (initialPriority) {
expectPriorityChange(childID, initialPriority, initialCPUPriority).then(function() {
expectPriorityChange(childID, initialPriority).then(function() {
resolve(childID);
});
} else {
@@ -141,9 +141,8 @@ function expectProcessCreated(/* optional */ initialPriority,
// Just like expectProcessCreated(), except we'll call ok(false) if a second
// process is created.
function expectOnlyOneProcessCreated(/* optional */ initialPriority,
/* optional */ initialCPUPriority) {
var p = expectProcessCreated(initialPriority, initialCPUPriority);
function expectOnlyOneProcessCreated(/* optional */ initialPriority) {
var p = expectProcessCreated(initialPriority);
p.then(function() {
expectProcessCreated().then(function(childID) {
ok(false, 'Got unexpected process creation, childID=' + childID);
@@ -153,15 +152,10 @@ function expectOnlyOneProcessCreated(/* optional */ initialPriority,
}
// Returns a promise which is resolved or rejected the next time the process
// childID changes its priority. We resolve if the (priority, CPU priority)
// tuple matches (expectedPriority, expectedCPUPriority) and we reject
// otherwise.
//
// expectedCPUPriority is an optional argument; if it's not specified, we
// resolve if priority matches expectedPriority.
// childID changes its priority. We resolve if the priority matches
// expectedPriority, and we reject otherwise.
function expectPriorityChange(childID, expectedPriority,
/* optional */ expectedCPUPriority) {
function expectPriorityChange(childID, expectedPriority) {
return new Promise(function(resolve, reject) {
var observed = false;
browserElementTestHelpers.addProcessPriorityObserver(
@@ -171,7 +165,7 @@ function expectPriorityChange(childID, expectedPriority,
return;
}
var [id, priority, cpuPriority] = data.split(":");
var [id, priority] = data.split(":");
if (id != childID) {
return;
}
@@ -184,14 +178,7 @@ function expectPriorityChange(childID, expectedPriority,
'Expected priority of childID ' + childID +
' to change to ' + expectedPriority);
if (expectedCPUPriority) {
is(cpuPriority, expectedCPUPriority,
'Expected CPU priority of childID ' + childID +
' to change to ' + expectedCPUPriority);
}
if (priority == expectedPriority &&
(!expectedCPUPriority || expectedCPUPriority == cpuPriority)) {
if (priority == expectedPriority) {
resolve();
} else {
reject();
@@ -201,27 +188,37 @@ function expectPriorityChange(childID, expectedPriority,
});
}
// Returns a promise which is resolved or rejected the next time the background
// process childID changes its priority. We resolve if the backgroundLRU
// matches expectedBackgroundLRU and we reject otherwise.
// Returns a promise which is resolved or rejected the next time the
// process childID changes its priority. We resolve if the expectedPriority
// matches the priority and the LRU parameter matches expectedLRU and we
// reject otherwise.
function expectPriorityWithBackgroundLRUSet(childID, expectedBackgroundLRU) {
function expectPriorityWithLRUSet(childID, expectedPriority, expectedLRU) {
return new Promise(function(resolve, reject) {
var observed = false;
browserElementTestHelpers.addProcessPriorityObserver(
'process-priority-with-background-LRU-set',
'process-priority-with-LRU-set',
function(subject, topic, data) {
if (observed) {
return;
}
var [id, priority, cpuPriority, backgroundLRU] = data.split(":");
var [id, priority, lru] = data.split(":");
if (id != childID) {
return;
}
is(backgroundLRU, expectedBackgroundLRU,
'Expected backgroundLRU ' + backgroundLRU + ' of childID ' + childID +
' to change to ' + expectedBackgroundLRU);
// Make sure we run the is() calls in this observer only once,
// otherwise we'll expect /every/ priority/LRU change to match
// expectedPriority/expectedLRU.
observed = true;
if (backgroundLRU == expectedBackgroundLRU) {
is(lru, expectedLRU,
'Expected LRU ' + lru +
' of childID ' + childID +
' to change to ' + expectedLRU);
if ((priority == expectedPriority) && (lru == expectedLRU)) {
resolve();
} else {
reject();
@@ -1,15 +0,0 @@
A word to the wise:
You must ensure that if your test finishes successfully, no processes have
priority FOREGROUND_HIGH.
If you don't do this, expect to see tests randomly fail with mysterious
FOREGROUND --> FOREGROUND priority transitions.
What's happening in this case is that your FOREGROUND_HIGH process lives until
the beginning of the next test. This causes the process started by the next
test to have low CPU priority. Then the FOREGROUND_HIGH process dies, because
its iframe gets GC'ed, and we transition the new test's process from low CPU
priority to regular CPU priority.
Ouch.
@@ -10,12 +10,11 @@ skip-if = toolkit != "gtk2" || ((buildapp =='mulet' || buildapp == 'b2g') && (to
[test_Visibility.html]
[test_HighPriority.html]
support-files = file_HighPriority.html
[test_HighPriorityDowngrade.html]
[test_HighPriorityDowngrade2.html]
[test_Background.html]
[test_BackgroundLRU.html]
[test_Audio.html]
support-files = file_Audio.html silence.ogg
[test_ForegroundLRU.html]
[test_Keyboard.html]
[test_MultipleFrames.html]
support-files = file_MultipleFrames.html
@@ -46,19 +46,22 @@ function runTest() {
document.body.appendChild(iframe2);
// At this point, we should have iframe1 in background already.
// We wait until another one is set to background, too.
// Once there are two in background, the first one (LRU order)
// should have 'backgroundLRU' equals 1
var p = expectPriorityWithBackgroundLRUSet(childID, '1');
// We wait until another process goes into the background, too.
// Once there are two in background, the first one should have its LRU
// adjustment value increased to 1.
var p = expectPriorityWithLRUSet(childID, 'BACKGROUND', '1');
iframe2.setVisible(false);
return p;
}).then(function() {
// Don't call removeChild immediately after calling setVisible.
// setVisible on remote browser is async method, so we should wait
// until it sends to the child process.
// When iframe2 is removed iframe1's LRU value should be decreased again.
var p = expectPriorityWithLRUSet(childID, 'BACKGROUND', '0');
document.body.removeChild(iframe2);
return p;
}).then(function() {
SimpleTest.finish();
});
@@ -0,0 +1,80 @@
<!DOCTYPE HTML>
<html>
<!--
Test that creating three foreground processes causes the LRU value of the
oldest one to be increased by one. Also test that the LRU value is decreased
again when the younger processes go into the background.
-->
<head>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="../browserElementTestHelpers.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<script type="application/javascript;version=1.7">
"use strict";
SimpleTest.waitForExplicitFinish();
browserElementTestHelpers.setEnabledPref(true);
browserElementTestHelpers.addPermission();
browserElementTestHelpers.enableProcessPriorityManager();
SpecialPowers.addPermission("embed-apps", true, document);
function runTest() {
var iframe1 = document.createElement('iframe');
iframe1.setAttribute('mozbrowser', true);
iframe1.src = 'file_MultipleFrames.html';
var iframe2 = null;
var childID = null;
// Wait for the first process to be created.
Promise.all([
expectProcessCreated('FOREGROUND').then(function(chid) {
childID = chid;
}),
expectMozbrowserEvent(iframe1, 'openwindow')
]).then(function() {
// Then wait for the second one.
var p = expectProcessCreated('FOREGROUND');
iframe2 = document.createElement('iframe');
iframe2.setAttribute('mozbrowser', true);
iframe2.setAttribute('mozapp', 'http://example.org/manifest.webapp');
iframe2.src = browserElementTestHelpers.emptyPage1;
document.body.appendChild(iframe2);
return p;
}).then(function() {
// Then wait for the third one and for the first one's LRU value to be
// increased by one.
var p = Promise.all([
expectProcessCreated('FOREGROUND'),
expectPriorityWithLRUSet(childID, 'FOREGROUND', 1)
]);
document.body.appendChild(iframe2);
return p;
}).then(function() {
// Now hide the second and third processes, this will send them into the
// background and make the first process LRU value to be decreased.
var p = expectPriorityWithLRUSet(childID, 'FOREGROUND', 0)
iframe2.setVisible(false);
return p;
}).then(function() {
SimpleTest.finish();
});
document.body.appendChild(iframe1);
}
addEventListener('testready', runTest);
</script>
</body>
</html>
@@ -1,81 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
Test that high-priority processes downgrade the CPU priority of regular
processes.
-->
<head>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="../browserElementTestHelpers.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<script type="application/javascript;version=1.7">
"use strict";
SimpleTest.waitForExplicitFinish();
browserElementTestHelpers.setEnabledPref(true);
browserElementTestHelpers.addPermission();
browserElementTestHelpers.enableProcessPriorityManager();
SpecialPowers.addPermission("embed-apps", true, document);
var iframe = null;
var childID = null;
function runTest() {
var iframe = document.createElement('iframe');
iframe.setAttribute('mozbrowser', true);
iframe.src = browserElementTestHelpers.emptyPage1;
var highPriorityIframe = null;
var childID = null;
var lock = null;
var p = null;
expectProcessCreated('FOREGROUND', 'CPU_NORMAL').then(function(chid) {
childID = chid;
}).then(function() {
// Create a new, high-priority iframe.
highPriorityIframe = document.createElement('iframe');
highPriorityIframe.setAttribute('mozbrowser', true);
highPriorityIframe.setAttribute('expecting-system-message', true);
highPriorityIframe.setAttribute('mozapptype', 'critical');
highPriorityIframe.setAttribute('mozapp', 'http://example.org/manifest.webapp');
highPriorityIframe.src = browserElementTestHelpers.emptyPage2;
p = expectPriorityChange(childID, 'FOREGROUND', 'CPU_LOW');
document.body.appendChild(highPriorityIframe);
return p;
}).then(function() {
return expectPriorityChange(childID, 'FOREGROUND', 'CPU_NORMAL');
}).then(function() {
p = expectPriorityChange(childID, 'FOREGROUND', 'CPU_LOW');
lock = navigator.requestWakeLock('high-priority');
return p;
}).then(function() {
p = expectPriorityChange(childID, 'FOREGROUND', 'CPU_NORMAL');
lock.unlock();
return p;
}).then(SimpleTest.finish);
document.body.appendChild(iframe);
}
addEventListener('testready', function() {
SpecialPowers.pushPrefEnv(
{set: [
/* Cause the CPU wake lock taken on behalf of the high-priority process
* to time out after 1s. */
["dom.ipc.systemMessageCPULockTimeoutSec", 1],
["dom.wakelock.enabled", true]
]},
runTest);
});
</script>
</body>
</html>
@@ -1,76 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
Test that high-priority processes downgrade the CPU priority of regular
processes.
This is just like test_HighPriorityDowngrade, except instead of waiting for the
high-priority process's wake lock to expire, we kill the process by removing
its iframe from the DOM.
-->
<head>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="../browserElementTestHelpers.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<script type="application/javascript;version=1.7">
"use strict";
SimpleTest.waitForExplicitFinish();
browserElementTestHelpers.setEnabledPref(true);
browserElementTestHelpers.addPermission();
browserElementTestHelpers.enableProcessPriorityManager();
SpecialPowers.addPermission("embed-apps", true, document);
function runTest() {
var iframe = document.createElement('iframe');
iframe.setAttribute('mozbrowser', true);
iframe.src = browserElementTestHelpers.emptyPage1;
var highPriorityIframe = null;
var childID = null;
expectProcessCreated('FOREGROUND', 'CPU_NORMAL').then(function(chid) {
childID = chid;
}).then(function() {
// Create a new, high-priority iframe.
highPriorityIframe = document.createElement('iframe');
highPriorityIframe.setAttribute('mozbrowser', true);
highPriorityIframe.setAttribute('expecting-system-message', true);
highPriorityIframe.setAttribute('mozapptype', 'critical');
highPriorityIframe.setAttribute('mozapp', 'http://example.org/manifest.webapp');
highPriorityIframe.src = browserElementTestHelpers.emptyPage2;
var p = Promise.all(
[expectPriorityChange(childID, 'FOREGROUND', 'CPU_LOW'),
expectMozbrowserEvent(highPriorityIframe, 'loadend')]
);
document.body.appendChild(highPriorityIframe);
return p;
}).then(function() {
// Killing the high-priority iframe should cause our CPU priority to go back
// up to regular.
var p = expectPriorityChange(childID, 'FOREGROUND', 'CPU_NORMAL');
document.body.removeChild(highPriorityIframe);
return p;
}).then(SimpleTest.finish);
document.body.appendChild(iframe);
}
addEventListener('testready', function() {
// Cause the CPU wake lock taken on behalf of the high-priority process never
// to time out during this test.
SpecialPowers.pushPrefEnv(
{set: [["dom.ipc.systemMessageCPULockTimeoutSec", 1000]]},
runTest);
});
</script>
</body>
</html>
@@ -53,7 +53,7 @@ function runTest()
// Ensure that the preallocated process initially gets BACKGROUND priority.
// That's it.
expectProcessCreated('PREALLOC', 'CPU_LOW').then(function() {
expectProcessCreated('PREALLOC').then(function() {
// We need to set the pref asynchoronously or the preallocated process won't
// be shut down.
SimpleTest.executeSoon(function(){
+7
View File
@@ -31,6 +31,8 @@ uint32_t CameraPreferences::sPrefCameraControlLowMemoryThresholdMB = 0;
bool CameraPreferences::sPrefCameraParametersIsLowMemory = false;
bool CameraPreferences::sPrefCameraParametersPermission = false;
#ifdef MOZ_WIDGET_GONK
StaticRefPtr<CameraPreferences> CameraPreferences::sObserver;
@@ -113,6 +115,11 @@ CameraPreferences::Pref CameraPreferences::sPrefs[] = {
kPrefValueIsCString,
{ &sPrefHardwareTest }
},
{
"camera.control.test.permission",
kPrefValueIsBoolean,
{ &sPrefCameraParametersPermission }
},
#ifdef MOZ_B2G
{
"camera.control.test.hardware.gonk.parameters",
+2
View File
@@ -80,6 +80,8 @@ protected:
static bool sPrefCameraParametersIsLowMemory;
static bool sPrefCameraParametersPermission;
#ifdef MOZ_WIDGET_GONK
static StaticRefPtr<CameraPreferences> sObserver;
+6 -1
View File
@@ -16,6 +16,7 @@
#include "DOMCameraControl.h"
#include "nsDOMClassInfo.h"
#include "CameraCommon.h"
#include "CameraPreferences.h"
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/PermissionMessageUtils.h"
@@ -298,7 +299,11 @@ nsDOMCameraManager::GetCamera(const nsAString& aCamera,
// which gets us a performance win.
uint16_t status = nsIPrincipal::APP_STATUS_NOT_INSTALLED;
principal->GetAppStatus(&status);
if (status == nsIPrincipal::APP_STATUS_CERTIFIED && CheckPermission(mWindow)) {
// Unprivileged mochitests always fail the dispatched permission check,
// even if permission to the camera has been granted.
bool immediateCheck = false;
CameraPreferences::GetPref("camera.control.test.permission", immediateCheck);
if ((status == nsIPrincipal::APP_STATUS_CERTIFIED || immediateCheck) && CheckPermission(mWindow)) {
PermissionAllowed(cameraId, aInitialConfig, promise);
return promise.forget();
}
+91
View File
@@ -0,0 +1,91 @@
/*
* Copyright (C) 2008 The Android Open Source Project
* Copyright (C) 2015 Mozilla Foundation
*
* 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.
*/
#include "FallbackCameraPlatform.h"
using namespace android;
MediaProfiles* MediaProfiles::sMediaProfiles = nullptr;
const char CameraParameters::KEY_PREVIEW_SIZE[] = "preview-size";
const char CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES[] = "preview-size-values";
const char CameraParameters::KEY_PREVIEW_FORMAT[] = "preview-format";
const char CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS[] = "preview-format-values";
const char CameraParameters::KEY_PREVIEW_FRAME_RATE[] = "preview-frame-rate";
const char CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES[] = "preview-frame-rate-values";
const char CameraParameters::KEY_PREVIEW_FPS_RANGE[] = "preview-fps-range";
const char CameraParameters::KEY_SUPPORTED_PREVIEW_FPS_RANGE[] = "preview-fps-range-values";
const char CameraParameters::KEY_PICTURE_SIZE[] = "picture-size";
const char CameraParameters::KEY_SUPPORTED_PICTURE_SIZES[] = "picture-size-values";
const char CameraParameters::KEY_PICTURE_FORMAT[] = "picture-format";
const char CameraParameters::KEY_SUPPORTED_PICTURE_FORMATS[] = "picture-format-values";
const char CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH[] = "jpeg-thumbnail-width";
const char CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT[] = "jpeg-thumbnail-height";
const char CameraParameters::KEY_SUPPORTED_JPEG_THUMBNAIL_SIZES[] = "jpeg-thumbnail-size-values";
const char CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY[] = "jpeg-thumbnail-quality";
const char CameraParameters::KEY_JPEG_QUALITY[] = "jpeg-quality";
const char CameraParameters::KEY_ROTATION[] = "rotation";
const char CameraParameters::KEY_GPS_LATITUDE[] = "gps-latitude";
const char CameraParameters::KEY_GPS_LONGITUDE[] = "gps-longitude";
const char CameraParameters::KEY_GPS_ALTITUDE[] = "gps-altitude";
const char CameraParameters::KEY_GPS_TIMESTAMP[] = "gps-timestamp";
const char CameraParameters::KEY_GPS_PROCESSING_METHOD[] = "gps-processing-method";
const char CameraParameters::KEY_WHITE_BALANCE[] = "whitebalance";
const char CameraParameters::KEY_SUPPORTED_WHITE_BALANCE[] = "whitebalance-values";
const char CameraParameters::KEY_EFFECT[] = "effect";
const char CameraParameters::KEY_SUPPORTED_EFFECTS[] = "effect-values";
const char CameraParameters::KEY_ANTIBANDING[] = "antibanding";
const char CameraParameters::KEY_SUPPORTED_ANTIBANDING[] = "antibanding-values";
const char CameraParameters::KEY_SCENE_MODE[] = "scene-mode";
const char CameraParameters::KEY_SUPPORTED_SCENE_MODES[] = "scene-mode-values";
const char CameraParameters::KEY_FLASH_MODE[] = "flash-mode";
const char CameraParameters::KEY_SUPPORTED_FLASH_MODES[] = "flash-mode-values";
const char CameraParameters::KEY_FOCUS_MODE[] = "focus-mode";
const char CameraParameters::KEY_SUPPORTED_FOCUS_MODES[] = "focus-mode-values";
const char CameraParameters::KEY_MAX_NUM_FOCUS_AREAS[] = "max-num-focus-areas";
const char CameraParameters::KEY_FOCUS_AREAS[] = "focus-areas";
const char CameraParameters::KEY_FOCAL_LENGTH[] = "focal-length";
const char CameraParameters::KEY_HORIZONTAL_VIEW_ANGLE[] = "horizontal-view-angle";
const char CameraParameters::KEY_VERTICAL_VIEW_ANGLE[] = "vertical-view-angle";
const char CameraParameters::KEY_EXPOSURE_COMPENSATION[] = "exposure-compensation";
const char CameraParameters::KEY_MAX_EXPOSURE_COMPENSATION[] = "max-exposure-compensation";
const char CameraParameters::KEY_MIN_EXPOSURE_COMPENSATION[] = "min-exposure-compensation";
const char CameraParameters::KEY_EXPOSURE_COMPENSATION_STEP[] = "exposure-compensation-step";
const char CameraParameters::KEY_AUTO_EXPOSURE_LOCK[] = "auto-exposure-lock";
const char CameraParameters::KEY_AUTO_EXPOSURE_LOCK_SUPPORTED[] = "auto-exposure-lock-supported";
const char CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK[] = "auto-whitebalance-lock";
const char CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK_SUPPORTED[] = "auto-whitebalance-lock-supported";
const char CameraParameters::KEY_MAX_NUM_METERING_AREAS[] = "max-num-metering-areas";
const char CameraParameters::KEY_METERING_AREAS[] = "metering-areas";
const char CameraParameters::KEY_ZOOM[] = "zoom";
const char CameraParameters::KEY_MAX_ZOOM[] = "max-zoom";
const char CameraParameters::KEY_ZOOM_RATIOS[] = "zoom-ratios";
const char CameraParameters::KEY_ZOOM_SUPPORTED[] = "zoom-supported";
const char CameraParameters::KEY_SMOOTH_ZOOM_SUPPORTED[] = "smooth-zoom-supported";
const char CameraParameters::KEY_FOCUS_DISTANCES[] = "focus-distances";
const char CameraParameters::KEY_VIDEO_FRAME_FORMAT[] = "video-frame-format";
const char CameraParameters::KEY_VIDEO_SIZE[] = "video-size";
const char CameraParameters::KEY_SUPPORTED_VIDEO_SIZES[] = "video-size-values";
const char CameraParameters::KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO[] = "preferred-preview-size-for-video";
const char CameraParameters::KEY_MAX_NUM_DETECTED_FACES_HW[] = "max-num-detected-faces-hw";
const char CameraParameters::KEY_MAX_NUM_DETECTED_FACES_SW[] = "max-num-detected-faces-sw";
const char CameraParameters::KEY_RECORDING_HINT[] = "recording-hint";
const char CameraParameters::KEY_VIDEO_SNAPSHOT_SUPPORTED[] = "video-snapshot-supported";
const char CameraParameters::KEY_VIDEO_STABILIZATION[] = "video-stabilization";
const char CameraParameters::KEY_VIDEO_STABILIZATION_SUPPORTED[] = "video-stabilization-supported";
const char CameraParameters::KEY_LIGHTFX[] = "light-fx";
+300
View File
@@ -0,0 +1,300 @@
/*
* Copyright (C) 2008 The Android Open Source Project
* Copyright (C) 2015 Mozilla Foundation
*
* 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.
*/
#ifndef DOM_CAMERA_FALLBACKCAMERAPLATFORM_H
#define DOM_CAMERA_FALLBACKCAMERAPLATFORM_H
#include <inttypes.h>
#include <string.h>
typedef struct {
int32_t id;
int32_t score;
int32_t rect[4];
int32_t left_eye[2];
int32_t right_eye[2];
int32_t mouth[2];
} camera_face_t;
typedef struct {
uint32_t number_of_faces;
camera_face_t* faces;
} camera_frame_metadata_t;
namespace android {
enum camcorder_quality {
CAMCORDER_QUALITY_LOW,
CAMCORDER_QUALITY_HIGH,
CAMCORDER_QUALITY_QCIF,
CAMCORDER_QUALITY_CIF,
CAMCORDER_QUALITY_480P,
CAMCORDER_QUALITY_720P,
CAMCORDER_QUALITY_1080P,
CAMCORDER_QUALITY_QVGA,
CAMCORDER_QUALITY_VGA,
CAMCORDER_QUALITY_LIST_START = CAMCORDER_QUALITY_LOW,
CAMCORDER_QUALITY_LIST_END = CAMCORDER_QUALITY_VGA
};
enum output_format {
OUTPUT_FORMAT_THREE_GPP,
OUTPUT_FORMAT_MPEG_4
};
enum video_encoder {
VIDEO_ENCODER_H263,
VIDEO_ENCODER_H264,
VIDEO_ENCODER_MPEG_4_SP
};
enum audio_encoder {
AUDIO_ENCODER_AMR_WB,
AUDIO_ENCODER_AMR_NB,
AUDIO_ENCODER_AAC
};
template <class T>
class sp final
{
public:
sp()
: mPtr(nullptr)
{ }
sp(T *aPtr)
: mPtr(aPtr)
{ }
virtual ~sp() { }
T* get() const { return mPtr; }
void clear() { mPtr = nullptr; }
T* operator->() const { return get(); }
private:
nsRefPtr<T> mPtr;
};
typedef uint64_t nsecs_t;
enum error_t {
OK = 0,
UNKNOWN_ERROR,
INVALID_OPERATION
};
enum camera_msg_t {
CAMERA_MSG_SHUTTER,
CAMERA_MSG_COMPRESSED_IMAGE
};
class String8 final
{
public:
String8() { }
String8(const char* aData) { mData.AssignASCII(aData); }
virtual ~String8() { }
const char* string() const { return mData.Data(); }
private:
nsCString mData;
};
enum camera_facing_t {
CAMERA_FACING_BACK,
CAMERA_FACING_FRONT
};
struct CameraInfo {
camera_facing_t facing;
};
class Camera final : public nsISupports
{
public:
NS_DECL_ISUPPORTS;
void disconnect() { }
String8 getParameters() { return String8(); }
int setParameters(const String8& aParams) { return UNKNOWN_ERROR; }
int storeMetaDataInBuffers(bool aEnabled) { return UNKNOWN_ERROR; }
int autoFocus() { return UNKNOWN_ERROR; }
int cancelAutoFocus() { return UNKNOWN_ERROR; }
int takePicture(uint32_t flags) { return UNKNOWN_ERROR; }
int startPreview() { return UNKNOWN_ERROR; }
int stopPreview() { return UNKNOWN_ERROR; }
int startRecording() { return UNKNOWN_ERROR; }
int stopRecording() { return UNKNOWN_ERROR; }
int startFaceDetection() { return UNKNOWN_ERROR; }
int stopFaceDetection() { return UNKNOWN_ERROR; }
static int32_t getNumberOfCameras() { return 2; }
static int getCameraInfo(int32_t aDevice, CameraInfo* aInfo)
{
switch (aDevice) {
case 0:
aInfo->facing = CAMERA_FACING_BACK;
break;
case 1:
aInfo->facing = CAMERA_FACING_FRONT;
break;
default:
return UNKNOWN_ERROR;
}
return OK;
}
protected:
Camera() { }
virtual ~Camera() { }
private:
Camera(const Camera&) = delete;
Camera& operator=(const Camera&) = delete;
};
class CameraParameters final
{
public:
static const char KEY_PREVIEW_SIZE[];
static const char KEY_SUPPORTED_PREVIEW_SIZES[];
static const char KEY_PREVIEW_FPS_RANGE[];
static const char KEY_SUPPORTED_PREVIEW_FPS_RANGE[];
static const char KEY_PREVIEW_FORMAT[];
static const char KEY_SUPPORTED_PREVIEW_FORMATS[];
static const char KEY_PREVIEW_FRAME_RATE[];
static const char KEY_SUPPORTED_PREVIEW_FRAME_RATES[];
static const char KEY_PICTURE_SIZE[];
static const char KEY_SUPPORTED_PICTURE_SIZES[];
static const char KEY_PICTURE_FORMAT[];
static const char KEY_SUPPORTED_PICTURE_FORMATS[];
static const char KEY_JPEG_THUMBNAIL_WIDTH[];
static const char KEY_JPEG_THUMBNAIL_HEIGHT[];
static const char KEY_SUPPORTED_JPEG_THUMBNAIL_SIZES[];
static const char KEY_JPEG_THUMBNAIL_QUALITY[];
static const char KEY_JPEG_QUALITY[];
static const char KEY_ROTATION[];
static const char KEY_GPS_LATITUDE[];
static const char KEY_GPS_LONGITUDE[];
static const char KEY_GPS_ALTITUDE[];
static const char KEY_GPS_TIMESTAMP[];
static const char KEY_GPS_PROCESSING_METHOD[];
static const char KEY_WHITE_BALANCE[];
static const char KEY_SUPPORTED_WHITE_BALANCE[];
static const char KEY_EFFECT[];
static const char KEY_SUPPORTED_EFFECTS[];
static const char KEY_ANTIBANDING[];
static const char KEY_SUPPORTED_ANTIBANDING[];
static const char KEY_SCENE_MODE[];
static const char KEY_SUPPORTED_SCENE_MODES[];
static const char KEY_FLASH_MODE[];
static const char KEY_SUPPORTED_FLASH_MODES[];
static const char KEY_FOCUS_MODE[];
static const char KEY_SUPPORTED_FOCUS_MODES[];
static const char KEY_MAX_NUM_FOCUS_AREAS[];
static const char KEY_FOCUS_AREAS[];
static const char KEY_FOCAL_LENGTH[];
static const char KEY_HORIZONTAL_VIEW_ANGLE[];
static const char KEY_VERTICAL_VIEW_ANGLE[];
static const char KEY_EXPOSURE_COMPENSATION[];
static const char KEY_MAX_EXPOSURE_COMPENSATION[];
static const char KEY_MIN_EXPOSURE_COMPENSATION[];
static const char KEY_EXPOSURE_COMPENSATION_STEP[];
static const char KEY_AUTO_EXPOSURE_LOCK[];
static const char KEY_AUTO_EXPOSURE_LOCK_SUPPORTED[];
static const char KEY_AUTO_WHITEBALANCE_LOCK[];
static const char KEY_AUTO_WHITEBALANCE_LOCK_SUPPORTED[];
static const char KEY_MAX_NUM_METERING_AREAS[];
static const char KEY_METERING_AREAS[];
static const char KEY_ZOOM[];
static const char KEY_MAX_ZOOM[];
static const char KEY_ZOOM_RATIOS[];
static const char KEY_ZOOM_SUPPORTED[];
static const char KEY_SMOOTH_ZOOM_SUPPORTED[];
static const char KEY_FOCUS_DISTANCES[];
static const char KEY_VIDEO_SIZE[];
static const char KEY_SUPPORTED_VIDEO_SIZES[];
static const char KEY_MAX_NUM_DETECTED_FACES_HW[];
static const char KEY_MAX_NUM_DETECTED_FACES_SW[];
static const char KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO[];
static const char KEY_VIDEO_FRAME_FORMAT[];
static const char KEY_RECORDING_HINT[];
static const char KEY_VIDEO_SNAPSHOT_SUPPORTED[];
static const char KEY_VIDEO_STABILIZATION[];
static const char KEY_VIDEO_STABILIZATION_SUPPORTED[];
static const char KEY_LIGHTFX[];
};
class MediaProfiles final
{
public:
static MediaProfiles* getInstance() {
if (!sMediaProfiles) {
sMediaProfiles = new MediaProfiles();
}
return sMediaProfiles;
}
bool hasCamcorderProfile(int aCameraId, camcorder_quality aQuality) const {
switch (aQuality) {
case CAMCORDER_QUALITY_LOW:
case CAMCORDER_QUALITY_HIGH:
case CAMCORDER_QUALITY_QVGA:
case CAMCORDER_QUALITY_VGA:
return true;
default:
break;
}
return false;
}
int getCamcorderProfileParamByName(const char* aParameter, int aCameraId, camcorder_quality aQuality) const {
switch (aQuality) {
case CAMCORDER_QUALITY_LOW:
case CAMCORDER_QUALITY_QVGA:
if (strcmp(aParameter, "vid.width") == 0) {
return 320;
} else if (strcmp(aParameter, "vid.height") == 0) {
return 240;
}
return 0;
case CAMCORDER_QUALITY_HIGH:
case CAMCORDER_QUALITY_VGA:
if (strcmp(aParameter, "vid.width") == 0) {
return 640;
} else if (strcmp(aParameter, "vid.height") == 0) {
return 480;
}
return 0;
default:
break;
}
return -1;
}
protected:
MediaProfiles() { }
virtual ~MediaProfiles() { }
private:
MediaProfiles(const MediaProfiles&) = delete;
MediaProfiles& operator=(const MediaProfiles&) = delete;
static MediaProfiles* sMediaProfiles;
};
}
#endif
+22 -7
View File
@@ -22,25 +22,24 @@
#include <errno.h>
#include <libgen.h>
#include "base/basictypes.h"
#include "camera/CameraParameters.h"
#include "Layers.h"
#ifdef MOZ_WIDGET_GONK
#include <media/mediaplayer.h>
#include <media/MediaProfiles.h>
#include "GrallocImages.h"
#endif
#include "nsCOMPtr.h"
#include "nsMemory.h"
#include "nsThread.h"
#include <media/MediaProfiles.h>
#include "mozilla/FileUtils.h"
#include "mozilla/Services.h"
#include "mozilla/unused.h"
#include "mozilla/ipc/FileDescriptorUtils.h"
#include "nsAlgorithm.h"
#include <media/mediaplayer.h>
#include "nsPrintfCString.h"
#include "nsIObserverService.h"
#include "nsIVolume.h"
#include "nsIVolumeService.h"
#include "AutoRwLock.h"
#include "GonkCameraHwMgr.h"
#include "GonkRecorderProfiles.h"
#include "GrallocImages.h"
#include "CameraCommon.h"
#include "GonkCameraParameters.h"
#include "DeviceStorageFileDescriptor.h"
@@ -71,7 +70,9 @@ nsGonkCameraControl::nsGonkCameraControl(uint32_t aCameraId)
, mAutoFlashModeOverridden(false)
, mSeparateVideoAndPreviewSizesSupported(false)
, mDeferConfigUpdate(0)
#ifdef MOZ_WIDGET_GONK
, mRecorder(nullptr)
#endif
, mRecorderMonitor("GonkCameraControl::mRecorder.Monitor")
, mVideoFile(nullptr)
, mReentrantMonitor("GonkCameraControl::OnTakePicture.Monitor")
@@ -1165,7 +1166,9 @@ nsGonkCameraControl::StartRecordingImpl(DeviceStorageFileDescriptor* aFileDescri
ReentrantMonitorAutoEnter mon(mRecorderMonitor);
NS_ENSURE_TRUE(!mCurrentConfiguration.mRecorderProfile.IsEmpty(), NS_ERROR_NOT_INITIALIZED);
#ifdef MOZ_WIDGET_GONK
NS_ENSURE_FALSE(mRecorder, NS_ERROR_FAILURE);
#endif
/**
* Get the base path from device storage and append the app-specified
@@ -1212,6 +1215,7 @@ nsGonkCameraControl::StartRecordingImpl(DeviceStorageFileDescriptor* aFileDescri
return rv;
}
#ifdef MOZ_WIDGET_GONK
if (mRecorder->start() != OK) {
DOM_CAMERA_LOGE("mRecorder->start() failed\n");
// important: we MUST destroy the recorder if start() fails!
@@ -1222,6 +1226,7 @@ nsGonkCameraControl::StartRecordingImpl(DeviceStorageFileDescriptor* aFileDescri
}
return NS_ERROR_FAILURE;
}
#endif
OnRecorderStateChange(CameraControlListener::kRecorderStarted);
return NS_OK;
@@ -1255,6 +1260,7 @@ nsGonkCameraControl::StopRecordingImpl()
ReentrantMonitorAutoEnter mon(mRecorderMonitor);
#ifdef MOZ_WIDGET_GONK
// nothing to do if we have no mRecorder
if (!mRecorder) {
return NS_OK;
@@ -1277,6 +1283,9 @@ nsGonkCameraControl::StopRecordingImpl()
// notify DeviceStorage that the new video file is closed and ready
return NS_DispatchToMainThread(new RecordingComplete(mVideoFile));
#else
return NS_OK;
#endif
}
nsresult
@@ -1697,6 +1706,7 @@ nsGonkCameraControl::SetVideoConfiguration(const Configuration& aConfig)
return NS_OK;
}
#ifdef MOZ_WIDGET_GONK
class GonkRecorderListener : public IMediaRecorderClient
{
public:
@@ -1843,6 +1853,7 @@ nsGonkCameraControl::OnRecorderEvent(int msg, int ext1, int ext2)
// All unhandled cases wind up here
DOM_CAMERA_LOGW("recorder-event : unhandled: msg=%d, ext1=%d, ext2=%d\n", msg, ext1, ext2);
}
#endif
nsresult
nsGonkCameraControl::SetupRecording(int aFd, int aRotation,
@@ -1851,6 +1862,7 @@ nsGonkCameraControl::SetupRecording(int aFd, int aRotation,
{
RETURN_IF_NO_CAMERA_HW();
#ifdef MOZ_WIDGET_GONK
// choosing a size big enough to hold the params
const size_t SIZE = 256;
char buffer[SIZE];
@@ -1911,6 +1923,7 @@ nsGonkCameraControl::SetupRecording(int aFd, int aRotation,
// recording API needs file descriptor of output file
CHECK_SETARG_RETURN(mRecorder->setOutputFile(aFd, 0, 0), NS_ERROR_FAILURE);
CHECK_SETARG_RETURN(mRecorder->prepare(), NS_ERROR_FAILURE);
#endif
return NS_OK;
}
@@ -2046,6 +2059,7 @@ nsGonkCameraControl::OnRateLimitPreview(bool aLimit)
void
nsGonkCameraControl::OnNewPreviewFrame(layers::TextureClient* aBuffer)
{
#ifdef MOZ_WIDGET_GONK
nsRefPtr<Image> frame = mImageContainer->CreateImage(ImageFormat::GRALLOC_PLANAR_YCBCR);
GrallocImage* videoImage = static_cast<GrallocImage*>(frame.get());
@@ -2058,6 +2072,7 @@ nsGonkCameraControl::OnNewPreviewFrame(layers::TextureClient* aBuffer)
OnNewPreviewFrame(frame, mCurrentConfiguration.mPreviewSize.width,
mCurrentConfiguration.mPreviewSize.height);
#endif
}
void
+13 -3
View File
@@ -19,18 +19,24 @@
#include "base/basictypes.h"
#include "nsRefPtrHashtable.h"
#include <media/MediaProfiles.h>
#include "mozilla/ReentrantMonitor.h"
#include "DeviceStorage.h"
#include "CameraControlImpl.h"
#include "CameraCommon.h"
#include "GonkRecorder.h"
#include "GonkCameraHwMgr.h"
#include "GonkCameraParameters.h"
#ifdef MOZ_WIDGET_GONK
#include <media/MediaProfiles.h>
#include <camera/Camera.h>
#include "GonkRecorder.h"
#else
#include "FallbackCameraPlatform.h"
#endif
namespace android {
class GonkCameraHardware;
class MediaProfiles;
class GonkRecorder;
class GonkCameraSource;
}
@@ -56,7 +62,9 @@ public:
void OnTakePictureError();
void OnRateLimitPreview(bool aLimit);
void OnNewPreviewFrame(layers::TextureClient* aBuffer);
#ifdef MOZ_WIDGET_GONK
void OnRecorderEvent(int msg, int ext1, int ext2);
#endif
void OnSystemError(CameraControlListener::SystemContext aWhere, nsresult aError);
// See ICameraControl.h for getter/setter return values.
@@ -177,7 +185,9 @@ protected:
nsRefPtr<mozilla::layers::ImageContainer> mImageContainer;
#ifdef MOZ_WIDGET_GONK
nsRefPtr<android::GonkRecorder> mRecorder;
#endif
// Touching mRecorder happens inside this monitor because the destructor
// can run on any thread, and we need to be able to clean up properly if
// GonkCameraControl goes away.
+33 -12
View File
@@ -17,8 +17,11 @@
#include "GonkCameraHwMgr.h"
#include "TestGonkCameraHardware.h"
#ifdef MOZ_WIDGET_GONK
#include <binder/IPCThreadState.h>
#include <sys/system_properties.h>
#include "GonkNativeWindow.h"
#endif
#include "base/basictypes.h"
#include "nsDebug.h"
@@ -26,19 +29,26 @@
#include "CameraPreferences.h"
#include "mozilla/RefPtr.h"
#include "GonkCameraControl.h"
#include "GonkNativeWindow.h"
#include "CameraCommon.h"
using namespace mozilla;
using namespace mozilla::layers;
using namespace android;
#ifndef MOZ_WIDGET_GONK
NS_IMPL_ISUPPORTS0(GonkCameraHardware);
NS_IMPL_ISUPPORTS0(android::Camera);
#endif
GonkCameraHardware::GonkCameraHardware(mozilla::nsGonkCameraControl* aTarget, uint32_t aCameraId, const sp<Camera>& aCamera)
: mCameraId(aCameraId)
, mClosing(false)
, mNumFrames(0)
#ifdef MOZ_WIDGET_GONK
, mCamera(aCamera)
#endif
, mTarget(aTarget)
, mRawSensorOrientation(0)
, mSensorOrientation(0)
{
DOM_CAMERA_LOGT("%s:%d : this=%p (aTarget=%p)\n", __func__, __LINE__, (void*)this, (void*)aTarget);
@@ -50,6 +60,7 @@ GonkCameraHardware::OnRateLimitPreview(bool aLimit)
::OnRateLimitPreview(mTarget, aLimit);
}
#ifdef MOZ_WIDGET_GONK
void
GonkCameraHardware::OnNewFrame()
{
@@ -147,12 +158,14 @@ GonkCameraHardware::postDataTimestamp(nsecs_t aTimestamp, int32_t aMsgType, cons
mCamera->releaseRecordingFrame(aDataPtr);
}
}
#endif
nsresult
GonkCameraHardware::Init()
{
DOM_CAMERA_LOGT("%s: this=%p\n", __func__, (void* )this);
#ifdef MOZ_WIDGET_GONK
CameraInfo info;
int rv = Camera::getCameraInfo(mCameraId, &info);
if (rv != 0) {
@@ -181,8 +194,6 @@ GonkCameraHardware::Init()
// Disable shutter sound in android CameraService because gaia camera app will play it
mCamera->sendCommand(CAMERA_CMD_ENABLE_SHUTTER_SOUND, 0, 0);
#if defined(MOZ_WIDGET_GONK)
#if ANDROID_VERSION >= 21
sp<IGraphicBufferProducer> producer;
sp<IGonkGraphicBufferConsumer> consumer;
@@ -227,10 +238,12 @@ GonkCameraHardware::Connect(mozilla::nsGonkCameraControl* aTarget, uint32_t aCam
CameraPreferences::GetPref("camera.control.test.enabled", test);
if (!test.EqualsASCII("hardware")) {
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 18
#ifdef MOZ_WIDGET_GONK
#if ANDROID_VERSION >= 18
camera = Camera::connect(aCameraId, /* clientPackageName */String16("gonk.camera"), Camera::USE_CALLING_UID);
#else
camera = Camera::connect(aCameraId);
#endif
#endif
if (camera.get() == nullptr) {
@@ -266,21 +279,25 @@ GonkCameraHardware::Close()
mCamera->stopPreview();
mCamera->disconnect();
}
mCamera.clear();
#ifdef MOZ_WIDGET_GONK
if (mNativeWindow.get()) {
mNativeWindow->abandon();
}
mCamera.clear();
mNativeWindow.clear();
// Ensure that ICamera's destructor is actually executed
IPCThreadState::self()->flushCommands();
#endif
}
GonkCameraHardware::~GonkCameraHardware()
{
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, (void*)this);
mCamera.clear();
#ifdef MOZ_WIDGET_GONK
mNativeWindow.clear();
#endif
}
int
@@ -366,13 +383,6 @@ GonkCameraHardware::PushParameters(const GonkCameraParameters& aParams)
return mCamera->setParameters(s);
}
int
GonkCameraHardware::PushParameters(const CameraParameters& aParams)
{
String8 s = aParams.flatten();
return mCamera->setParameters(s);
}
nsresult
GonkCameraHardware::PullParameters(GonkCameraParameters& aParams)
{
@@ -380,12 +390,21 @@ GonkCameraHardware::PullParameters(GonkCameraParameters& aParams)
return aParams.Unflatten(s);
}
#ifdef MOZ_WIDGET_GONK
int
GonkCameraHardware::PushParameters(const CameraParameters& aParams)
{
String8 s = aParams.flatten();
return mCamera->setParameters(s);
}
void
GonkCameraHardware::PullParameters(CameraParameters& aParams)
{
const String8 s = mCamera->getParameters();
aParams.unflatten(s);
}
#endif
int
GonkCameraHardware::StartPreview()
@@ -422,6 +441,7 @@ GonkCameraHardware::StopRecording()
return OK;
}
#ifdef MOZ_WIDGET_GONK
int
GonkCameraHardware::SetListener(const sp<GonkCameraListener>& aListener)
{
@@ -434,6 +454,7 @@ GonkCameraHardware::ReleaseRecordingFrame(const sp<IMemory>& aFrame)
{
mCamera->releaseRecordingFrame(aFrame);
}
#endif
int
GonkCameraHardware::StoreMetaDataInBuffers(bool aEnabled)
+29 -11
View File
@@ -17,18 +17,21 @@
#ifndef DOM_CAMERA_GONKCAMERAHWMGR_H
#define DOM_CAMERA_GONKCAMERAHWMGR_H
#include "GonkCameraControl.h"
#include "CameraCommon.h"
#include "GonkCameraParameters.h"
#include "mozilla/ReentrantMonitor.h"
#ifdef MOZ_WIDGET_GONK
#include <binder/IMemory.h>
#include <camera/Camera.h>
#include <camera/CameraParameters.h>
#include <utils/threads.h>
#include "GonkCameraControl.h"
#include "CameraCommon.h"
#include "GonkCameraListener.h"
#include "GonkNativeWindow.h"
#include "GonkCameraParameters.h"
#include "mozilla/ReentrantMonitor.h"
#else
#include "FallbackCameraPlatform.h"
#endif
namespace mozilla {
class nsGonkCameraControl;
@@ -37,9 +40,18 @@ namespace mozilla {
namespace android {
class GonkCameraHardware : public GonkNativeWindowNewFrameCallback
, public CameraListener
class GonkCameraHardware
#ifdef MOZ_WIDGET_GONK
: public GonkNativeWindowNewFrameCallback
, public CameraListener
#else
: public nsISupports
#endif
{
#ifndef MOZ_WIDGET_GONK
NS_DECL_ISUPPORTS
#endif
protected:
GonkCameraHardware(mozilla::nsGonkCameraControl* aTarget, uint32_t aCameraId, const sp<Camera>& aCamera);
virtual ~GonkCameraHardware();
@@ -57,6 +69,7 @@ public:
virtual void OnRateLimitPreview(bool aLimit);
#ifdef MOZ_WIDGET_GONK
// derived from GonkNativeWindowNewFrameCallback
virtual void OnNewFrame() override;
@@ -64,6 +77,7 @@ public:
virtual void notify(int32_t aMsgType, int32_t ext1, int32_t ext2);
virtual void postData(int32_t aMsgType, const sp<IMemory>& aDataPtr, camera_frame_metadata_t* metadata);
virtual void postDataTimestamp(nsecs_t aTimestamp, int32_t aMsgType, const sp<IMemory>& aDataPtr);
#endif
/**
* The physical orientation of the camera sensor: 0, 90, 180, or 270.
@@ -103,13 +117,15 @@ public:
virtual int StartPreview();
virtual void StopPreview();
virtual int PushParameters(const mozilla::GonkCameraParameters& aParams);
virtual int PushParameters(const CameraParameters& aParams);
virtual nsresult PullParameters(mozilla::GonkCameraParameters& aParams);
#ifdef MOZ_WIDGET_GONK
virtual int PushParameters(const CameraParameters& aParams);
virtual void PullParameters(CameraParameters& aParams);
virtual int StartRecording();
virtual int StopRecording();
virtual int SetListener(const sp<GonkCameraListener>& aListener);
virtual void ReleaseRecordingFrame(const sp<IMemory>& aFrame);
#endif
virtual int StartRecording();
virtual int StopRecording();
virtual int StoreMetaDataInBuffers(bool aEnabled);
protected:
@@ -118,8 +134,10 @@ protected:
uint32_t mNumFrames;
sp<Camera> mCamera;
mozilla::nsGonkCameraControl* mTarget;
#ifdef MOZ_WIDGET_GONK
sp<GonkNativeWindow> mNativeWindow;
sp<GonkCameraListener> mListener;
#endif
int mRawSensorOrientation;
int mSensorOrientation;
+6 -3
View File
@@ -15,14 +15,17 @@
*/
#include "ICameraControl.h"
#include <camera/Camera.h>
#include "CameraCommon.h"
#include "GonkCameraControl.h"
#include "CameraPreferences.h"
#include "TestGonkCameraControl.h"
#ifdef MOZ_WIDGET_GONK
#include <camera/Camera.h>
#else
#include "FallbackCameraPlatform.h"
#endif
using namespace mozilla;
// From ICameraControl, gonk-specific management functions
+132 -75
View File
@@ -15,12 +15,12 @@
*/
#include "GonkCameraParameters.h"
#include "camera/CameraParameters.h"
#include "CameraPreferences.h"
#include "ICameraControl.h"
#include "CameraCommon.h"
#include "mozilla/Hal.h"
#include "nsDataHashtable.h"
#include "nsPrintfCString.h"
using namespace mozilla;
using namespace android;
@@ -52,13 +52,13 @@ GonkCameraParameters::IsLowMemoryPlatform()
}
const char*
GonkCameraParameters::Parameters::FindVendorSpecificKey(const char* aPotentialKeys[],
size_t aPotentialKeyCount)
GonkCameraParameters::FindVendorSpecificKey(const char* aPotentialKeys[],
size_t aPotentialKeyCount)
{
const char* val;
for (size_t i = 0; i < aPotentialKeyCount; ++i) {
get(aPotentialKeys[i], val);
GetImpl(aPotentialKeys[i], val);
if (val) {
// We received a value (potentially an empty-string one),
// which indicates that this key exists.
@@ -69,59 +69,122 @@ GonkCameraParameters::Parameters::FindVendorSpecificKey(const char* aPotentialKe
return nullptr;
}
/* static */ PLDHashOperator
GonkCameraParameters::EnumerateFlatten(const nsACString& aKey,
nsCString* aValue,
void* aUserArg)
{
nsCString* data = static_cast<nsCString*>(aUserArg);
if (!data->IsEmpty()) {
data->Append(';');
}
data->Append(aKey);
data->Append('=');
data->Append(*aValue);
return PL_DHASH_NEXT;
}
String8
GonkCameraParameters::Flatten() const
{
MutexAutoLock lock(mLock);
nsCString data;
mParams.EnumerateRead(EnumerateFlatten, static_cast<void*>(&data));
return String8(data.Data());
}
nsresult
GonkCameraParameters::Unflatten(const String8& aFlatParameters)
{
MutexAutoLock lock(mLock);
mParams.Clear();
const char* data = aFlatParameters.string();
while (data && *data) {
const char* pos = strchr(data, '=');
if (!pos) {
break;
}
nsAutoCString key(data, pos - data);
data = pos + 1;
nsCString* value;
pos = strchr(data, ';');
if (pos) {
value = new nsCString(data, pos - data);
data = pos + 1;
} else {
value = new nsCString(data);
data = nullptr;
}
mParams.Put(key, value);
}
if (mInitialized) {
return NS_OK;
}
// We call Initialize() once when the parameter set is first loaded,
// to set up any constant values this class requires internally,
// e.g. the exposure compensation step and limits.
return Initialize();
}
const char*
GonkCameraParameters::Parameters::GetTextKey(uint32_t aKey)
GonkCameraParameters::GetTextKey(uint32_t aKey)
{
switch (aKey) {
case CAMERA_PARAM_PREVIEWSIZE:
return KEY_PREVIEW_SIZE;
return CameraParameters::KEY_PREVIEW_SIZE;
case CAMERA_PARAM_PREVIEWFORMAT:
return KEY_PREVIEW_FORMAT;
return CameraParameters::KEY_PREVIEW_FORMAT;
case CAMERA_PARAM_PREVIEWFRAMERATE:
return KEY_PREVIEW_FRAME_RATE;
return CameraParameters::KEY_PREVIEW_FRAME_RATE;
case CAMERA_PARAM_EFFECT:
return KEY_EFFECT;
return CameraParameters::KEY_EFFECT;
case CAMERA_PARAM_WHITEBALANCE:
return KEY_WHITE_BALANCE;
return CameraParameters::KEY_WHITE_BALANCE;
case CAMERA_PARAM_SCENEMODE:
return KEY_SCENE_MODE;
return CameraParameters::KEY_SCENE_MODE;
case CAMERA_PARAM_FLASHMODE:
return KEY_FLASH_MODE;
return CameraParameters::KEY_FLASH_MODE;
case CAMERA_PARAM_FOCUSMODE:
return KEY_FOCUS_MODE;
return CameraParameters::KEY_FOCUS_MODE;
case CAMERA_PARAM_ZOOM:
return KEY_ZOOM;
return CameraParameters::KEY_ZOOM;
case CAMERA_PARAM_METERINGAREAS:
return KEY_METERING_AREAS;
return CameraParameters::KEY_METERING_AREAS;
case CAMERA_PARAM_FOCUSAREAS:
return KEY_FOCUS_AREAS;
return CameraParameters::KEY_FOCUS_AREAS;
case CAMERA_PARAM_FOCALLENGTH:
return KEY_FOCAL_LENGTH;
return CameraParameters::KEY_FOCAL_LENGTH;
case CAMERA_PARAM_FOCUSDISTANCENEAR:
return KEY_FOCUS_DISTANCES;
return CameraParameters::KEY_FOCUS_DISTANCES;
case CAMERA_PARAM_FOCUSDISTANCEOPTIMUM:
return KEY_FOCUS_DISTANCES;
return CameraParameters::KEY_FOCUS_DISTANCES;
case CAMERA_PARAM_FOCUSDISTANCEFAR:
return KEY_FOCUS_DISTANCES;
return CameraParameters::KEY_FOCUS_DISTANCES;
case CAMERA_PARAM_EXPOSURECOMPENSATION:
return KEY_EXPOSURE_COMPENSATION;
return CameraParameters::KEY_EXPOSURE_COMPENSATION;
case CAMERA_PARAM_THUMBNAILQUALITY:
return KEY_JPEG_THUMBNAIL_QUALITY;
return CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY;
case CAMERA_PARAM_PICTURE_SIZE:
return KEY_PICTURE_SIZE;
return CameraParameters::KEY_PICTURE_SIZE;
case CAMERA_PARAM_PICTURE_FILEFORMAT:
return KEY_PICTURE_FORMAT;
return CameraParameters::KEY_PICTURE_FORMAT;
case CAMERA_PARAM_PICTURE_ROTATION:
return KEY_ROTATION;
return CameraParameters::KEY_ROTATION;
case CAMERA_PARAM_PICTURE_DATETIME:
// Not every platform defines a KEY_EXIF_DATETIME;
// Not every platform defines a CameraParameters::EXIF_DATETIME;
// for those that don't, we use the raw string key, and if the platform
// doesn't support it, it will be ignored.
//
// See bug 832494.
return "exif-datetime";
case CAMERA_PARAM_VIDEOSIZE:
return KEY_VIDEO_SIZE;
return CameraParameters::KEY_VIDEO_SIZE;
case CAMERA_PARAM_ISOMODE:
if (!mVendorSpecificKeyIsoMode) {
const char* isoModeKeys[] = {
@@ -135,55 +198,55 @@ GonkCameraParameters::Parameters::GetTextKey(uint32_t aKey)
case CAMERA_PARAM_LUMINANCE:
return "luminance-condition";
case CAMERA_PARAM_SCENEMODE_HDR_RETURNNORMALPICTURE:
// Not every platform defines KEY_QC_HDR_NEED_1X;
// Not every platform defines CameraParameters::QC_HDR_NEED_1X;
// for those that don't, we use the raw string key.
return "hdr-need-1x";
case CAMERA_PARAM_RECORDINGHINT:
return KEY_RECORDING_HINT;
return CameraParameters::KEY_RECORDING_HINT;
case CAMERA_PARAM_PICTURE_QUALITY:
return KEY_JPEG_QUALITY;
return CameraParameters::KEY_JPEG_QUALITY;
case CAMERA_PARAM_PREFERRED_PREVIEWSIZE_FOR_VIDEO:
return KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO;
return CameraParameters::KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO;
case CAMERA_PARAM_METERINGMODE:
// Not every platform defines KEY_AUTO_EXPOSURE.
// Not every platform defines CameraParameters::AUTO_EXPOSURE.
return "auto-exposure";
case CAMERA_PARAM_SUPPORTED_PREVIEWSIZES:
return KEY_SUPPORTED_PREVIEW_SIZES;
return CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES;
case CAMERA_PARAM_SUPPORTED_PICTURESIZES:
return KEY_SUPPORTED_PICTURE_SIZES;
return CameraParameters::KEY_SUPPORTED_PICTURE_SIZES;
case CAMERA_PARAM_SUPPORTED_VIDEOSIZES:
return KEY_SUPPORTED_VIDEO_SIZES;
return CameraParameters::KEY_SUPPORTED_VIDEO_SIZES;
case CAMERA_PARAM_SUPPORTED_PICTUREFORMATS:
return KEY_SUPPORTED_PICTURE_FORMATS;
return CameraParameters::KEY_SUPPORTED_PICTURE_FORMATS;
case CAMERA_PARAM_SUPPORTED_WHITEBALANCES:
return KEY_SUPPORTED_WHITE_BALANCE;
return CameraParameters::KEY_SUPPORTED_WHITE_BALANCE;
case CAMERA_PARAM_SUPPORTED_SCENEMODES:
return KEY_SUPPORTED_SCENE_MODES;
return CameraParameters::KEY_SUPPORTED_SCENE_MODES;
case CAMERA_PARAM_SUPPORTED_EFFECTS:
return KEY_SUPPORTED_EFFECTS;
return CameraParameters::KEY_SUPPORTED_EFFECTS;
case CAMERA_PARAM_SUPPORTED_FLASHMODES:
return KEY_SUPPORTED_FLASH_MODES;
return CameraParameters::KEY_SUPPORTED_FLASH_MODES;
case CAMERA_PARAM_SUPPORTED_FOCUSMODES:
return KEY_SUPPORTED_FOCUS_MODES;
return CameraParameters::KEY_SUPPORTED_FOCUS_MODES;
case CAMERA_PARAM_SUPPORTED_MAXFOCUSAREAS:
return KEY_MAX_NUM_FOCUS_AREAS;
return CameraParameters::KEY_MAX_NUM_FOCUS_AREAS;
case CAMERA_PARAM_SUPPORTED_MAXMETERINGAREAS:
return KEY_MAX_NUM_METERING_AREAS;
return CameraParameters::KEY_MAX_NUM_METERING_AREAS;
case CAMERA_PARAM_SUPPORTED_MINEXPOSURECOMPENSATION:
return KEY_MIN_EXPOSURE_COMPENSATION;
return CameraParameters::KEY_MIN_EXPOSURE_COMPENSATION;
case CAMERA_PARAM_SUPPORTED_MAXEXPOSURECOMPENSATION:
return KEY_MAX_EXPOSURE_COMPENSATION;
return CameraParameters::KEY_MAX_EXPOSURE_COMPENSATION;
case CAMERA_PARAM_SUPPORTED_EXPOSURECOMPENSATIONSTEP:
return KEY_EXPOSURE_COMPENSATION_STEP;
return CameraParameters::KEY_EXPOSURE_COMPENSATION_STEP;
case CAMERA_PARAM_SUPPORTED_ZOOM:
return KEY_ZOOM_SUPPORTED;
return CameraParameters::KEY_ZOOM_SUPPORTED;
case CAMERA_PARAM_SUPPORTED_ZOOMRATIOS:
return KEY_ZOOM_RATIOS;
return CameraParameters::KEY_ZOOM_RATIOS;
case CAMERA_PARAM_SUPPORTED_MAXDETECTEDFACES:
return KEY_MAX_NUM_DETECTED_FACES_HW;
return CameraParameters::KEY_MAX_NUM_DETECTED_FACES_HW;
case CAMERA_PARAM_SUPPORTED_JPEG_THUMBNAIL_SIZES:
return KEY_SUPPORTED_JPEG_THUMBNAIL_SIZES;
return CameraParameters::KEY_SUPPORTED_JPEG_THUMBNAIL_SIZES;
case CAMERA_PARAM_SUPPORTED_ISOMODES:
if (!mVendorSpecificKeySupportedIsoModes) {
const char* supportedIsoModesKeys[] = {
@@ -196,7 +259,7 @@ GonkCameraParameters::Parameters::GetTextKey(uint32_t aKey)
}
return mVendorSpecificKeySupportedIsoModes;
case CAMERA_PARAM_SUPPORTED_METERINGMODES:
// Not every platform defines KEY_SUPPORTED_AUTO_EXPOSURE.
// Not every platform defines CameraParameters::SUPPORTED_AUTO_EXPOSURE.
return "auto-exposure-values";
default:
DOM_CAMERA_LOGE("Unhandled camera parameter value %u\n", aKey);
@@ -205,26 +268,20 @@ GonkCameraParameters::Parameters::GetTextKey(uint32_t aKey)
}
GonkCameraParameters::GonkCameraParameters()
: mLock(PR_NewRWLock(PR_RWLOCK_RANK_NONE, "GonkCameraParameters.Lock"))
: mLock("mozilla::camera::GonkCameraParameters")
, mDirty(false)
, mInitialized(false)
, mExposureCompensationStep(0.0)
, mVendorSpecificKeyIsoMode(nullptr)
, mVendorSpecificKeySupportedIsoModes(nullptr)
{
MOZ_COUNT_CTOR(GonkCameraParameters);
if (!mLock) {
MOZ_CRASH("Out of memory getting new PRRWLock");
}
}
GonkCameraParameters::~GonkCameraParameters()
{
MOZ_COUNT_DTOR(GonkCameraParameters);
mIsoModeMap.Clear();
MOZ_ASSERT(mLock, "mLock missing in ~GonkCameraParameters()");
if (mLock) {
PR_DestroyRWLock(mLock);
mLock = nullptr;
}
}
nsresult
@@ -278,17 +335,17 @@ GonkCameraParameters::Initialize()
{
nsresult rv;
rv = GetImpl(Parameters::KEY_EXPOSURE_COMPENSATION_STEP, mExposureCompensationStep);
rv = GetImpl(CameraParameters::KEY_EXPOSURE_COMPENSATION_STEP, mExposureCompensationStep);
if (NS_FAILED(rv)) {
NS_WARNING("Failed to initialize exposure compensation step size");
mExposureCompensationStep = 0.0;
}
rv = GetImpl(Parameters::KEY_MIN_EXPOSURE_COMPENSATION, mExposureCompensationMinIndex);
rv = GetImpl(CameraParameters::KEY_MIN_EXPOSURE_COMPENSATION, mExposureCompensationMinIndex);
if (NS_FAILED(rv)) {
NS_WARNING("Failed to initialize minimum exposure compensation index");
mExposureCompensationMinIndex = 0;
}
rv = GetImpl(Parameters::KEY_MAX_EXPOSURE_COMPENSATION, mExposureCompensationMaxIndex);
rv = GetImpl(CameraParameters::KEY_MAX_EXPOSURE_COMPENSATION, mExposureCompensationMaxIndex);
if (NS_FAILED(rv)) {
NS_WARNING("Failed to initialize maximum exposure compensation index");
mExposureCompensationMaxIndex = 0;
@@ -425,9 +482,9 @@ GonkCameraParameters::SetTranslated(uint32_t aKey, const ICameraControl::Size& a
// This is a special case--for some reason the thumbnail size
// is accessed as two separate values instead of a tuple.
// XXXmikeh - make this restore the original values on error
rv = SetImpl(Parameters::KEY_JPEG_THUMBNAIL_WIDTH, static_cast<int>(aSize.width));
rv = SetImpl(CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH, static_cast<int>(aSize.width));
if (NS_SUCCEEDED(rv)) {
rv = SetImpl(Parameters::KEY_JPEG_THUMBNAIL_HEIGHT, static_cast<int>(aSize.height));
rv = SetImpl(CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT, static_cast<int>(aSize.height));
}
break;
@@ -461,14 +518,14 @@ GonkCameraParameters::GetTranslated(uint32_t aKey, ICameraControl::Size& aSize)
int width;
int height;
rv = GetImpl(Parameters::KEY_JPEG_THUMBNAIL_WIDTH, width);
rv = GetImpl(CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH, width);
if (NS_FAILED(rv)) {
return rv;
}
if (width < 0) {
return NS_ERROR_NOT_AVAILABLE;
}
rv = GetImpl(Parameters::KEY_JPEG_THUMBNAIL_HEIGHT, height);
rv = GetImpl(CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT, height);
if (NS_FAILED(rv)) {
return rv;
}
@@ -572,27 +629,27 @@ GonkCameraParameters::SetTranslated(uint32_t aKey, const ICameraControl::Positio
// Add any specified location information -- we don't care if these fail.
if (!isnan(aPosition.latitude)) {
DOM_CAMERA_LOGI("setting picture latitude to %lf\n", aPosition.latitude);
SetImpl(Parameters::KEY_GPS_LATITUDE, nsPrintfCString("%lf", aPosition.latitude).get());
SetImpl(CameraParameters::KEY_GPS_LATITUDE, nsPrintfCString("%lf", aPosition.latitude).get());
} else {
ClearImpl(Parameters::KEY_GPS_LATITUDE);
ClearImpl(CameraParameters::KEY_GPS_LATITUDE);
}
if (!isnan(aPosition.longitude)) {
DOM_CAMERA_LOGI("setting picture longitude to %lf\n", aPosition.longitude);
SetImpl(Parameters::KEY_GPS_LONGITUDE, nsPrintfCString("%lf", aPosition.longitude).get());
SetImpl(CameraParameters::KEY_GPS_LONGITUDE, nsPrintfCString("%lf", aPosition.longitude).get());
} else {
ClearImpl(Parameters::KEY_GPS_LONGITUDE);
ClearImpl(CameraParameters::KEY_GPS_LONGITUDE);
}
if (!isnan(aPosition.altitude)) {
DOM_CAMERA_LOGI("setting picture altitude to %lf\n", aPosition.altitude);
SetImpl(Parameters::KEY_GPS_ALTITUDE, nsPrintfCString("%lf", aPosition.altitude).get());
SetImpl(CameraParameters::KEY_GPS_ALTITUDE, nsPrintfCString("%lf", aPosition.altitude).get());
} else {
ClearImpl(Parameters::KEY_GPS_ALTITUDE);
ClearImpl(CameraParameters::KEY_GPS_ALTITUDE);
}
if (!isnan(aPosition.timestamp)) {
DOM_CAMERA_LOGI("setting picture timestamp to %lf\n", aPosition.timestamp);
SetImpl(Parameters::KEY_GPS_TIMESTAMP, nsPrintfCString("%lf", aPosition.timestamp).get());
SetImpl(CameraParameters::KEY_GPS_TIMESTAMP, nsPrintfCString("%lf", aPosition.timestamp).get());
} else {
ClearImpl(Parameters::KEY_GPS_TIMESTAMP);
ClearImpl(CameraParameters::KEY_GPS_TIMESTAMP);
}
return NS_OK;
+120 -84
View File
@@ -18,14 +18,18 @@
#define DOM_CAMERA_GONKCAMERAPARAMETERS_H
#include <math.h>
#include "camera/CameraParameters.h"
#include "nsTArray.h"
#include "nsString.h"
#include "AutoRwLock.h"
#include "nsPrintfCString.h"
#include "mozilla/Mutex.h"
#include "nsClassHashtable.h"
#include "ICameraControl.h"
#ifdef MOZ_WIDGET_GONK
#include <camera/CameraParameters.h>
#else
#include "FallbackCameraPlatform.h"
#endif
namespace mozilla {
class GonkCameraParameters
@@ -44,7 +48,7 @@ public:
template<class T> nsresult
Set(uint32_t aKey, const T& aValue)
{
RwLockAutoEnterWrite lock(mLock);
MutexAutoLock lock(mLock);
nsresult rv = SetTranslated(aKey, aValue);
mDirty = mDirty || NS_SUCCEEDED(rv);
return rv;
@@ -53,7 +57,7 @@ public:
template<class T> nsresult
Get(uint32_t aKey, T& aValue)
{
RwLockAutoEnterRead lock(mLock);
MutexAutoLock lock(mLock);
return GetTranslated(aKey, aValue);
}
@@ -62,36 +66,17 @@ public:
{
bool dirty;
RwLockAutoEnterWrite lock(mLock);
MutexAutoLock lock(mLock);
dirty = mDirty;
mDirty = false;
return dirty;
}
android::String8
Flatten() const
{
RwLockAutoEnterRead lock(mLock);
return mParams.flatten();
}
nsresult
Unflatten(const android::String8& aFlatParameters)
{
RwLockAutoEnterWrite lock(mLock);
mParams.unflatten(aFlatParameters);
if (mInitialized) {
return NS_OK;
}
// We call Initialize() once when the parameter set is first loaded,
// to set up any constant values this class requires internally,
// e.g. the exposure compensation step and limits.
return Initialize();
}
android::String8 Flatten() const;
nsresult Unflatten(const android::String8& aFlatParameters);
protected:
PRRWLock* mLock;
mutable Mutex mLock;
bool mDirty;
bool mInitialized;
@@ -99,55 +84,123 @@ protected:
double mExposureCompensationStep;
int32_t mExposureCompensationMinIndex;
int32_t mExposureCompensationMaxIndex;
const char* mVendorSpecificKeyIsoMode;
const char* mVendorSpecificKeySupportedIsoModes;
nsTArray<int> mZoomRatios;
nsTArray<nsString> mIsoModes;
nsTArray<nsString> mSceneModes;
nsTArray<nsString> mMeteringModes;
nsClassHashtable<nsStringHashKey, nsCString> mIsoModeMap;
nsClassHashtable<nsCStringHashKey, nsCString> mParams;
// This subclass of android::CameraParameters just gives
// all of the AOSP getters and setters the same signature.
class Parameters : public android::CameraParameters
static PLDHashOperator EnumerateFlatten(const nsACString& aKey, nsCString* aValue, void* aUserArg);
nsresult SetImpl(const char* aKey, const char* aValue)
{
public:
Parameters()
: mVendorSpecificKeyIsoMode(nullptr)
, mVendorSpecificKeySupportedIsoModes(nullptr)
{ }
virtual ~Parameters() { }
nsCString key(aKey);
mParams.Put(key, new nsCString(aValue));
return NS_OK;
}
using android::CameraParameters::set;
using android::CameraParameters::get;
using android::CameraParameters::TRUE;
using android::CameraParameters::FALSE;
nsresult SetImpl(const char* aKey, int aValue)
{
nsCString key(aKey);
nsCString* value = new nsCString();
value->AppendInt(aValue);
mParams.Put(key, value);
return NS_OK;
}
void set(const char* aKey, float aValue) { setFloat(aKey, aValue); }
void set(const char* aKey, double aValue) { setFloat(aKey, aValue); }
void set(const char* aKey, bool aValue) { set(aKey, aValue ? TRUE : FALSE); }
void get(const char* aKey, float& aRet) { aRet = getFloat(aKey); }
void get(const char* aKey, double& aRet) { aRet = getFloat(aKey); }
void get(const char* aKey, const char*& aRet) { aRet = get(aKey); }
void get(const char* aKey, int& aRet) { aRet = getInt(aKey); }
nsresult SetImpl(const char* aKey, double aValue)
{
nsCString key(aKey);
nsCString* value = new nsCString();
value->AppendFloat(aValue);
mParams.Put(key, value);
return NS_OK;
}
void
get(const char* aKey, bool& aRet)
{
const char* value = get(aKey);
aRet = value ? strcmp(value, TRUE) == 0 : false;
nsresult SetImpl(const char* aKey, float aValue)
{
nsCString key(aKey);
nsCString* value = new nsCString();
value->AppendFloat(aValue);
mParams.Put(key, value);
return NS_OK;
}
nsresult SetImpl(const char* aKey, bool aValue)
{
nsCString key(aKey);
mParams.Put(key, new nsCString(aValue ? "true" : "false"));
return NS_OK;
}
nsresult GetImpl(const char* aKey, const char*& aRet)
{
nsCString key(aKey);
nsCString* value;
if (!mParams.Get(key, &value)) {
aRet = nullptr;
return NS_ERROR_FAILURE;
}
aRet = value->Data();
return NS_OK;
}
void remove(const char* aKey) { android::CameraParameters::remove(aKey); }
nsresult GetImpl(const char* aKey, float& aRet)
{
nsCString key(aKey);
nsCString* value;
nsresult rv = NS_ERROR_FAILURE;
if (mParams.Get(key, &value)) {
aRet = value->ToFloat(&rv);
} else {
aRet = 0.0;
}
return rv;
}
const char* GetTextKey(uint32_t aKey);
nsresult GetImpl(const char* aKey, double& aRet)
{
nsCString key(aKey);
nsCString* value;
nsresult rv = NS_ERROR_FAILURE;
if (mParams.Get(key, &value)) {
aRet = value->ToFloat(&rv);
} else {
aRet = 0.0;
}
return rv;
}
protected:
const char* FindVendorSpecificKey(const char* aPotentialKeys[], size_t aPotentialKeyCount);
nsresult GetImpl(const char* aKey, int& aRet)
{
nsCString key(aKey);
nsCString* value;
nsresult rv = NS_ERROR_FAILURE;
if (mParams.Get(key, &value)) {
aRet = value->ToInteger(&rv);
} else {
aRet = 0.0;
}
return rv;
}
const char* mVendorSpecificKeyIsoMode;
const char* mVendorSpecificKeySupportedIsoModes;
};
nsresult GetImpl(const char* aKey, bool& aRet)
{
nsCString key(aKey);
nsCString* value;
if (!mParams.Get(key, &value)) {
aRet = false;
return NS_ERROR_FAILURE;
}
aRet = value->EqualsLiteral("true");
return NS_OK;
}
Parameters mParams;
const char* GetTextKey(uint32_t aKey);
const char* FindVendorSpecificKey(const char* aPotentialKeys[], size_t aPotentialKeyCount);
// The *Impl() templates handle converting the parameter keys from
// their enum values to string types, if necessary. These are the
@@ -159,41 +212,24 @@ protected:
template<typename T> nsresult
SetImpl(uint32_t aKey, const T& aValue)
{
const char* key = mParams.GetTextKey(aKey);
const char* key = GetTextKey(aKey);
NS_ENSURE_TRUE(key, NS_ERROR_NOT_IMPLEMENTED);
mParams.set(key, aValue);
return NS_OK;
return SetImpl(key, aValue);
}
template<typename T> nsresult
GetImpl(uint32_t aKey, T& aValue)
{
const char* key = mParams.GetTextKey(aKey);
const char* key = GetTextKey(aKey);
NS_ENSURE_TRUE(key, NS_ERROR_NOT_IMPLEMENTED);
mParams.get(key, aValue);
return NS_OK;
}
template<class T> nsresult
SetImpl(const char* aKey, const T& aValue)
{
mParams.set(aKey, aValue);
return NS_OK;
}
template<class T> nsresult
GetImpl(const char* aKey, T& aValue)
{
mParams.get(aKey, aValue);
return NS_OK;
return GetImpl(key, aValue);
}
nsresult
ClearImpl(const char* aKey)
{
mParams.remove(aKey);
nsCString key(aKey);
mParams.Remove(key);
return NS_OK;
}
+7 -3
View File
@@ -15,12 +15,14 @@
*/
#include "GonkRecorderProfiles.h"
#include <media/MediaProfiles.h>
#include "nsMimeTypes.h"
#include "GonkRecorder.h"
#include "CameraControlImpl.h"
#include "CameraCommon.h"
#ifdef MOZ_WIDGET_GONK
#include "GonkRecorder.h"
#endif
using namespace mozilla;
using namespace android;
@@ -374,10 +376,11 @@ GonkRecorderProfile::GetAll(uint32_t aCameraId,
aProfiles.Clear();
profiles->EnumerateRead(Enumerate, static_cast<void*>(&aProfiles));
return NS_OK;
}
#ifdef MOZ_WIDGET_GONK
nsresult
GonkRecorderProfile::ConfigureRecorder(GonkRecorder& aRecorder)
{
@@ -425,3 +428,4 @@ GonkRecorderProfile::ConfigureRecorder(android::GonkRecorder& aRecorder,
return profile->ConfigureRecorder(aRecorder);
}
#endif
+9
View File
@@ -5,7 +5,12 @@
#ifndef DOM_CAMERA_GONK_RECORDER_PROFILES_H
#define DOM_CAMERA_GONK_RECORDER_PROFILES_H
#ifdef MOZ_WIDGET_GONK
#include <media/MediaProfiles.h>
#else
#include "FallbackCameraPlatform.h"
#endif
#include "ICameraControl.h"
#include "nsClassHashtable.h"
#include "nsRefPtrHashtable.h"
@@ -109,6 +114,7 @@ public:
static nsresult GetAll(uint32_t aCameraId,
nsTArray<nsRefPtr<ICameraControl::RecorderProfile>>& aProfiles);
#ifdef MOZ_WIDGET_GONK
// Configures the specified recorder using the specified profile.
//
// Return values:
@@ -118,6 +124,7 @@ public:
static nsresult ConfigureRecorder(android::GonkRecorder& aRecorder,
uint32_t aCameraId,
const nsAString& aProfileName);
#endif
protected:
GonkRecorderProfile(uint32_t aCameraId,
@@ -129,7 +136,9 @@ protected:
bool GetMimeType(android::output_format aContainer, nsAString& aMimeType);
bool IsValid() const { return mIsValid; };
#ifdef MOZ_WIDGET_GONK
nsresult ConfigureRecorder(android::GonkRecorder& aRecorder);
#endif
static already_AddRefed<GonkRecorderProfile> CreateProfile(uint32_t aCameraId,
int aQuality);
static ProfileHashtable* GetProfileHashtable(uint32_t aCameraId);
+6
View File
@@ -31,6 +31,10 @@ using namespace android;
using namespace mozilla;
using namespace mozilla::dom;
#ifndef MOZ_WIDGET_GONK
NS_IMPL_ISUPPORTS_INHERITED0(TestGonkCameraHardware, GonkCameraHardware);
#endif
static void
CopyFaceFeature(int32_t (&aDst)[2], bool aExists, const DOMPoint* aSrc)
{
@@ -633,6 +637,7 @@ TestGonkCameraHardware::PullParameters(GonkCameraParameters& aParams)
return NS_OK;
}
#ifdef MOZ_WIDGET_GONK
int
TestGonkCameraHardware::PushParameters(const CameraParameters& aParams)
{
@@ -658,6 +663,7 @@ TestGonkCameraHardware::PullParameters(CameraParameters& aParams)
String8 s(NS_LossyConvertUTF16toASCII(as).get());
aParams.unflatten(s);
}
#endif
int
TestGonkCameraHardware::StartRecording()
+6
View File
@@ -26,6 +26,10 @@ namespace mozilla {
class TestGonkCameraHardware : public android::GonkCameraHardware
{
#ifndef MOZ_WIDGET_GONK
NS_DECL_ISUPPORTS_INHERITED
#endif
public:
virtual nsresult Init() override;
virtual int AutoFocus() override;
@@ -40,8 +44,10 @@ public:
virtual int StartRecording() override;
virtual int StopRecording() override;
virtual int StoreMetaDataInBuffers(bool aEnabled) override;
#ifdef MOZ_WIDGET_GONK
virtual int PushParameters(const android::CameraParameters& aParams) override;
virtual void PullParameters(android::CameraParameters& aParams) override;
#endif
TestGonkCameraHardware(mozilla::nsGonkCameraControl* aTarget,
uint32_t aCameraId,
+11 -3
View File
@@ -4,7 +4,7 @@
# 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/.
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
if CONFIG['MOZ_B2G_CAMERA']:
MOCHITEST_MANIFESTS += ['test/mochitest.ini']
EXPORTS += [
@@ -36,13 +36,21 @@ if CONFIG['MOZ_B2G_CAMERA']:
'GonkCameraHwMgr.cpp',
'GonkCameraManager.cpp',
'GonkCameraParameters.cpp',
'GonkCameraSource.cpp',
'GonkRecorder.cpp',
'GonkRecorderProfiles.cpp',
'TestGonkCameraControl.cpp',
'TestGonkCameraHardware.cpp',
]
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
UNIFIED_SOURCES += [
'GonkCameraSource.cpp',
'GonkRecorder.cpp',
]
else:
UNIFIED_SOURCES += [
'FallbackCameraPlatform.cpp',
]
EXTRA_COMPONENTS += [
'CameraTestHardware.js',
'CameraTestHardware.manifest',
+51 -2
View File
@@ -68,12 +68,18 @@ function CameraTestSuite() {
this.logError = this._logError.bind(this);
this.expectedError = this._expectedError.bind(this);
this.expectedRejectGetCamera = this._expectedRejectGetCamera.bind(this);
this.expectedRejectConfigure = this._expectedRejectConfigure.bind(this);
this.expectedRejectAutoFocus = this._expectedRejectAutoFocus.bind(this);
this.expectedRejectTakePicture = this._expectedRejectTakePicture.bind(this);
this.expectedRejectStartRecording = this._expectedRejectStartRecording.bind(this);
this.expectedRejectStopRecording = this._expectedRejectStopRecording.bind(this);
this.rejectGetCamera = this._rejectGetCamera.bind(this);
this.rejectConfigure = this._rejectConfigure.bind(this);
this.rejectRelease = this._rejectRelease.bind(this);
this.rejectAutoFocus = this._rejectAutoFocus.bind(this);
this.rejectTakePicture = this._rejectTakePicture.bind(this);
this.rejectStartRecording = this._rejectStartRecording.bind(this);
this.rejectStopRecording = this._rejectStopRecording.bind(this);
this.rejectPreviewStarted = this._rejectPreviewStarted.bind(this);
var self = this;
@@ -95,20 +101,35 @@ CameraTestSuite.prototype = {
camera: null,
hw: null,
_lowMemSet: false,
_reloading: false,
/* Returns a promise which is resolved when the test suite is ready
to be executing individual test cases. One may provide the expected
hardware type here if desired; the default is to use the JS test
hardware. Use '' for the native emulated camera hardware. */
_setup: function(hwType) {
/* Depending on how we run the mochitest, we may not have the necessary
permissions yet. If we do need to request them, then we have to reload
the window to ensure the reconfiguration propogated properly. */
if (!SpecialPowers.hasPermission("camera", document)) {
info("requesting camera permission");
this._reloading = true;
SpecialPowers.addPermission("camera", true, document);
window.location.reload();
return Promise.reject();
}
info("has camera permission");
if (!isDefined(hwType)) {
hwType = 'hardware';
}
this._hwType = hwType;
return new Promise(function(resolve, reject) {
SpecialPowers.pushPrefEnv({'set': [['camera.control.test.enabled', hwType]]}, function() {
resolve();
SpecialPowers.pushPrefEnv({'set': [['camera.control.test.permission', true]]}, function() {
SpecialPowers.pushPrefEnv({'set': [['camera.control.test.enabled', hwType]]}, function() {
resolve();
});
});
});
},
@@ -158,6 +179,10 @@ CameraTestSuite.prototype = {
/* Execute all test cases (after setup is called). */
_run: function() {
if (this._reloading) {
return;
}
var test = this._tests.shift();
var self = this;
if (test) {
@@ -348,6 +373,10 @@ CameraTestSuite.prototype = {
return this.logError('get camera failed', e);
},
_rejectConfigure: function(e) {
return this.logError('set configuration failed', e);
},
_rejectRelease: function(e) {
return this.logError('release camera failed', e);
},
@@ -360,6 +389,14 @@ CameraTestSuite.prototype = {
return this.logError('take picture failed', e);
},
_rejectStartRecording: function(e) {
return this.logError('start recording failed', e);
},
_rejectStopRecording: function(e) {
return this.logError('stop recording failed', e);
},
_rejectPreviewStarted: function(e) {
return this.logError('preview start failed', e);
},
@@ -384,6 +421,10 @@ CameraTestSuite.prototype = {
return this.expectedError('expected get camera to fail');
},
_expectedRejectConfigure: function(p) {
return this.expectedError('expected set configuration to fail');
},
_expectedRejectAutoFocus: function(p) {
return this.expectedError('expected auto focus to fail');
},
@@ -391,6 +432,14 @@ CameraTestSuite.prototype = {
_expectedRejectTakePicture: function(p) {
return this.expectedError('expected take picture to fail');
},
_expectedRejectStartRecording: function(p) {
return this.expectedError('expected start recording to fail');
},
_expectedRejectStopRecording: function(p) {
return this.expectedError('expected stop recording to fail');
},
};
ise(SpecialPowers.sanityCheck(), "foo", "SpecialPowers passed sanity check");
+4
View File
@@ -2,8 +2,11 @@
support-files = camera_common.js
[test_camera.html]
skip-if = toolkit != 'gonk'
[test_camera_2.html]
skip-if = toolkit != 'gonk'
[test_camera_3.html]
skip-if = toolkit != 'gonk'
[test_camera_hardware_init_failure.html]
[test_camera_hardware_failures.html]
[test_bug975472.html]
@@ -14,4 +17,5 @@ support-files = camera_common.js
[test_bug1037322.html]
[test_bug1099390.html]
[test_bug1104913.html]
skip-if = toolkit != 'gonk'
[test_camera_bad_initial_config.html]
+40 -60
View File
@@ -12,76 +12,56 @@
<img src="#" alt="This image is going to load" id="testimage"/>
<script class="testbody" type="text/javascript;version=1.7">
var whichCamera = navigator.mozCameras.getListOfCameras()[0];
var config = {
mode: 'picture',
recorderProfile: 'high',
previewSize: {
width: 320,
height: 240
}
};
var suite = new CameraTestSuite();
function onError(e) {
ok(false, "Error: " + JSON.stringify(e));
}
suite.test('bug-1037322', function() {
var cameraManager = navigator.mozCameras;
var whichCamera = cameraManager.getListOfCameras()[0];
var Camera = {
cameraObj: null,
get viewfinder() {
return document.getElementById('viewfinder');
},
start: function test_start() {
function setConfig_onSuccess(cfg) {
// Check our specific configuration
ok(cfg.mode === config.mode, "Configured mode = " + cfg.mode);
ok(cfg.previewSize.width === config.previewSize.width &&
cfg.previewSize.height === config.previewSize.height,
"Configured preview size = " + cfg.previewSize.width + "x" + cfg.previewSize.height);
ok(cfg.recorderProfile === config.recorderProfile,
"Configured recorder profile = '" + cfg.recorderProfile + "'");
SimpleTest.finish();
var postConfig = {
mode: 'picture',
recorderProfile: 'low',
previewSize: {
width: 320,
height: 240
}
};
function getCamera_onSuccess(d) {
var camera = d.camera;
var cfg = d.configuration;
Camera.cameraObj = camera;
Camera.viewfinder.mozSrcObject = camera;
Camera.viewfinder.play();
function resolveGetCamera(p) {
suite.camera = p.camera;
// Check the default configuration
ok(cfg.mode === "unspecified", "Initial mode = " + cfg.mode);
ok(cfg.previewSize.width === 0 && cfg.previewSize.height === 0,
"Initial preview size = " + cfg.previewSize.width + "x" + cfg.previewSize.height);
ok(cfg.recorderProfile === "default",
"Initial recorder profile = '" + cfg.recorderProfile + "'");
// Apply our specific configuration
camera.setConfiguration(config).then(setConfig_onSuccess, onError);
}
var cfg = {
mode: 'unspecified',
};
navigator.mozCameras.getCamera(whichCamera, cfg).then(getCamera_onSuccess, onError);
// Check the default configuration
var cfg = p.configuration;
ok(cfg.mode === "unspecified", "Initial mode = " + cfg.mode);
ok(cfg.previewSize.width === 0 && cfg.previewSize.height === 0,
"Initial preview size = " + cfg.previewSize.width + "x" + cfg.previewSize.height);
ok(cfg.recorderProfile === "default",
"Initial recorder profile = '" + cfg.recorderProfile + "'");
}
}
SimpleTest.waitForExplicitFinish();
window.addEventListener('beforeunload', function() {
Camera.viewfinder.mozSrcObject = null;
if (Camera.cameraObj) {
Camera.cameraObj.release();
Camera.cameraObj = null;
function configure(p) {
// Apply our specific configuration
return suite.camera.setConfiguration(postConfig);
}
function resolveConfigure(cfg) {
// Check our specific configuration
ok(cfg.mode === postConfig.mode, "Configured mode = " + cfg.mode);
ok(cfg.previewSize.width === postConfig.previewSize.width &&
cfg.previewSize.height === postConfig.previewSize.height,
"Configured preview size = " + cfg.previewSize.width + "x" + cfg.previewSize.height);
ok(cfg.recorderProfile === postConfig.recorderProfile,
"Configured recorder profile = '" + cfg.recorderProfile + "'");
}
return cameraManager.getCamera(whichCamera, {mode: 'unspecified'})
.then(resolveGetCamera, suite.rejectGetCamera)
.then(configure)
.then(resolveConfigure, suite.rejectConfigure);
});
Camera.start();
suite.setup()
.then(suite.run);
</script>
</body>
+28 -81
View File
@@ -12,95 +12,42 @@
<img src="#" alt="This image is going to load" id="testimage"/>
<script class="testbody" type="text/javascript;version=1.7">
var whichCamera = navigator.mozCameras.getListOfCameras()[0];
var config = {
mode: 'picture',
recorderProfile: 'high',
previewSize: {
width: 352,
height: 288
}
};
var suite = new CameraTestSuite();
function onError(e) {
ok(false, "Error " + e);
}
suite.test('bug-1099390', function() {
function release(p) {
return new Promise(function(resolve, reject) {
var gotCloseEvent = false;
var gotReleasePromise = false;
var Camera = {
_cameraObj: null,
get viewfinder() {
return document.getElementById('viewfinder');
},
release: function release() {
viewfinder.mozSrcObject = null;
if (Camera._cameraObj) {
Camera._cameraObj.release();
Camera._cameraObj = null;
}
},
test: function test(cam) {
var gotCloseEvent = false;
var gotReleasePromise = false;
function gotAll() {
var all = gotCloseEvent && gotReleasePromise;
if (all) {
info("Got all expected notifications");
}
return all;
};
var onClosed = function(e) {
cam.removeEventListener('close', onClosed);
ok(!gotCloseEvent, "gotCloseEvent was " + gotCloseEvent);
ok(e.reason === "HardwareReleased", "'close' event reason is: " + e.reason);
gotCloseEvent = true;
if (gotAll()) {
SimpleTest.finish();
}
};
cam.addEventListener('close', onClosed);
var onResolve = function() {
ok(!gotReleasePromise, "gotReleasePromise was " + gotReleasePromise);
gotReleasePromise = true;
if (gotAll()) {
SimpleTest.finish();
}
};
cam.release().then(onResolve, onError);
}, // test()
start: function start() {
function onSuccess(d) {
Camera._cameraObj = d.camera;
var cam = d.camera;
var onPreviewStateChange = function(e) {
if (e.newState === 'started') {
cam.removeEventListener('previewstatechange', onPreviewStateChange);
Camera.test(cam);
var onClosed = function(e) {
suite.camera.removeEventListener('close', onClosed);
ok(!gotCloseEvent, "gotCloseEvent was " + gotCloseEvent);
ok(e.reason === "HardwareReleased", "'close' event reason is: " + e.reason);
gotCloseEvent = true;
if (gotReleasePromise) {
resolve();
}
}; // onPreviewStateChange
cam.addEventListener('previewstatechange', onPreviewStateChange);
}; // onSuccess()
};
navigator.mozCameras.getCamera(whichCamera, config).then(onSuccess, onError);
}, // start()
}
suite.camera.addEventListener('close', onClosed);
SimpleTest.waitForExplicitFinish();
suite.camera.release().then(function(p) {
ok(true, "released camera");
gotReleasePromise = true;
if (gotCloseEvent) {
resolve();
}
}).catch(reject);
});
}
window.addEventListener('beforeunload', function() {
Camera.release();
return suite.getCamera()
.then(release, suite.rejectGetCamera);
});
Camera.start();
suite.setup()
.then(suite.run);
</script>
</body>
+159 -226
View File
@@ -12,237 +12,170 @@
<img src="#" alt="This image is going to load" id="testimage"/>
<script class="testbody" type="text/javascript;version=1.7">
const Cr = Components.results;
var suite = new CameraTestSuite();
var whichCamera = navigator.mozCameras.getListOfCameras()[0];
var config = {
mode: 'picture',
recorderProfile: 'high',
previewSize: {
width: 320,
height: 240
}
};
var options = {
rotation: 0,
position: {
latitude: 43.645687,
longitude: -79.393661
},
dateTime: Date.now()
};
function onError(e) {
ok(false, "Error " + e);
}
function next() {
Camera.nextTest();
function cameraRelease(p) {
return suite.camera.release();
}
// The array of tests
var tests = [
{
key: "release-after-release",
func: function testAutoFocus(camera) {
function onSuccess(success) {
ok(true, "release() succeeded");
next();
}
function onError(error) {
ok(false, "release() failed with: " + error);
}
camera.release().then(onSuccess, onError);
}
},
{
key: "set-picture-size-after-release",
func: function testSetPictureSize(camera) {
try {
camera.setPictureSize({ width: 0, height: 0 });
} catch(e) {
ok(e.result === SpecialPowers.Cr.NS_ERROR_NOT_AVAILABLE,
"setPictureSize() failed with: " + e.name);
next();
}
}
},
{
key: "set-thumbnail-size-after-release",
func: function testSetThumbnailSize(camera) {
try {
camera.setThumbnailSize({ width: 0, height: 0 });
} catch(e) {
ok(e.result === SpecialPowers.Cr.NS_ERROR_NOT_AVAILABLE,
"setThumbnailSize() failed with: " + e.name);
next();
}
}
},
{
key: "get-sensor-angle-after-release",
func: function testGetSensorAngle(camera) {
ok(camera.sensorAngle == 0, "camera.sensorAngle = " + camera.sensorAngle);
next();
}
},
{
key: "resume-preview-after-release",
func: function testResumePreview(camera) {
try {
camera.resumePreview();
} catch(e) {
ok(e.result === SpecialPowers.Cr.NS_ERROR_NOT_AVAILABLE,
"resumePreview() failed with: " + e.name);
next();
}
}
},
{
key: "auto-focus-after-release",
func: function testAutoFocus(camera) {
function onSuccess(success) {
ok(false, "autoFocus() succeeded incorrectly");
}
function onError(error) {
ok(error.name === "NS_ERROR_NOT_AVAILABLE",
"autoFocus() failed with: " + error.name);
next();
}
camera.autoFocus().then(onSuccess, onError);
}
},
{
key: "take-picture-after-release",
func: function testTakePicture(camera) {
function onSuccess(picture) {
ok(false, "takePicture() succeeded incorrectly");
}
function onError(error) {
ok(error.name === "NS_ERROR_NOT_AVAILABLE",
"takePicture() failed with: " + error.name);
next();
}
camera.takePicture(null).then(onSuccess, onError);
}
},
{
key: "start-recording-after-release",
func: function testStartRecording(camera) {
function onSuccess(picture) {
ok(false, "startRecording() process succeeded incorrectly");
}
function onError(error) {
ok(error.name === "NS_ERROR_NOT_AVAILABLE",
"startRecording() failed with: " + error.name);
next();
}
var recordingOptions = {
profile: 'high',
rotation: 0
};
camera.startRecording(recordingOptions,
navigator.getDeviceStorage('videos'),
'bug975472.mp4').then(onSuccess, onError);
}
},
{
key: "stop-recording-after-release",
func: function testStopRecording(camera) {
try {
camera.stopRecording();
} catch(e) {
ok(e.result === SpecialPowers.Cr.NS_ERROR_NOT_AVAILABLE,
"stopRecording() failed with: " + e.name);
next();
}
}
},
{
key: "set-configuration-after-release",
func: function testSetConfiguration(camera) {
function onSuccess(picture) {
ok(false, "setConfiguration() process succeeded incorrectly");
}
function onError(error) {
ok(error.name === "NS_ERROR_NOT_AVAILABLE",
"setConfiguration() failed with: " + error.name);
next();
}
camera.setConfiguration(config).then(onSuccess, onError);
}
},
];
var testGenerator = function() {
for (var i = 0; i < tests.length; ++i ) {
yield tests[i];
}
}();
var Camera = {
cameraObj: null,
_otherPictureSize: null,
get viewfinder() {
return document.getElementById('viewfinder');
},
onCameraReady: function () {
Camera.nextTest = function() {
try {
var t = testGenerator.next();
info("test: " + t.key);
t.func(Camera.cameraObj);
} catch(e) {
if (e instanceof StopIteration) {
SimpleTest.finish();
} else {
throw e;
}
}
};
// Release the camera hardware, and call all of the asynchronous methods
// to make sure they properly handle being in this state.
Camera.cameraObj.release();
next();
},
release: function release() {
cameraObj = null;
},
start: function run_test() {
function onSuccess(d) {
var camera = d.camera;
Camera.cameraObj = camera;
var onPreviewStateChange = function(e) {
if (e.newState === 'started') {
info("viewfinder is ready and playing");
Camera.cameraObj.removeEventListener('previewstatechange', onPreviewStateChange);
Camera.onCameraReady();
}
};
camera.addEventListener('previewstatechange', onPreviewStateChange);
Camera.viewfinder.mozSrcObject = camera;
Camera.viewfinder.play();
ok(camera.capabilities.pictureSizes.length > 0,
"capabilities.pictureSizes.length = " +
camera.capabilities.pictureSizes.length);
Camera._otherPictureSize = camera.capabilities.pictureSizes.slice(-1)[0];
camera.setPictureSize(camera.capabilities.pictureSizes[0]);
options.pictureSize = Camera._otherPictureSize;
options.fileFormat = camera.capabilities.fileFormats[0];
info("getCamera callback, setting pictureSize = " + options.pictureSize.toSource());
};
navigator.mozCameras.getCamera(whichCamera, config).then(onSuccess, onError);
}
}
SimpleTest.waitForExplicitFinish();
window.addEventListener('beforeunload', function() {
Camera.viewfinder.mozSrcObject = null;
Camera.cameraObj.release();
Camera.cameraObj = null;
suite.test('release-after-release', function() {
return suite.getCamera()
.then(cameraRelease, suite.rejectGetCamera)
.then(cameraRelease, suite.rejectRelease)
.catch(suite.rejectRelease);
});
Camera.start();
suite.test('set-picture-size-after-release', function() {
function setPictureSize(p) {
try {
suite.camera.setPictureSize({ width: 0, height: 0 });
ok(false, "SetPictureSize() should have failed");
} catch(e) {
ok(e.result === SpecialPowers.Cr.NS_ERROR_NOT_AVAILABLE,
"setPictureSize() failed with: " + e.name);
}
}
return suite.getCamera()
.then(cameraRelease, suite.rejectGetCamera)
.then(setPictureSize, suite.rejectRelease);
});
suite.test('set-thumbnail-size-after-release', function() {
function setThumbnailSize(p) {
try {
suite.camera.setThumbnailSize({ width: 0, height: 0 });
ok(false, "SetThumbnailSize() should have failed");
} catch(e) {
ok(e.result === SpecialPowers.Cr.NS_ERROR_NOT_AVAILABLE,
"setThumbnailSize() failed with: " + e.name);
}
}
return suite.getCamera()
.then(cameraRelease, suite.rejectGetCamera)
.then(setThumbnailSize, suite.rejectRelease);
});
suite.test('get-sensor-angle-after-release', function() {
function getSensorAngle(p) {
ok(suite.camera.sensorAngle == 0, "camera.sensorAngle = " + suite.camera.sensorAngle);
}
return suite.getCamera()
.then(cameraRelease, suite.rejectGetCamera)
.then(getSensorAngle, suite.rejectRelease);
});
suite.test('resume-preview-after-release', function() {
function resumePreview(p) {
try {
suite.camera.resumePreview();
ok(false, "resumePreview() should have failed");
} catch(e) {
ok(e.result === SpecialPowers.Cr.NS_ERROR_NOT_AVAILABLE,
"resumePreview() failed with: " + e.name);
}
}
return suite.getCamera()
.then(cameraRelease, suite.rejectGetCamera)
.then(resumePreview, suite.rejectRelease);
});
suite.test('auto-focus-after-release', function() {
function autoFocus(p) {
return suite.camera.autoFocus();
}
function rejectAutoFocus(error) {
ok(error.name === "NS_ERROR_NOT_AVAILABLE",
"autoFocus() failed with: " + error.name);
return Promise.resolve();
}
return suite.getCamera()
.then(cameraRelease, suite.rejectGetCamera)
.then(autoFocus, suite.rejectRelease)
.then(suite.expectedRejectAutoFocus, rejectAutoFocus);
});
suite.test('take-picture-after-release', function() {
function takePicture(p) {
return suite.camera.takePicture(null);
}
function rejectTakePicture(error) {
ok(error.name === "NS_ERROR_NOT_AVAILABLE",
"takePicture() failed with: " + error.name);
return Promise.resolve();
}
return suite.getCamera()
.then(cameraRelease, suite.rejectGetCamera)
.then(takePicture, suite.rejectRelease)
.then(suite.expectedRejectTakePicture, rejectTakePicture);
});
suite.test('start-recording-after-release', function() {
function startRecording(p) {
return suite.camera.startRecording(
{
profile: 'high',
rotation: 0
},
navigator.getDeviceStorage('videos'),
'bug975472.mp4'
);
}
function rejectStartRecording(error) {
ok(error.name === "NS_ERROR_NOT_AVAILABLE",
"takePicture() failed with: " + error.name);
return Promise.resolve();
}
return suite.getCamera()
.then(cameraRelease, suite.rejectGetCamera)
.then(startRecording, suite.rejectRelease)
.then(suite.expectedRejectStartRecording, rejectStartRecording);
});
suite.test('stop-recording-after-release', function() {
function stopRecording(p) {
try {
suite.camera.stopRecording();
ok(false, "stopRecording() should have failed");
} catch(e) {
ok(e.result === SpecialPowers.Cr.NS_ERROR_NOT_AVAILABLE,
"stopRecording() failed with: " + e.name);
}
}
return suite.getCamera()
.then(cameraRelease, suite.rejectGetCamera)
.then(stopRecording, suite.rejectRelease);
});
suite.test('set-configuration-after-release', function() {
function configure(p) {
return suite.camera.setConfiguration(null);
}
function rejectConfigure(error) {
ok(error.name === "NS_ERROR_NOT_AVAILABLE",
"takePicture() failed with: " + error.name);
return Promise.resolve();
}
return suite.getCamera()
.then(cameraRelease, suite.rejectGetCamera)
.then(configure, suite.rejectRelease)
.then(suite.expectedRejectConfigure, rejectConfigure);
});
suite.setup()
.then(suite.run);
</script>
</body>
@@ -12,45 +12,31 @@
<img src="#" alt="This image is going to load" id="testimage"/>
<script class="testbody" type="text/javascript;version=1.7">
var whichCamera = navigator.mozCameras.getListOfCameras()[0];
var config = {
mode: 'picture',
recorderProfile: 'foobar',
};
var suite = new CameraTestSuite();
var Camera = {
cameraObj: null,
suite.test('bad-initial-config', function() {
function getCamera() {
var whichCamera = navigator.mozCameras.getListOfCameras()[0];
var config = {
mode: 'picture',
recorderProfile: 'foobar',
};
get viewfinder() {
return document.getElementById('viewfinder');
},
start: function test_start() {
function getCamera_onSuccess(d) {
ok(false, "Get camera should have failed");
SimpleTest.finish();
}
function getCamera_onError(e) {
ok(true, "Get camera failed as expected: " + JSON.stringify(e));
SimpleTest.finish();
}
navigator.mozCameras.getCamera(whichCamera, config).then(getCamera_onSuccess, getCamera_onError);
return navigator.mozCameras.getCamera(whichCamera, config);
}
}
SimpleTest.waitForExplicitFinish();
window.addEventListener('beforeunload', function() {
Camera.viewfinder.mozSrcObject = null;
if (Camera.cameraObj) {
Camera.cameraObj.release();
Camera.cameraObj = null;
function rejectGetCamera(error) {
ok(error.name === "NS_ERROR_NOT_AVAILABLE",
"getCamera() failed with: " + error.name);
return Promise.resolve();
}
return getCamera()
.then(suite.expectedRejectGetCamera, rejectGetCamera);
});
Camera.start();
suite.setup()
.then(suite.run);
</script>
</body>
+40 -15
View File
@@ -24,6 +24,7 @@
#include "nsIScriptContext.h"
#include "nsIDocument.h"
#include "nsIScriptGlobalObject.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/DataTransferBinding.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/BindingUtils.h"
@@ -82,7 +83,6 @@ DataTransfer::DataTransfer(nsISupports* aParent, uint32_t aEventType,
mDragImageX(0),
mDragImageY(0)
{
MOZ_ASSERT(mParent);
// For these events, we want to be able to add data to the data transfer, so
// clear the readonly state. Otherwise, the data is already present. For
// external usage, cache the data from the native clipboard or drag.
@@ -300,10 +300,16 @@ DataTransfer::GetFiles(ErrorResult& aRv)
nsCOMPtr<nsIFile> file = do_QueryInterface(supports);
if (!file)
continue;
nsRefPtr<File> domFile = File::CreateFromFile(GetParentObject(), file);
nsRefPtr<File> domFile;
if (file) {
domFile = File::CreateFromFile(GetParentObject(), file);
} else {
nsCOMPtr<FileImpl> fileImpl = do_QueryInterface(supports);
if (!fileImpl) {
continue;
}
domFile = new File(GetParentObject(), static_cast<FileImpl*>(fileImpl.get()));
}
if (!mFiles->Append(domFile)) {
aRv.Throw(NS_ERROR_FAILURE);
@@ -875,13 +881,6 @@ DataTransfer::GetTransferables(nsIDOMNode* aDragTarget)
{
MOZ_ASSERT(aDragTarget);
nsCOMPtr<nsISupportsArray> transArray =
do_CreateInstance("@mozilla.org/supports-array;1");
if (!transArray) {
return nullptr;
}
nsCOMPtr<nsINode> dragNode = do_QueryInterface(aDragTarget);
if (!dragNode) {
return nullptr;
@@ -891,12 +890,23 @@ DataTransfer::GetTransferables(nsIDOMNode* aDragTarget)
if (!doc) {
return nullptr;
}
nsILoadContext* loadContext = doc->GetLoadContext();
return GetTransferables(doc->GetLoadContext());
}
already_AddRefed<nsISupportsArray>
DataTransfer::GetTransferables(nsILoadContext* aLoadContext)
{
nsCOMPtr<nsISupportsArray> transArray =
do_CreateInstance("@mozilla.org/supports-array;1");
if (!transArray) {
return nullptr;
}
uint32_t count = mItems.Length();
for (uint32_t i = 0; i < count; i++) {
nsCOMPtr<nsITransferable> transferable = GetTransferable(i, loadContext);
nsCOMPtr<nsITransferable> transferable = GetTransferable(i, aLoadContext);
if (transferable) {
transArray->AppendElement(transferable);
}
@@ -1273,5 +1283,20 @@ DataTransfer::FillInExternalData(TransferItem& aItem, uint32_t aIndex)
aItem.mData = variant;
}
void
DataTransfer::FillAllExternalData()
{
if (mIsExternal) {
for (uint32_t i = 0; i < mItems.Length(); ++i) {
nsTArray<TransferItem>& itemArray = mItems[i];
for (uint32_t j = 0; j < itemArray.Length(); ++j) {
if (!itemArray[j].mData) {
FillInExternalData(itemArray[j], i);
}
}
}
}
}
} // namespace dom
} // namespace mozilla
+4
View File
@@ -185,6 +185,7 @@ public:
// converts the data into an array of nsITransferable objects to be used for
// drag and drop or clipboard operations.
already_AddRefed<nsISupportsArray> GetTransferables(nsIDOMNode* aDragTarget);
already_AddRefed<nsISupportsArray> GetTransferables(nsILoadContext* aLoadContext);
// converts the data for a single item at aIndex into an nsITransferable object.
already_AddRefed<nsITransferable> GetTransferable(uint32_t aIndex,
@@ -239,6 +240,9 @@ protected:
// clipboard for a given index.
void FillInExternalData(TransferItem& aItem, uint32_t aIndex);
friend class ContentParent;
void FillAllExternalData();
void MozClearDataAtHelper(const nsAString& aFormat, uint32_t aIndex,
mozilla::ErrorResult& aRv);
+53 -9
View File
@@ -15,6 +15,7 @@
#include "mozilla/TextComposition.h"
#include "mozilla/TextEvents.h"
#include "mozilla/TouchEvents.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/Event.h"
#include "mozilla/dom/TabParent.h"
#include "mozilla/dom/UIEvent.h"
@@ -81,6 +82,7 @@
#include "nsIController.h"
#include "nsICommandParams.h"
#include "mozilla/Services.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/HTMLLabelElement.h"
#include "mozilla/Preferences.h"
@@ -1133,6 +1135,29 @@ EventStateManager::DispatchCrossProcessEvent(WidgetEvent* aEvent,
*aStatus = nsEventStatus_eConsumeNoDefault;
return remote->SendRealTouchEvent(*aEvent->AsTouchEvent());
}
case eDragEventClass: {
if (remote->Manager()->IsContentParent()) {
remote->Manager()->AsContentParent()->MaybeInvokeDragSession(remote);
}
nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
uint32_t dropEffect = nsIDragService::DRAGDROP_ACTION_NONE;
uint32_t action = nsIDragService::DRAGDROP_ACTION_NONE;
if (dragSession) {
dragSession->DragEventDispatchedToChildProcess();
dragSession->GetDragAction(&action);
nsCOMPtr<nsIDOMDataTransfer> initialDataTransfer;
dragSession->GetDataTransfer(getter_AddRefs(initialDataTransfer));
if (initialDataTransfer) {
initialDataTransfer->GetDropEffectInt(&dropEffect);
}
}
bool retval = remote->SendRealDragEvent(*aEvent->AsDragEvent(),
action, dropEffect);
return retval;
}
default: {
MOZ_CRASH("Attempt to send non-whitelisted event?");
}
@@ -1189,6 +1214,13 @@ CrossProcessSafeEvent(const WidgetEvent& aEvent)
default:
return false;
}
case eDragEventClass:
switch (aEvent.message) {
case NS_DRAGDROP_OVER:
case NS_DRAGDROP_EXIT:
case NS_DRAGDROP_DROP:
return true;
}
default:
return false;
}
@@ -1522,6 +1554,12 @@ EventStateManager::BeginTrackingDragGesture(nsPresContext* aPresContext,
}
}
void
EventStateManager::BeginTrackingRemoteDragGesture(nsIContent* aContent)
{
mGestureDownContent = aContent;
mGestureDownFrameOwner = aContent;
}
//
// StopTrackingDragGesture
@@ -1623,8 +1661,9 @@ EventStateManager::GenerateDragGesture(nsPresContext* aPresContext,
nsCOMPtr<nsIContent> eventContent, targetContent;
mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(eventContent));
if (eventContent)
DetermineDragTarget(window, eventContent, dataTransfer,
getter_AddRefs(selection), getter_AddRefs(targetContent));
DetermineDragTargetAndDefaultData(window, eventContent, dataTransfer,
getter_AddRefs(selection),
getter_AddRefs(targetContent));
// Stop tracking the drag gesture now. This should stop us from
// reentering GenerateDragGesture inside DOM event processing.
@@ -1720,11 +1759,11 @@ EventStateManager::GenerateDragGesture(nsPresContext* aPresContext,
} // GenerateDragGesture
void
EventStateManager::DetermineDragTarget(nsPIDOMWindow* aWindow,
nsIContent* aSelectionTarget,
DataTransfer* aDataTransfer,
nsISelection** aSelection,
nsIContent** aTargetNode)
EventStateManager::DetermineDragTargetAndDefaultData(nsPIDOMWindow* aWindow,
nsIContent* aSelectionTarget,
DataTransfer* aDataTransfer,
nsISelection** aSelection,
nsIContent** aTargetNode)
{
*aTargetNode = nullptr;
@@ -3177,6 +3216,7 @@ EventStateManager::PostHandleEvent(nsPresContext* aPresContext,
// "none". This way, if the event is just ignored, no drop will be
// allowed.
uint32_t dropEffect = nsIDragService::DRAGDROP_ACTION_NONE;
uint32_t action = nsIDragService::DRAGDROP_ACTION_NONE;
if (nsEventStatus_eConsumeNoDefault == *aStatus) {
// if the event has a dataTransfer set, use it.
if (dragEvent->dataTransfer) {
@@ -3194,7 +3234,6 @@ EventStateManager::PostHandleEvent(nsPresContext* aPresContext,
// based on the effectAllowed below.
dataTransfer = initialDataTransfer;
uint32_t action;
dragSession->GetDragAction(&action);
// filter the drop effect based on the action. Use UNINITIALIZED as
@@ -3216,7 +3255,6 @@ EventStateManager::PostHandleEvent(nsPresContext* aPresContext,
// effectAllowed state doesn't include that type of action. If the
// dropEffect is "none", then the action will be 'none' so a drop will
// not be allowed.
uint32_t action = nsIDragService::DRAGDROP_ACTION_NONE;
if (effectAllowed == nsIDragService::DRAGDROP_ACTION_UNINITIALIZED ||
dropEffect & effectAllowed)
action = dropEffect;
@@ -3240,6 +3278,12 @@ EventStateManager::PostHandleEvent(nsPresContext* aPresContext,
// No one called preventDefault(), so handle drop only in chrome.
dragSession->SetOnlyChromeDrop(true);
}
if (ContentChild* child = ContentChild::GetSingleton()) {
child->SendUpdateDropEffect(action, dropEffect);
}
if (dispatchedToContentProcess) {
dragSession->SetCanDrop(true);
}
// now set the drop effect in the initial dataTransfer. This ensures
// that we can get the desired drop effect in the drop event.
+8 -5
View File
@@ -753,6 +753,9 @@ protected:
void BeginTrackingDragGesture(nsPresContext* aPresContext,
WidgetMouseEvent* aDownEvent,
nsIFrame* aDownFrame);
friend class mozilla::dom::TabParent;
void BeginTrackingRemoteDragGesture(nsIContent* aContent);
void StopTrackingDragGesture();
void GenerateDragGesture(nsPresContext* aPresContext,
WidgetMouseEvent* aEvent);
@@ -767,11 +770,11 @@ protected:
* aSelection - [out] set to the selection to be dragged
* aTargetNode - [out] the draggable node, or null if there isn't one
*/
void DetermineDragTarget(nsPIDOMWindow* aWindow,
nsIContent* aSelectionTarget,
dom::DataTransfer* aDataTransfer,
nsISelection** aSelection,
nsIContent** aTargetNode);
void DetermineDragTargetAndDefaultData(nsPIDOMWindow* aWindow,
nsIContent* aSelectionTarget,
dom::DataTransfer* aDataTransfer,
nsISelection** aSelection,
nsIContent** aTargetNode);
/*
* Perform the default handling for the dragstart/draggesture event and set up a
-14
View File
@@ -263,9 +263,6 @@ FileOutputStreamWrapper::FileOutputStreamWrapper(nsISupports* aFileStream,
uint64_t aLimit,
uint32_t aFlags)
: FileStreamWrapper(aFileStream, aFileHelper, aOffset, aLimit, aFlags)
#ifdef DEBUG
, mWriteThread(nullptr)
#endif
{
mOutputStream = do_QueryInterface(mFileStream);
NS_ASSERTION(mOutputStream, "This should always succeed!");
@@ -282,12 +279,6 @@ FileOutputStreamWrapper::Close()
nsresult rv = NS_OK;
if (!mFirstTime) {
NS_ASSERTION(PR_GetCurrentThread() == mWriteThread,
"Unsetting thread locals on wrong thread!");
mFileHelper->mMutableFile->UnsetThreadLocals();
}
if (mFlags & NOTIFY_CLOSE) {
nsCOMPtr<nsIRunnable> runnable = new CloseRunnable(mFileHelper);
@@ -313,11 +304,6 @@ FileOutputStreamWrapper::Write(const char* aBuf, uint32_t aCount,
if (mFirstTime) {
mFirstTime = false;
#ifdef DEBUG
mWriteThread = PR_GetCurrentThread();
#endif
mFileHelper->mMutableFile->SetThreadLocals();
nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(mOutputStream);
if (seekable) {
if (mOffset == UINT64_MAX) {
-3
View File
@@ -94,9 +94,6 @@ protected:
private:
nsCOMPtr<nsIOutputStream> mOutputStream;
#ifdef DEBUG
void* mWriteThread;
#endif
};
} // namespace dom
+1 -11
View File
@@ -20,8 +20,7 @@ class FileService;
/**
* This class provides a base for MutableFile implementations.
* The subclasses can override implementation of IsInvalid, CreateStream,
* SetThreadLocals and UnsetThreadLocals.
* The subclasses can override implementation of IsInvalid and CreateStream.
* (for example IDBMutableFile provides IndexedDB specific implementation).
*/
class MutableFileBase
@@ -49,15 +48,6 @@ public:
virtual already_AddRefed<nsISupports>
CreateStream(bool aReadOnly);
virtual void
SetThreadLocals()
{
}
virtual void
UnsetThreadLocals()
{
}
protected:
MutableFileBase();
-17
View File
@@ -275,23 +275,6 @@ IDBMutableFile::CreateStream(bool aReadOnly)
return result.forget();
}
void
IDBMutableFile::SetThreadLocals()
{
MOZ_ASSERT(IndexedDatabaseManager::IsMainProcess());
MOZ_ASSERT(mDatabase->GetOwner(), "Should have owner!");
QuotaManager::SetCurrentWindow(mDatabase->GetOwner());
}
void
IDBMutableFile::UnsetThreadLocals()
{
MOZ_ASSERT(IndexedDatabaseManager::IsMainProcess());
QuotaManager::SetCurrentWindow(nullptr);
}
JSObject*
IDBMutableFile::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
-6
View File
@@ -102,12 +102,6 @@ public:
virtual already_AddRefed<nsISupports>
CreateStream(bool aReadOnly) override;
virtual void
SetThreadLocals() override;
virtual void
UnsetThreadLocals() override;
// nsWrapperCache
virtual JSObject*
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
+87 -2
View File
@@ -28,6 +28,7 @@
#include "mozilla/dom/ContentBridgeChild.h"
#include "mozilla/dom/ContentBridgeParent.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/DataTransfer.h"
#include "mozilla/dom/DOMStorageIPC.h"
#include "mozilla/dom/ExternalHelperAppChild.h"
#include "mozilla/dom/ProcessGlobal.h"
@@ -68,6 +69,7 @@
#include "mozInlineSpellChecker.h"
#include "nsIConsoleListener.h"
#include "nsICycleCollectorListener.h"
#include "nsIDragService.h"
#include "nsIIPCBackgroundChildCreateCallback.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsIMemoryReporter.h"
@@ -176,7 +178,9 @@
#include "mozilla/dom/time/DateCacheCleaner.h"
#include "mozilla/dom/voicemail/VoicemailIPCService.h"
#include "mozilla/net/NeckoMessageUtils.h"
#include "mozilla/widget/PuppetBidiKeyboard.h"
#include "mozilla/RemoteSpellCheckEngineChild.h"
#include "GMPServiceChild.h"
using namespace mozilla;
using namespace mozilla::docshell;
@@ -189,11 +193,13 @@ using namespace mozilla::dom::mobilemessage;
using namespace mozilla::dom::telephony;
using namespace mozilla::dom::voicemail;
using namespace mozilla::embedding;
using namespace mozilla::gmp;
using namespace mozilla::hal_sandbox;
using namespace mozilla::ipc;
using namespace mozilla::layers;
using namespace mozilla::net;
using namespace mozilla::jsipc;
using namespace mozilla::widget;
#if defined(MOZ_WIDGET_GONK)
using namespace mozilla::system;
#endif
@@ -750,12 +756,14 @@ ContentChild::InitXPCOM()
if (NS_FAILED(svc->RegisterListener(mConsoleListener)))
NS_WARNING("Couldn't register console listener for child process");
bool isOffline;
bool isOffline, isLangRTL;
ClipboardCapabilities clipboardCaps;
DomainPolicyClone domainPolicy;
SendGetXPCOMProcessAttributes(&isOffline, &mAvailableDictionaries, &clipboardCaps, &domainPolicy);
SendGetXPCOMProcessAttributes(&isOffline, &isLangRTL, &mAvailableDictionaries,
&clipboardCaps, &domainPolicy);
RecvSetOffline(isOffline);
RecvBidiKeyboardNotify(isLangRTL);
if (domainPolicy.active()) {
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
@@ -997,6 +1005,13 @@ ContentChild::AllocPContentBridgeParent(mozilla::ipc::Transport* aTransport,
return mLastBridge;
}
PGMPServiceChild*
ContentChild::AllocPGMPServiceChild(mozilla::ipc::Transport* aTransport,
base::ProcessId aOtherProcess)
{
return GMPServiceChild::Create(aTransport, aOtherProcess);
}
PCompositorChild*
ContentChild::AllocPCompositorChild(mozilla::ipc::Transport* aTransport,
base::ProcessId aOtherProcess)
@@ -1257,6 +1272,18 @@ ContentChild::RecvUpdateServiceWorkerRegistrations()
return true;
}
bool
ContentChild::RecvBidiKeyboardNotify(const bool& aIsLangRTL)
{
// bidi is always of type PuppetBidiKeyboard* (because in the child, the only
// possible implementation of nsIBidiKeyboard is PuppetBidiKeyboard).
PuppetBidiKeyboard* bidi = static_cast<PuppetBidiKeyboard*>(nsContentUtils::GetBidiKeyboard());
if (bidi) {
bidi->SetIsLangRTL(aIsLangRTL);
}
return true;
}
static CancelableTask* sFirstIdleTask;
static void FirstIdle(void)
@@ -2725,6 +2752,64 @@ NextWindowID()
return (processBits << kWindowIDWindowBits) | windowBits;
}
bool
ContentChild::RecvInvokeDragSession(nsTArray<IPCDataTransfer>&& aTransfers,
const uint32_t& aAction)
{
nsCOMPtr<nsIDragService> dragService =
do_GetService("@mozilla.org/widget/dragservice;1");
if (dragService) {
dragService->StartDragSession();
nsCOMPtr<nsIDragSession> session;
dragService->GetCurrentSession(getter_AddRefs(session));
if (session) {
session->SetDragAction(aAction);
nsCOMPtr<DataTransfer> dataTransfer =
new DataTransfer(nullptr, NS_DRAGDROP_START, false, -1);
for (uint32_t i = 0; i < aTransfers.Length(); ++i) {
auto& items = aTransfers[i].items();
for (uint32_t j = 0; j < items.Length(); ++j) {
const IPCDataTransferItem& item = items[j];
nsCOMPtr<nsIWritableVariant> variant =
do_CreateInstance(NS_VARIANT_CONTRACTID);
NS_ENSURE_TRUE(variant, false);
if (item.data().type() == IPCDataTransferData::TnsString) {
const nsString& data = item.data().get_nsString();
variant->SetAsAString(data);
} else if (item.data().type() == IPCDataTransferData::TPBlobChild) {
BlobChild* blob = static_cast<BlobChild*>(item.data().get_PBlobChild());
nsRefPtr<FileImpl> fileImpl = blob->GetBlobImpl();
variant->SetAsISupports(fileImpl);
}
dataTransfer->SetDataWithPrincipal(NS_ConvertUTF8toUTF16(item.flavor()),
variant, i,
nsContentUtils::GetSystemPrincipal());
}
}
session->SetDataTransfer(dataTransfer);
}
}
return true;
}
bool
ContentChild::RecvEndDragSession(const bool& aDoneDrag,
const bool& aUserCancelled)
{
nsCOMPtr<nsIDragService> dragService =
do_GetService("@mozilla.org/widget/dragservice;1");
if (dragService) {
if (aUserCancelled) {
nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
if (dragSession) {
dragSession->UserCancelled();
}
}
dragService->EndDragSession(aDoneDrag);
}
return true;
}
} // namespace dom
} // namespace mozilla
+11
View File
@@ -115,6 +115,10 @@ public:
AllocPContentBridgeChild(mozilla::ipc::Transport* transport,
base::ProcessId otherProcess) override;
PGMPServiceChild*
AllocPGMPServiceChild(mozilla::ipc::Transport* transport,
base::ProcessId otherProcess) override;
PCompositorChild*
AllocPCompositorChild(mozilla::ipc::Transport* aTransport,
base::ProcessId aOtherProcess) override;
@@ -289,6 +293,8 @@ public:
virtual bool RecvUpdateServiceWorkerRegistrations() override;
virtual bool RecvBidiKeyboardNotify(const bool& isLangRTL) override;
virtual bool RecvNotifyVisited(const URIParams& aURI) override;
// auto remove when alertfinished is received.
nsresult AddRemoteAlertObserver(const nsString& aData, nsIObserver* aObserver);
@@ -386,6 +392,11 @@ public:
const OptionalURIParams& aDomain) override;
virtual bool RecvShutdown() override;
virtual bool
RecvInvokeDragSession(nsTArray<IPCDataTransfer>&& aTransfers,
const uint32_t& aAction) override;
virtual bool RecvEndDragSession(const bool& aDoneDrag,
const bool& aUserCancelled) override;
#ifdef ANDROID
gfxIntSize GetScreenSize() { return mScreenSize; }
#endif
+96 -2
View File
@@ -27,6 +27,7 @@
#include "AppProcessChecker.h"
#include "AudioChannelService.h"
#include "BlobParent.h"
#include "GMPServiceParent.h"
#include "IHistory.h"
#include "mozIApplication.h"
#ifdef ACCESSIBILITY
@@ -36,6 +37,7 @@
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/docshell/OfflineCacheUpdateParent.h"
#include "mozilla/dom/DataStoreService.h"
#include "mozilla/dom/DataTransfer.h"
#include "mozilla/dom/DOMStorageIPC.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/File.h"
@@ -100,6 +102,7 @@
#include "nsIDocument.h"
#include "nsIDOMGeoGeolocation.h"
#include "nsIDOMGeoPositionError.h"
#include "nsIDragService.h"
#include "mozilla/dom/WakeLock.h"
#include "nsIDOMWindow.h"
#include "nsIExternalProtocolService.h"
@@ -146,6 +149,8 @@
#include "private/pprio.h"
#include "ContentProcessManager.h"
#include "nsIBidiKeyboard.h"
#if defined(ANDROID) || defined(LINUX)
#include "nsSystemInfo.h"
#endif
@@ -222,6 +227,7 @@ using namespace mozilla::dom::mobilemessage;
using namespace mozilla::dom::telephony;
using namespace mozilla::dom::voicemail;
using namespace mozilla::embedding;
using namespace mozilla::gmp;
using namespace mozilla::hal;
using namespace mozilla::ipc;
using namespace mozilla::layers;
@@ -986,6 +992,23 @@ static nsIDocShell* GetOpenerDocShellHelper(Element* aFrameElement)
return docShell;
}
bool
ContentParent::RecvCreateGMPService()
{
return PGMPService::Open(this);
}
bool
ContentParent::RecvGetGMPPluginVersionForAPI(const nsCString& aAPI,
nsTArray<nsCString>&& aTags,
bool* aHasVersion,
nsCString* aVersion)
{
return GMPServiceParent::RecvGetGMPPluginVersionForAPI(aAPI, Move(aTags),
aHasVersion,
aVersion);
}
bool
ContentParent::RecvLoadPlugin(const uint32_t& aPluginId, nsresult* aRv)
{
@@ -2742,11 +2765,11 @@ ContentParent::RecvAddNewProcess(const uint32_t& aPid,
}
// Update offline settings.
bool isOffline;
bool isOffline, isLangRTL;
InfallibleTArray<nsString> unusedDictionaries;
ClipboardCapabilities clipboardCaps;
DomainPolicyClone domainPolicy;
RecvGetXPCOMProcessAttributes(&isOffline, &unusedDictionaries,
RecvGetXPCOMProcessAttributes(&isOffline, &isLangRTL, &unusedDictionaries,
&clipboardCaps, &domainPolicy);
mozilla::unused << content->SendSetOffline(isOffline);
MOZ_ASSERT(!clipboardCaps.supportsSelectionClipboard() &&
@@ -3008,6 +3031,13 @@ ContentParent::RecvPDocAccessibleConstructor(PDocAccessibleParent* aDoc, PDocAcc
return true;
}
PGMPServiceParent*
ContentParent::AllocPGMPServiceParent(mozilla::ipc::Transport* aTransport,
base::ProcessId aOtherProcess)
{
return GMPServiceParent::Create(aTransport, aOtherProcess);
}
PCompositorParent*
ContentParent::AllocPCompositorParent(mozilla::ipc::Transport* aTransport,
base::ProcessId aOtherProcess)
@@ -3057,6 +3087,7 @@ ContentParent::RecvGetProcessAttributes(ContentParentId* aCpId,
bool
ContentParent::RecvGetXPCOMProcessAttributes(bool* aIsOffline,
bool* aIsLangRTL,
InfallibleTArray<nsString>* dictionaries,
ClipboardCapabilities* clipboardCaps,
DomainPolicyClone* domainPolicy)
@@ -3066,6 +3097,13 @@ ContentParent::RecvGetXPCOMProcessAttributes(bool* aIsOffline,
DebugOnly<nsresult> rv = io->GetOffline(aIsOffline);
MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed getting offline?");
nsIBidiKeyboard* bidi = nsContentUtils::GetBidiKeyboard();
*aIsLangRTL = false;
if (bidi) {
bidi->IsLangRTL(aIsLangRTL);
}
nsCOMPtr<nsISpellChecker> spellChecker(do_GetService(NS_SPELLCHECKER_CONTRACTID));
MOZ_ASSERT(spellChecker, "No spell checker?");
@@ -4620,6 +4658,62 @@ ContentParent::RecvSetOfflinePermission(const Principal& aPrincipal)
return true;
}
void
ContentParent::MaybeInvokeDragSession(TabParent* aParent)
{
nsCOMPtr<nsIDragService> dragService =
do_GetService("@mozilla.org/widget/dragservice;1");
if (dragService && dragService->MaybeAddChildProcess(this)) {
// We need to send transferable data to child process.
nsCOMPtr<nsIDragSession> session;
dragService->GetCurrentSession(getter_AddRefs(session));
if (session) {
nsTArray<IPCDataTransfer> dataTransfers;
nsCOMPtr<nsIDOMDataTransfer> domTransfer;
session->GetDataTransfer(getter_AddRefs(domTransfer));
nsCOMPtr<DataTransfer> transfer = do_QueryInterface(domTransfer);
if (!transfer) {
// Pass NS_DRAGDROP_DROP to get DataTransfer with external
// drag formats cached.
transfer = new DataTransfer(nullptr, NS_DRAGDROP_DROP, true, -1);
session->SetDataTransfer(transfer);
}
// Note, even though this fills the DataTransfer object with
// external data, the data is usually transfered over IPC lazily when
// needed.
transfer->FillAllExternalData();
nsCOMPtr<nsILoadContext> lc = aParent ?
aParent->GetLoadContext() : nullptr;
nsCOMPtr<nsISupportsArray> transferables =
transfer->GetTransferables(lc);
nsContentUtils::TransferablesToIPCTransferables(transferables,
dataTransfers,
nullptr,
this);
uint32_t action;
session->GetDragAction(&action);
mozilla::unused << SendInvokeDragSession(dataTransfers, action);
}
}
}
bool
ContentParent::RecvUpdateDropEffect(const uint32_t& aDragAction,
const uint32_t& aDropEffect)
{
nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
if (dragSession) {
dragSession->SetDragAction(aDragAction);
nsCOMPtr<nsIDOMDataTransfer> dt;
dragSession->GetDataTransfer(getter_AddRefs(dt));
if (dt) {
dt->SetDropEffectInt(aDropEffect);
}
dragSession->UpdateDragEffect();
}
return true;
}
} // namespace dom
} // namespace mozilla
+13
View File
@@ -168,6 +168,12 @@ public:
TabId* aTabId) override;
virtual bool RecvBridgeToChildProcess(const ContentParentId& aCpId) override;
virtual bool RecvCreateGMPService() override;
virtual bool RecvGetGMPPluginVersionForAPI(const nsCString& aAPI,
nsTArray<nsCString>&& aTags,
bool* aHasPlugin,
nsCString* aVersion) override;
virtual bool RecvLoadPlugin(const uint32_t& aPluginId, nsresult* aRv) override;
virtual bool RecvConnectPluginBridge(const uint32_t& aPluginId, nsresult* aRv) override;
virtual bool RecvFindPlugins(const uint32_t& aPluginEpoch,
@@ -357,6 +363,7 @@ public:
virtual bool RecvFinishShutdown() override;
void MaybeInvokeDragSession(TabParent* aParent);
protected:
void OnChannelConnected(int32_t pid) override;
virtual void ActorDestroy(ActorDestroyReason why) override;
@@ -495,6 +502,9 @@ private:
static void ForceKillTimerCallback(nsITimer* aTimer, void* aClosure);
PGMPServiceParent*
AllocPGMPServiceParent(mozilla::ipc::Transport* aTransport,
base::ProcessId aOtherProcess) override;
PCompositorParent*
AllocPCompositorParent(mozilla::ipc::Transport* aTransport,
base::ProcessId aOtherProcess) override;
@@ -517,6 +527,7 @@ private:
bool* aIsForApp,
bool* aIsForBrowser) override;
virtual bool RecvGetXPCOMProcessAttributes(bool* aIsOffline,
bool* aIsLangRTL,
InfallibleTArray<nsString>* dictionaries,
ClipboardCapabilities* clipboardCaps,
DomainPolicyClone* domainPolicy)
@@ -800,6 +811,8 @@ private:
virtual bool RecvPDocAccessibleConstructor(PDocAccessibleParent* aDoc,
PDocAccessibleParent* aParentDoc, const uint64_t& aParentID) override;
virtual bool RecvUpdateDropEffect(const uint32_t& aDragAction,
const uint32_t& aDropEffect) override;
// If you add strong pointers to cycle collected objects here, be sure to
// release these objects in ShutDownProcess. See the comment there for more
// details.
+17
View File
@@ -135,5 +135,22 @@ union BlobConstructorParams
ParentBlobConstructorParams;
};
union IPCDataTransferData
{
nsString;
PBlob;
};
struct IPCDataTransferItem
{
nsCString flavor;
IPCDataTransferData data;
};
struct IPCDataTransfer
{
IPCDataTransferItem[] items;
};
} // namespace dom
} // namespace mozilla
+5
View File
@@ -44,6 +44,7 @@ using struct nsIntSize from "nsSize.h";
using class mozilla::WidgetKeyboardEvent from "ipc/nsGUIEventIPC.h";
using class mozilla::WidgetMouseEvent from "ipc/nsGUIEventIPC.h";
using class mozilla::WidgetWheelEvent from "ipc/nsGUIEventIPC.h";
using class mozilla::WidgetDragEvent from "ipc/nsGUIEventIPC.h";
using struct nsRect from "nsRect.h";
using class mozilla::WidgetSelectionEvent from "ipc/nsGUIEventIPC.h";
using class mozilla::WidgetTouchEvent from "ipc/nsGUIEventIPC.h";
@@ -496,6 +497,9 @@ parent:
prio(high) sync DispatchMouseEvent(WidgetMouseEvent event);
prio(high) sync DispatchKeyboardEvent(WidgetKeyboardEvent event);
InvokeDragSession(IPCDataTransfer[] transfers, uint32_t action,
nsCString visualData, uint32_t width, uint32_t height,
uint32_t stride, uint8_t format, int32_t dragAreaX, int32_t dragAreaY);
child:
/**
* Notify the remote browser that it has been Show()n on this
@@ -564,6 +568,7 @@ child:
MouseWheelEvent(WidgetWheelEvent event, ScrollableLayerGuid aGuid, uint64_t aInputBlockId);
RealTouchEvent(WidgetTouchEvent aEvent, ScrollableLayerGuid aGuid, uint64_t aInputBlockId);
RealTouchMoveEvent(WidgetTouchEvent aEvent, ScrollableLayerGuid aGuid, uint64_t aInputBlockId);
RealDragEvent(WidgetDragEvent aEvent, uint32_t aDragAction, uint32_t aDropEffect);
/**
* @see nsIDOMWindowUtils sendKeyEvent.
+24 -1
View File
@@ -25,7 +25,15 @@ include protocol PImageBridge;
include protocol PMemoryReportRequest;
include protocol PMobileConnection;
include protocol PNecko;
// FIXME This is pretty ridiculous, but we have to keep the order of the
// following 4 includes, or the parser is confused about PGMPContent
// bridging PContent and PGMP. As soon as it registers the bridge between
// PContent and PPluginModule it seems to think that PContent's parent and
// child live in the same process!
include protocol PGMPContent;
include protocol PGMPService;
include protocol PPluginModule;
include protocol PGMP;
include protocol PPrinting;
include protocol POfflineCacheUpdate;
include protocol PScreenManager;
@@ -362,6 +370,7 @@ prio(normal upto urgent) sync protocol PContent
parent opens PProcessHangMonitor;
parent opens PSharedBufferManager;
parent opens PImageBridge;
parent opens PGMPService;
child opens PBackground;
manages PAsmJSCacheEntry;
@@ -443,6 +452,12 @@ child:
async SpeakerManagerNotify();
/**
* Communication between the PuppetBidiKeyboard and the actual
* BidiKeyboard hosted by the parent
*/
async BidiKeyboardNotify(bool isLangRTL);
async UpdateServiceWorkerRegistrations();
async DataStoreNotify(uint32_t aAppId, nsString aName,
@@ -559,6 +574,9 @@ child:
prio(high) sync GetProfile()
returns (nsCString aProfile);
InvokeDragSession(IPCDataTransfer[] transfers, uint32_t action);
EndDragSession(bool aDoneDrag, bool aUserCancelled);
NuwaFreeze();
async DomainSetChanged(uint32_t aSetType, uint32_t aChangeType, OptionalURIParams aDomain);
@@ -602,7 +620,7 @@ parent:
sync GetProcessAttributes()
returns (ContentParentId cpId, bool isForApp, bool isForBrowser);
sync GetXPCOMProcessAttributes()
returns (bool isOffline, nsString[] dictionaries,
returns (bool isOffline, bool isLangRTL, nsString[] dictionaries,
ClipboardCapabilities clipboardCaps,
DomainPolicyClone domainPolicy);
@@ -612,6 +630,10 @@ parent:
returns (ContentParentId cpId, bool isForApp, bool isForBrowser, TabId tabId);
sync BridgeToChildProcess(ContentParentId cpId);
async CreateGMPService();
sync GetGMPPluginVersionForAPI(nsCString api, nsCString[] tags)
returns (bool hasPlugin, nsCString version);
/**
* This call connects the content process to a plugin process. While this
* call runs, a new PluginModuleParent will be created in the ContentChild
@@ -922,6 +944,7 @@ parent:
*/
async FinishShutdown();
UpdateDropEffect(uint32_t aDragAction, uint32_t aDropEffect);
both:
AsyncMessage(nsString aMessage, ClonedMessageData aData,
CpowEntry[] aCpows, Principal aPrincipal);
+193 -395
View File
@@ -10,6 +10,7 @@
#include "mozilla/dom/Element.h"
#include "mozilla/dom/TabParent.h"
#include "mozilla/Hal.h"
#include "mozilla/IntegerPrintfMacros.h"
#include "mozilla/Preferences.h"
#include "mozilla/Services.h"
#include "mozilla/unused.h"
@@ -49,22 +50,23 @@
# include <android/log.h>
# define LOG(fmt, ...) \
__android_log_print(ANDROID_LOG_INFO, \
"Goanna:ProcessPriorityManager", \
"Gecko:ProcessPriorityManager", \
fmt, ## __VA_ARGS__)
# define LOGP(fmt, ...) \
__android_log_print(ANDROID_LOG_INFO, \
"Goanna:ProcessPriorityManager", \
"[%schild-id=%llu, pid=%d] " fmt, \
"Gecko:ProcessPriorityManager", \
"[%schild-id=%" PRIu64 ", pid=%d] " fmt, \
NameWithComma().get(), \
(long long unsigned) ChildID(), Pid(), ## __VA_ARGS__)
static_cast<uint64_t>(ChildID()), Pid(), ## __VA_ARGS__)
#elif defined(ENABLE_LOGGING)
# define LOG(fmt, ...) \
printf("ProcessPriorityManager - " fmt "\n", ##__VA_ARGS__)
# define LOGP(fmt, ...) \
printf("ProcessPriorityManager[%schild-id=%llu, pid=%d] - " fmt "\n", \
printf("ProcessPriorityManager[%schild-id=%" PRIu64 ", pid=%d] - " \
fmt "\n", \
NameWithComma().get(), \
(unsigned long long) ChildID(), Pid(), ##__VA_ARGS__)
static_cast<uint64_t>(ChildID()), Pid(), ##__VA_ARGS__)
#elif defined(PR_LOGGING)
static PRLogModuleInfo*
@@ -80,9 +82,9 @@
("ProcessPriorityManager - " fmt, ##__VA_ARGS__))
# define LOGP(fmt, ...) \
PR_LOG(GetPPMLog(), PR_LOG_DEBUG, \
("ProcessPriorityManager[%schild-id=%llu, pid=%d] - " fmt, \
("ProcessPriorityManager[%schild-id=%" PRIu64 ", pid=%d] - " fmt, \
NameWithComma().get(), \
(unsigned long long) ChildID(), Pid(), ##__VA_ARGS__))
static_cast<uint64_t>(ChildID()), Pid(), ##__VA_ARGS__))
#else
#define LOG(fmt, ...)
#define LOGP(fmt, ...)
@@ -96,6 +98,42 @@ namespace {
class ParticularProcessPriorityManager;
class ProcessLRUPool final
{
public:
/**
* Creates a new process LRU pool for the specified priority.
*/
ProcessLRUPool(ProcessPriority aPriority, uint32_t aBias);
/**
* Used to remove a particular process priority manager from the LRU pool
* when the associated ContentParent is destroyed or its priority changes.
*/
void Remove(ParticularProcessPriorityManager* aParticularManager);
/**
* Used to add a particular process priority manager into the LRU pool when
* the associated ContentParent's priority changes.
*/
void Add(ParticularProcessPriorityManager* aParticularManager);
private:
ProcessPriority mPriority;
uint32_t mLRUPoolLevels;
uint32_t mLRUPoolSize;
uint32_t mBias;
nsTArray<ParticularProcessPriorityManager*> mLRUPool;
uint32_t CalculateLRULevel(uint32_t aLRUPoolIndex);
void AdjustLRUValues(
nsTArray<ParticularProcessPriorityManager*>::index_type aStart,
bool removed);
DISALLOW_EVIL_CONSTRUCTORS(ProcessLRUPool);
};
/**
* This singleton class does the work to implement the process priority manager
* in the main process. This class may not be used in child processes. (You
@@ -129,7 +167,7 @@ public:
*/
void SetProcessPriority(ContentParent* aContentParent,
ProcessPriority aPriority,
uint32_t aBackgroundLRU = 0);
uint32_t aLRU = 0);
/**
* If a magic testing-only pref is set, notify the observer service on the
@@ -138,13 +176,6 @@ public:
void FireTestOnlyObserverNotification(const char* aTopic,
const nsACString& aData = EmptyCString());
/**
* Does some process, other than the one handled by aParticularManager, have
* priority FOREGROUND_HIGH?
*/
bool OtherProcessHasHighPriority(
ParticularProcessPriorityManager* aParticularManager);
/**
* Does one of the child processes have priority FOREGROUND_HIGH?
*/
@@ -182,13 +213,21 @@ private:
void ObserveContentParentCreated(nsISupports* aContentParent);
void ObserveContentParentDestroyed(nsISupports* aSubject);
void ResetAllCPUPriorities();
nsDataHashtable<nsUint64HashKey, nsRefPtr<ParticularProcessPriorityManager> >
mParticularManagers;
/** True if the main process is holding a high-priority wakelock */
bool mHighPriority;
/** Contains the PIDs of child processes holding high-priority wakelocks */
nsTHashtable<nsUint64HashKey> mHighPriorityChildIDs;
/** Contains a pseudo-LRU list of background processes */
ProcessLRUPool mBackgroundLRUPool;
/** Contains a pseudo-LRU list of foreground processes */
ProcessLRUPool mForegroundLRUPool;
};
/**
@@ -267,23 +306,11 @@ public:
ProcessPriority CurrentPriority();
ProcessPriority ComputePriority();
ProcessCPUPriority ComputeCPUPriority(ProcessPriority aPriority);
void ScheduleResetPriority(const char* aTimeoutPref);
void ResetPriority();
void ResetPriorityNow();
void ResetCPUPriorityNow();
/**
* This overload is equivalent to SetPriorityNow(aPriority,
* ComputeCPUPriority()).
*/
void SetPriorityNow(ProcessPriority aPriority,
uint32_t aBackgroundLRU = 0);
void SetPriorityNow(ProcessPriority aPriority,
ProcessCPUPriority aCPUPriority,
uint32_t aBackgroundLRU = 0);
void SetPriorityNow(ProcessPriority aPriority, uint32_t aLRU = 0);
void ShutDown();
@@ -299,7 +326,7 @@ private:
ContentParent* mContentParent;
uint64_t mChildID;
ProcessPriority mPriority;
ProcessCPUPriority mCPUPriority;
uint32_t mLRU;
bool mHoldsCPUWakeLock;
bool mHoldsHighPriorityWakeLock;
@@ -311,46 +338,6 @@ private:
nsCOMPtr<nsITimer> mResetPriorityTimer;
};
class BackgroundProcessLRUPool final
{
public:
static BackgroundProcessLRUPool* Singleton();
/**
* Used to remove a ContentParent from background LRU pool when
* it is destroyed or its priority changed from BACKGROUND to others.
*/
void RemoveFromBackgroundLRUPool(ContentParent* aContentParent);
/**
* Used to add a ContentParent into background LRU pool when
* its priority changed to BACKGROUND from others.
*/
void AddIntoBackgroundLRUPool(ContentParent* aContentParent);
private:
static StaticAutoPtr<BackgroundProcessLRUPool> sSingleton;
int32_t mLRUPoolLevels;
int32_t mLRUPoolSize;
int32_t mLRUPoolAvailableIndex;
nsTArray<ContentParent*> mLRUPool;
uint32_t CalculateLRULevel(uint32_t aBackgroundLRUPoolIndex);
nsresult UpdateAvailableIndexInLRUPool(
ContentParent* aContentParent,
int32_t aTargetIndex = -1);
void ShiftLRUPool();
void EnsureLRUPool();
BackgroundProcessLRUPool();
DISALLOW_EVIL_CONSTRUCTORS(BackgroundProcessLRUPool);
};
/* static */ bool ProcessPriorityManagerImpl::sInitialized = false;
/* static */ bool ProcessPriorityManagerImpl::sPrefListenersRegistered = false;
/* static */ StaticRefPtr<ProcessPriorityManagerImpl>
@@ -421,6 +408,8 @@ ProcessPriorityManagerImpl::GetSingleton()
ProcessPriorityManagerImpl::ProcessPriorityManagerImpl()
: mHighPriority(false)
, mBackgroundLRUPool(PROCESS_PRIORITY_BACKGROUND, 1)
, mForegroundLRUPool(PROCESS_PRIORITY_FOREGROUND, 0)
{
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
RegisterWakeLockObserver(this);
@@ -439,8 +428,7 @@ ProcessPriorityManagerImpl::Init()
// The master process's priority never changes; set it here and then forget
// about it. We'll manage only subprocesses' priorities using the process
// priority manager.
hal::SetProcessPriority(getpid(), PROCESS_PRIORITY_MASTER,
PROCESS_CPU_PRIORITY_NORMAL);
hal::SetProcessPriority(getpid(), PROCESS_PRIORITY_MASTER);
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
if (os) {
@@ -496,13 +484,13 @@ ProcessPriorityManagerImpl::GetParticularProcessPriorityManager(
void
ProcessPriorityManagerImpl::SetProcessPriority(ContentParent* aContentParent,
ProcessPriority aPriority,
uint32_t aBackgroundLRU)
uint32_t aLRU)
{
MOZ_ASSERT(aContentParent);
nsRefPtr<ParticularProcessPriorityManager> pppm =
GetParticularProcessPriorityManager(aContentParent);
if (pppm) {
pppm->SetPriorityNow(aPriority, aBackgroundLRU);
pppm->SetPriorityNow(aPriority, aLRU);
}
}
@@ -517,18 +505,6 @@ ProcessPriorityManagerImpl::ObserveContentParentCreated(
GetParticularProcessPriorityManager(cp->AsContentParent());
}
static PLDHashOperator
EnumerateParticularProcessPriorityManagers(
const uint64_t& aKey,
nsRefPtr<ParticularProcessPriorityManager> aValue,
void* aUserData)
{
nsTArray<nsRefPtr<ParticularProcessPriorityManager> >* aArray =
static_cast<nsTArray<nsRefPtr<ParticularProcessPriorityManager> >*>(aUserData);
aArray->AppendElement(aValue);
return PL_DHASH_NEXT;
}
void
ProcessPriorityManagerImpl::ObserveContentParentDestroyed(nsISupports* aSubject)
{
@@ -542,44 +518,20 @@ ProcessPriorityManagerImpl::ObserveContentParentDestroyed(nsISupports* aSubject)
nsRefPtr<ParticularProcessPriorityManager> pppm;
mParticularManagers.Get(childID, &pppm);
if (pppm) {
// Unconditionally remove the manager from the pools
mBackgroundLRUPool.Remove(pppm);
mForegroundLRUPool.Remove(pppm);
pppm->ShutDown();
mParticularManagers.Remove(childID);
if (mHighPriorityChildIDs.Contains(childID)) {
mHighPriorityChildIDs.RemoveEntry(childID);
// We just lost a high-priority process; reset everyone's CPU priorities.
ResetAllCPUPriorities();
}
}
}
void
ProcessPriorityManagerImpl::ResetAllCPUPriorities( void )
{
nsTArray<nsRefPtr<ParticularProcessPriorityManager> > pppms;
mParticularManagers.EnumerateRead(
&EnumerateParticularProcessPriorityManagers,
&pppms);
for (uint32_t i = 0; i < pppms.Length(); i++) {
pppms[i]->ResetCPUPriorityNow();
}
}
bool
ProcessPriorityManagerImpl::OtherProcessHasHighPriority(
ParticularProcessPriorityManager* aParticularManager)
{
if (mHighPriority) {
return true;
} else if (mHighPriorityChildIDs.Contains(aParticularManager->ChildID())) {
return mHighPriorityChildIDs.Count() > 1;
}
return mHighPriorityChildIDs.Count() > 0;
}
bool
ProcessPriorityManagerImpl::ChildProcessHasHighPriority( void )
{
@@ -591,33 +543,34 @@ ProcessPriorityManagerImpl::NotifyProcessPriorityChanged(
ParticularProcessPriorityManager* aParticularManager,
ProcessPriority aOldPriority)
{
// This priority change can only affect other processes' priorities if we're
// changing to/from FOREGROUND_HIGH.
ProcessPriority newPriority = aParticularManager->CurrentPriority();
bool isPreallocated = aParticularManager->IsPreallocated();
if (aOldPriority < PROCESS_PRIORITY_FOREGROUND_HIGH &&
aParticularManager->CurrentPriority() <
PROCESS_PRIORITY_FOREGROUND_HIGH) {
return;
if (newPriority == PROCESS_PRIORITY_BACKGROUND &&
aOldPriority != PROCESS_PRIORITY_BACKGROUND &&
!isPreallocated) {
mBackgroundLRUPool.Add(aParticularManager);
} else if (newPriority != PROCESS_PRIORITY_BACKGROUND &&
aOldPriority == PROCESS_PRIORITY_BACKGROUND &&
!isPreallocated) {
mBackgroundLRUPool.Remove(aParticularManager);
}
if (aParticularManager->CurrentPriority() >=
PROCESS_PRIORITY_FOREGROUND_HIGH) {
if (newPriority == PROCESS_PRIORITY_FOREGROUND &&
aOldPriority != PROCESS_PRIORITY_FOREGROUND) {
mForegroundLRUPool.Add(aParticularManager);
} else if (newPriority != PROCESS_PRIORITY_FOREGROUND &&
aOldPriority == PROCESS_PRIORITY_FOREGROUND) {
mForegroundLRUPool.Remove(aParticularManager);
}
if (newPriority >= PROCESS_PRIORITY_FOREGROUND_HIGH &&
aOldPriority < PROCESS_PRIORITY_FOREGROUND_HIGH) {
mHighPriorityChildIDs.PutEntry(aParticularManager->ChildID());
} else {
} else if (newPriority < PROCESS_PRIORITY_FOREGROUND_HIGH &&
aOldPriority >= PROCESS_PRIORITY_FOREGROUND_HIGH) {
mHighPriorityChildIDs.RemoveEntry(aParticularManager->ChildID());
}
nsTArray<nsRefPtr<ParticularProcessPriorityManager> > pppms;
mParticularManagers.EnumerateRead(
&EnumerateParticularProcessPriorityManagers,
&pppms);
for (uint32_t i = 0; i < pppms.Length(); i++) {
if (pppms[i] != aParticularManager) {
pppms[i]->ResetCPUPriorityNow();
}
}
}
/* virtual */ void
@@ -633,10 +586,6 @@ ProcessPriorityManagerImpl::Notify(const WakeLockInformation& aInfo)
mHighPriority = false;
}
/* The main process got a high-priority wakelock change; reset everyone's
* CPU priorities. */
ResetAllCPUPriorities();
LOG("Got wake lock changed event. "
"Now mHighPriorityParent = %d\n", mHighPriority);
}
@@ -653,7 +602,7 @@ ParticularProcessPriorityManager::ParticularProcessPriorityManager(
: mContentParent(aContentParent)
, mChildID(aContentParent->ChildID())
, mPriority(PROCESS_PRIORITY_UNKNOWN)
, mCPUPriority(PROCESS_CPU_PRIORITY_NORMAL)
, mLRU(0)
, mHoldsCPUWakeLock(false)
, mHoldsHighPriorityWakeLock(false)
{
@@ -1015,96 +964,46 @@ ParticularProcessPriorityManager::ComputePriority()
PROCESS_PRIORITY_BACKGROUND;
}
ProcessCPUPriority
ParticularProcessPriorityManager::ComputeCPUPriority(ProcessPriority aPriority)
{
if (aPriority == PROCESS_PRIORITY_PREALLOC) {
return PROCESS_CPU_PRIORITY_LOW;
}
if (aPriority >= PROCESS_PRIORITY_FOREGROUND_HIGH) {
return PROCESS_CPU_PRIORITY_NORMAL;
}
return ProcessPriorityManagerImpl::GetSingleton()->
OtherProcessHasHighPriority(this) ?
PROCESS_CPU_PRIORITY_LOW :
PROCESS_CPU_PRIORITY_NORMAL;
}
void
ParticularProcessPriorityManager::ResetCPUPriorityNow()
{
SetPriorityNow(mPriority);
}
void
ParticularProcessPriorityManager::SetPriorityNow(ProcessPriority aPriority,
uint32_t aBackgroundLRU)
{
SetPriorityNow(aPriority, ComputeCPUPriority(aPriority), aBackgroundLRU);
}
void
ParticularProcessPriorityManager::SetPriorityNow(ProcessPriority aPriority,
ProcessCPUPriority aCPUPriority,
uint32_t aBackgroundLRU)
uint32_t aLRU)
{
if (aPriority == PROCESS_PRIORITY_UNKNOWN) {
MOZ_ASSERT(false);
return;
}
if (aBackgroundLRU > 0 &&
aPriority == PROCESS_PRIORITY_BACKGROUND &&
mPriority == PROCESS_PRIORITY_BACKGROUND) {
hal::SetProcessPriority(Pid(), mPriority, mCPUPriority, aBackgroundLRU);
nsPrintfCString ProcessPriorityWithBackgroundLRU("%s:%d",
ProcessPriorityToString(mPriority, mCPUPriority),
aBackgroundLRU);
FireTestOnlyObserverNotification("process-priority-with-background-LRU-set",
ProcessPriorityWithBackgroundLRU.get());
}
if (!mContentParent ||
!ProcessPriorityManagerImpl::PrefsEnabled() ||
(mPriority == aPriority && mCPUPriority == aCPUPriority)) {
if (!ProcessPriorityManagerImpl::PrefsEnabled() ||
!mContentParent ||
((mPriority == aPriority) && (mLRU == aLRU))) {
return;
}
// If the prefs were disabled after this ParticularProcessPriorityManager was
// created, we can at least avoid any further calls to
// hal::SetProcessPriority. Supporting dynamic enabling/disabling of the
// ProcessPriorityManager is mostly for testing.
if (!ProcessPriorityManagerImpl::PrefsEnabled()) {
if ((mPriority == aPriority) && (mLRU != aLRU)) {
mLRU = aLRU;
hal::SetProcessPriority(Pid(), mPriority, aLRU);
nsPrintfCString processPriorityWithLRU("%s:%d",
ProcessPriorityToString(mPriority), aLRU);
FireTestOnlyObserverNotification("process-priority-with-LRU-set",
processPriorityWithLRU.get());
return;
}
if (aPriority == PROCESS_PRIORITY_BACKGROUND &&
mPriority != PROCESS_PRIORITY_BACKGROUND &&
!IsPreallocated()) {
ProcessPriorityManager::AddIntoBackgroundLRUPool(mContentParent);
}
if (aPriority != PROCESS_PRIORITY_BACKGROUND &&
mPriority == PROCESS_PRIORITY_BACKGROUND &&
!IsPreallocated()) {
ProcessPriorityManager::RemoveFromBackgroundLRUPool(mContentParent);
}
LOGP("Changing priority from %s to %s.",
ProcessPriorityToString(mPriority, mCPUPriority),
ProcessPriorityToString(aPriority, aCPUPriority));
ProcessPriorityToString(mPriority),
ProcessPriorityToString(aPriority));
ProcessPriority oldPriority = mPriority;
mPriority = aPriority;
mCPUPriority = aCPUPriority;
hal::SetProcessPriority(Pid(), mPriority, mCPUPriority);
hal::SetProcessPriority(Pid(), mPriority);
if (oldPriority != mPriority) {
ProcessPriorityManagerImpl::GetSingleton()->
NotifyProcessPriorityChanged(this, oldPriority);
unused << mContentParent->SendNotifyProcessPriorityChanged(mPriority);
}
@@ -1113,12 +1012,7 @@ ParticularProcessPriorityManager::SetPriorityNow(ProcessPriority aPriority,
}
FireTestOnlyObserverNotification("process-priority-set",
ProcessPriorityToString(mPriority, mCPUPriority));
if (oldPriority != mPriority) {
ProcessPriorityManagerImpl::GetSingleton()->
NotifyProcessPriorityChanged(this, oldPriority);
}
ProcessPriorityToString(mPriority));
}
void
@@ -1133,10 +1027,6 @@ ParticularProcessPriorityManager::ShutDown()
mResetPriorityTimer = nullptr;
}
if (mPriority == PROCESS_PRIORITY_BACKGROUND && !IsPreallocated()) {
ProcessPriorityManager::RemoveFromBackgroundLRUPool(mContentParent);
}
mContentParent = nullptr;
}
@@ -1277,179 +1167,112 @@ ProcessPriorityManagerChild::CurrentProcessIsHighPriority()
mCachedPriority >= PROCESS_PRIORITY_FOREGROUND_HIGH;
}
/* static */ StaticAutoPtr<BackgroundProcessLRUPool>
BackgroundProcessLRUPool::sSingleton;
/* static */ BackgroundProcessLRUPool*
BackgroundProcessLRUPool::Singleton()
ProcessLRUPool::ProcessLRUPool(ProcessPriority aPriority, uint32_t aBias)
: mPriority(aPriority)
, mLRUPoolLevels(1)
, mBias(aBias)
{
if (!sSingleton) {
sSingleton = new BackgroundProcessLRUPool();
ClearOnShutdown(&sSingleton);
}
return sSingleton;
}
BackgroundProcessLRUPool::BackgroundProcessLRUPool()
{
EnsureLRUPool();
}
uint32_t
BackgroundProcessLRUPool::CalculateLRULevel(uint32_t aBackgroundLRUPoolIndex)
{
// Set LRU level of each background process and maintain LRU buffer as below:
// Priority background : LRU0
// Priority background+1: LRU1, LRU2
// Priority background+2: LRU3, LRU4, LRU5, LRU6
// Priority background+3: LRU7, LRU8, LRU9, LRU10, LRU11, LRU12, LRU13, LRU14
// ...
// Priority background+L-1: 2^(number of background LRU pool levels - 1)
// (End of buffer)
return (uint32_t)(log((float)aBackgroundLRUPoolIndex) / log(2.0));
}
void
BackgroundProcessLRUPool::EnsureLRUPool()
{
// We set mBackgroundLRUPoolLevels according to our pref.
// We set mLRUPoolLevels according to our pref.
// This value is used to set background process LRU pool
if (!NS_SUCCEEDED(Preferences::GetInt(
"dom.ipc.processPriorityManager.backgroundLRUPoolLevels",
&mLRUPoolLevels))) {
mLRUPoolLevels = 1;
}
const char* str = ProcessPriorityToString(aPriority);
nsPrintfCString pref("dom.ipc.processPriorityManager.%s.LRUPoolLevels", str);
if (mLRUPoolLevels <= 0) {
MOZ_CRASH();
}
Preferences::GetUint(pref.get(), &mLRUPoolLevels);
// GonkHal defines OOM_ADJUST_MAX is 15 and b2g.js defines
// PROCESS_PRIORITY_BACKGROUND's oom_score_adj is 667 and oom_adj is 10.
// This means we can only have at most (15 -10 + 1) = 6 background LRU levels.
// See bug 822325 comment 49
MOZ_ASSERT(mLRUPoolLevels <= 6);
// Similarly we can have at most 4 foreground LRU levels. We should really be
// getting rid of oom_adj and just rely on oom_score_adj only which would
// lift this constraint.
MOZ_ASSERT(aPriority != PROCESS_PRIORITY_BACKGROUND || mLRUPoolLevels <= 6);
MOZ_ASSERT(aPriority != PROCESS_PRIORITY_FOREGROUND || mLRUPoolLevels <= 4);
// LRU pool size = 2 ^ (number of background LRU pool levels) - 1
mLRUPoolSize = (1 << mLRUPoolLevels) - 1;
mLRUPoolAvailableIndex = 0;
LOG("Making %s LRU pool with size(%d)", str, mLRUPoolSize);
}
LOG("Making background LRU pool with size(%d)", mLRUPoolSize);
uint32_t
ProcessLRUPool::CalculateLRULevel(uint32_t aLRU)
{
// This is used to compute the LRU adjustment for the specified LRU position.
// We use power-of-two groups with increasing adjustments that look like the
// following:
mLRUPool.InsertElementsAt(0, mLRUPoolSize, (ContentParent*)nullptr);
// Priority : LRU0, LRU1
// Priority+1: LRU2, LRU3
// Priority+2: LRU4, LRU5, LRU6, LRU7
// Priority+3: LRU8, LRU9, LRU10, LRU11, LRU12, LRU12, LRU13, LRU14, LRU15
// ...
// Priority+L-1: 2^(number of LRU pool levels - 1)
// (End of buffer)
// Biasing the input can be used to shift the assignment
int exp;
unused << frexp(static_cast<double>(aLRU), &exp);
uint32_t level = std::max(exp - 1, 0);
return std::min(mLRUPoolLevels - 1, level);
}
void
BackgroundProcessLRUPool::RemoveFromBackgroundLRUPool(
ContentParent* aContentParent)
ProcessLRUPool::Remove(ParticularProcessPriorityManager* aParticularManager)
{
for (int32_t i = 0; i < mLRUPoolSize; i++) {
if (mLRUPool[i]) {
if (mLRUPool[i]->ChildID() == aContentParent->ChildID()) {
nsTArray<ParticularProcessPriorityManager*>::index_type index =
mLRUPool.IndexOf(aParticularManager);
mLRUPool[i] = nullptr;
LOG("Remove ChildID(%llu) from LRU pool", aContentParent->ChildID());
// After we remove this ContentParent from LRU pool, we still need to
// update the available index if the index of removed one is less than
// the available index we already have.
UpdateAvailableIndexInLRUPool(aContentParent, i);
break;
}
}
}
}
nsresult
BackgroundProcessLRUPool::UpdateAvailableIndexInLRUPool(
ContentParent* aContentParent,
int32_t aTargetIndex)
{
// If we specify which index we want to assign to mLRUPoolAvailableIndex,
// We have to make sure the index in LRUPool doesn't point to any
// ContentParent.
if (aTargetIndex >= 0 && aTargetIndex < mLRUPoolSize &&
aTargetIndex < mLRUPoolAvailableIndex &&
!mLRUPool[aTargetIndex]) {
mLRUPoolAvailableIndex = aTargetIndex;
return NS_OK;
}
// When we didn't specify any legal aTargetIndex, then we just check
// whether current mLRUPoolAvailableIndex points to any ContentParent or not.
if (mLRUPoolAvailableIndex >= 0 && mLRUPoolAvailableIndex < mLRUPoolSize &&
!(mLRUPool[mLRUPoolAvailableIndex])) {
return NS_OK;
}
// Both above way failed. So now we have to find proper value
// for mLRUPoolAvailableIndex.
// We are looking for an available index. We only shift process with
// LRU less than the available index should have, so we stop update
// mLRUPoolAvailableIndex from the for loop once we got a candidate.
mLRUPoolAvailableIndex = -1;
for (int32_t i = 0; i < mLRUPoolSize; i++) {
if (mLRUPool[i]) {
if (mLRUPool[i]->ChildID() == aContentParent->ChildID()) {
LOG("ChildID(%llu) already in LRU pool", aContentParent->ChildID());
MOZ_ASSERT(false);
return NS_ERROR_UNEXPECTED;
}
continue;
} else {
if (mLRUPoolAvailableIndex == -1) {
mLRUPoolAvailableIndex = i;
}
}
}
// If the LRUPool is already full, mLRUPoolAvailableIndex is still -1 after
// above loop finished. We should set mLRUPoolAvailableIndex
// to mLRUPoolSize - 1 in this case. Here uses the mod operator to do it:
// New mLRUPoolAvailableIndex either equals old mLRUPoolAvailableIndex, or
// mLRUPoolSize - 1 if old mLRUPoolAvailableIndex is -1.
mLRUPoolAvailableIndex =
(mLRUPoolAvailableIndex + mLRUPoolSize) % mLRUPoolSize;
return NS_OK;
}
void
BackgroundProcessLRUPool::ShiftLRUPool()
{
for (int32_t i = mLRUPoolAvailableIndex; i > 0; i--) {
mLRUPool[i] = mLRUPool[i - 1];
// Check whether i+1 is power of Two.
// If so, then it crossed a LRU group boundary and
// we need to assign its new process priority LRU.
if (!((i + 1) & i)) {
ProcessPriorityManagerImpl::GetSingleton()->SetProcessPriority(
mLRUPool[i], PROCESS_PRIORITY_BACKGROUND, CalculateLRULevel(i + 1));
}
}
}
void
BackgroundProcessLRUPool::AddIntoBackgroundLRUPool(
ContentParent* aContentParent)
{
// We have to make sure that we have correct available index in LRU pool
if (!NS_SUCCEEDED(
UpdateAvailableIndexInLRUPool(aContentParent))) {
if (index == nsTArray<ParticularProcessPriorityManager*>::NoIndex) {
return;
}
mLRUPool.RemoveElementAt(index);
AdjustLRUValues(index, /* removed */ true);
LOG("Remove ChildID(%" PRIu64 ") from %s LRU pool",
static_cast<uint64_t>(aParticularManager->ChildID()),
ProcessPriorityToString(mPriority));
}
/*
* Adjust the LRU values of all the processes in an LRU pool. When true the
* `removed` parameter indicates that the processes were shifted left because
* an element was removed; otherwise it means the elements were shifted right
* as an element was added.
*/
void
ProcessLRUPool::AdjustLRUValues(
nsTArray<ParticularProcessPriorityManager*>::index_type aStart,
bool removed)
{
uint32_t adj = (removed ? 1 : 0) + mBias;
for (nsTArray<ParticularProcessPriorityManager*>::index_type i = aStart;
i < mLRUPool.Length();
i++) {
/* Check whether i is a power of two. If so, then it crossed a LRU group
* boundary and we need to assign its new process priority LRU. Note that
* depending on the direction and the bias this test will pick different
* elements. */
if (((i + adj) & (i + adj - 1)) == 0) {
mLRUPool[i]->SetPriorityNow(mPriority, CalculateLRULevel(i + mBias));
}
}
}
void
ProcessLRUPool::Add(ParticularProcessPriorityManager* aParticularManager)
{
// Shift the list in the pool, so we have room at index 0 for the newly added
// ContentParent
ShiftLRUPool();
// manager
mLRUPool.InsertElementAt(0, aParticularManager);
AdjustLRUValues(1, /* removed */ false);
mLRUPool[0] = aContentParent;
LOG("Add ChildID(%llu) into LRU pool", aContentParent->ChildID());
LOG("Add ChildID(%" PRIu64 ") into %s LRU pool",
static_cast<uint64_t>(aParticularManager->ChildID()),
ProcessPriorityToString(mPriority));
}
} // namespace
@@ -1476,31 +1299,6 @@ ProcessPriorityManager::SetProcessPriority(ContentParent* aContentParent,
}
}
/* static */ void
ProcessPriorityManager::RemoveFromBackgroundLRUPool(
ContentParent* aContentParent)
{
MOZ_ASSERT(aContentParent);
BackgroundProcessLRUPool* singleton =
BackgroundProcessLRUPool::Singleton();
if (singleton) {
singleton->RemoveFromBackgroundLRUPool(aContentParent);
}
}
/* static */ void
ProcessPriorityManager::AddIntoBackgroundLRUPool(ContentParent* aContentParent)
{
MOZ_ASSERT(aContentParent);
BackgroundProcessLRUPool* singleton =
BackgroundProcessLRUPool::Singleton();
if (singleton) {
singleton->AddIntoBackgroundLRUPool(aContentParent);
}
}
/* static */ bool
ProcessPriorityManager::CurrentProcessIsForeground()
{
-12
View File
@@ -74,18 +74,6 @@ public:
*/
static bool AnyProcessHasHighPriority();
/**
* Used to remove a ContentParent from background LRU pool when
* it is destroyed or its priority changed from BACKGROUND to others.
*/
static void RemoveFromBackgroundLRUPool(dom::ContentParent* aContentParent);
/**
* Used to add a ContentParent into background LRU pool when
* its priority changed to BACKGROUND from others.
*/
static void AddIntoBackgroundLRUPool(dom::ContentParent* aContentParent);
private:
ProcessPriorityManager();
DISALLOW_EVIL_CONSTRUCTORS(ProcessPriorityManager);
+38
View File
@@ -2406,6 +2406,44 @@ TabChild::RecvRealTouchMoveEvent(const WidgetTouchEvent& aEvent,
return RecvRealTouchEvent(aEvent, aGuid, aInputBlockId);
}
bool
TabChild::RecvRealDragEvent(const WidgetDragEvent& aEvent,
const uint32_t& aDragAction,
const uint32_t& aDropEffect)
{
WidgetDragEvent localEvent(aEvent);
localEvent.widget = mWidget;
nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
if (dragSession) {
dragSession->SetDragAction(aDragAction);
nsCOMPtr<nsIDOMDataTransfer> initialDataTransfer;
dragSession->GetDataTransfer(getter_AddRefs(initialDataTransfer));
if (initialDataTransfer) {
initialDataTransfer->SetDropEffectInt(aDropEffect);
}
}
if (aEvent.message == NS_DRAGDROP_DROP) {
bool canDrop = true;
if (!dragSession || NS_FAILED(dragSession->GetCanDrop(&canDrop)) ||
!canDrop) {
localEvent.message = NS_DRAGDROP_EXIT;
}
} else if (aEvent.message == NS_DRAGDROP_OVER) {
nsCOMPtr<nsIDragService> dragService =
do_GetService("@mozilla.org/widget/dragservice;1");
if (dragService) {
// This will dispatch 'drag' event at the source if the
// drag transaction started in this process.
dragService->FireDragEventAtSource(NS_DRAGDROP_DRAG);
}
}
APZCCallbackHelper::DispatchWidgetEvent(localEvent);
return true;
}
void
TabChild::RequestNativeKeyBindings(AutoCacheNativeKeyCommands* aAutoCache,
WidgetKeyboardEvent* aEvent)
+3
View File
@@ -353,6 +353,9 @@ public:
const bool& aIgnoreRootScrollFrame) override;
virtual bool RecvRealMouseMoveEvent(const mozilla::WidgetMouseEvent& event) override;
virtual bool RecvRealMouseButtonEvent(const mozilla::WidgetMouseEvent& event) override;
virtual bool RecvRealDragEvent(const WidgetDragEvent& aEvent,
const uint32_t& aDragAction,
const uint32_t& aDropEffect) override;
virtual bool RecvRealKeyEvent(const mozilla::WidgetKeyboardEvent& event,
const MaybeNativeKeyBinding& aBindings) override;
virtual bool RecvMouseWheelEvent(const mozilla::WidgetWheelEvent& event,
+121
View File
@@ -12,11 +12,13 @@
#include "mozIApplication.h"
#include "mozilla/BrowserElementParent.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/DataTransfer.h"
#include "mozilla/dom/PContentPermissionRequestParent.h"
#include "mozilla/dom/ServiceWorkerRegistrar.h"
#include "mozilla/dom/indexedDB/ActorsParent.h"
#include "mozilla/plugins/PluginWidgetParent.h"
#include "mozilla/EventStateManager.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/Hal.h"
#include "mozilla/ipc/DocumentRendererParent.h"
#include "mozilla/jsipc/CrossProcessObjectWrappers.h"
@@ -29,7 +31,9 @@
#include "mozilla/TextEvents.h"
#include "mozilla/TouchEvents.h"
#include "mozilla/unused.h"
#include "BlobParent.h"
#include "nsCOMPtr.h"
#include "nsContentAreaDragDrop.h"
#include "nsContentPermissionHelper.h"
#include "nsContentUtils.h"
#include "nsDebug.h"
@@ -76,6 +80,7 @@
#include "nsNetCID.h"
#include "nsIAuthInformation.h"
#include "nsIAuthPromptCallback.h"
#include "SourceSurfaceRawData.h"
#include "nsAuthInformationHolder.h"
#include "nsICancelable.h"
#include "gfxPrefs.h"
@@ -275,6 +280,8 @@ TabParent::TabParent(nsIContentParent* aManager,
, mAppPackageFileDescriptorSent(false)
, mSendOfflineStatus(true)
, mChromeFlags(aChromeFlags)
, mDragAreaX(0)
, mDragAreaY(0)
, mInitedByParent(false)
, mTabId(aTabId)
, mCreatingWindow(false)
@@ -1220,6 +1227,17 @@ TabParent::GetLayoutDeviceToCSSScale()
: 0.0f);
}
bool
TabParent::SendRealDragEvent(WidgetDragEvent& event, uint32_t aDragAction,
uint32_t aDropEffect)
{
if (mIsDestroyed) {
return false;
}
event.refPoint += GetChildProcessOffset();
return PBrowserParent::SendRealDragEvent(event, aDragAction, aDropEffect);
}
CSSPoint TabParent::AdjustTapToChildWidget(const CSSPoint& aPoint)
{
return aPoint + (LayoutDevicePoint(mChildProcessOffsetAtTouchStart) * GetLayoutDeviceToCSSScale());
@@ -2939,6 +2957,109 @@ TabParent::RecvAsyncAuthPrompt(const nsCString& aUri,
return rv == NS_OK;
}
bool
TabParent::RecvInvokeDragSession(nsTArray<IPCDataTransfer>&& aTransfers,
const uint32_t& aAction,
const nsCString& aVisualDnDData,
const uint32_t& aWidth, const uint32_t& aHeight,
const uint32_t& aStride, const uint8_t& aFormat,
const int32_t& aDragAreaX, const int32_t& aDragAreaY)
{
mInitialDataTransferItems.Clear();
nsPresContext* pc = mFrameElement->OwnerDoc()->GetShell()->GetPresContext();
EventStateManager* esm = pc->EventStateManager();
for (uint32_t i = 0; i < aTransfers.Length(); ++i) {
auto& items = aTransfers[i].items();
nsTArray<DataTransferItem>* itemArray = mInitialDataTransferItems.AppendElement();
for (uint32_t j = 0; j < items.Length(); ++j) {
const IPCDataTransferItem& item = items[j];
DataTransferItem* localItem = itemArray->AppendElement();
localItem->mFlavor = item.flavor();
if (item.data().type() == IPCDataTransferData::TnsString) {
localItem->mType = DataTransferItem::DataType::eString;
localItem->mStringData = item.data().get_nsString();
} else {
localItem->mType = DataTransferItem::DataType::eBlob;
BlobParent* blobParent =
static_cast<BlobParent*>(item.data().get_PBlobParent());
if (blobParent) {
localItem->mBlobData = blobParent->GetBlobImpl();
}
}
}
}
if (Manager()->IsContentParent()) {
nsCOMPtr<nsIDragService> dragService =
do_GetService("@mozilla.org/widget/dragservice;1");
if (dragService) {
dragService->MaybeAddChildProcess(Manager()->AsContentParent());
}
}
if (aVisualDnDData.IsEmpty()) {
mDnDVisualization = nullptr;
} else {
mDnDVisualization =
new mozilla::gfx::SourceSurfaceRawData();
mozilla::gfx::SourceSurfaceRawData* raw =
static_cast<mozilla::gfx::SourceSurfaceRawData*>(mDnDVisualization.get());
raw->InitWrappingData(
reinterpret_cast<uint8_t*>(const_cast<nsCString&>(aVisualDnDData).BeginWriting()),
mozilla::gfx::IntSize(aWidth, aHeight), aStride,
static_cast<mozilla::gfx::SurfaceFormat>(aFormat), false);
raw->GuaranteePersistance();
}
mDragAreaX = aDragAreaX;
mDragAreaY = aDragAreaY;
esm->BeginTrackingRemoteDragGesture(mFrameElement);
return true;
}
void
TabParent::AddInitialDnDDataTo(DataTransfer* aDataTransfer)
{
for (uint32_t i = 0; i < mInitialDataTransferItems.Length(); ++i) {
nsTArray<DataTransferItem>& itemArray = mInitialDataTransferItems[i];
for (uint32_t j = 0; j < itemArray.Length(); ++j) {
DataTransferItem& item = itemArray[j];
nsCOMPtr<nsIWritableVariant> variant =
do_CreateInstance(NS_VARIANT_CONTRACTID);
if (!variant) {
break;
}
// Special case kFilePromiseMime so that we get the right
// nsIFlavorDataProvider for it.
if (item.mFlavor.EqualsLiteral(kFilePromiseMime)) {
nsRefPtr<nsISupports> flavorDataProvider =
new nsContentAreaDragDropDataProvider();
variant->SetAsISupports(flavorDataProvider);
} else if (item.mType == DataTransferItem::DataType::eString) {
variant->SetAsAString(item.mStringData);
} else if (item.mType == DataTransferItem::DataType::eBlob) {
variant->SetAsISupports(item.mBlobData);
}
// Using system principal here, since once the data is on parent process
// side, it can be handled as being from browser chrome or OS.
aDataTransfer->SetDataWithPrincipal(NS_ConvertUTF8toUTF16(item.mFlavor),
variant, i,
nsContentUtils::GetSystemPrincipal());
}
}
mInitialDataTransferItems.Clear();
}
void
TabParent::TakeDragVisualization(RefPtr<mozilla::gfx::SourceSurface>& aSurface,
int32_t& aDragAreaX, int32_t& aDragAreaY)
{
aSurface = mDnDVisualization.forget();
aDragAreaX = mDragAreaX;
aDragAreaY = mDragAreaY;
}
NS_IMETHODIMP
FakeChannel::OnAuthAvailable(nsISupports *aContext, nsIAuthInformation *aAuthInfo)
{
+40
View File
@@ -13,7 +13,9 @@
#include "mozilla/dom/PFilePickerParent.h"
#include "mozilla/dom/TabContext.h"
#include "mozilla/EventForwards.h"
#include "mozilla/dom/File.h"
#include "mozilla/WritingModes.h"
#include "mozilla/RefPtr.h"
#include "nsCOMPtr.h"
#include "nsIAuthPromptProvider.h"
#include "nsIBrowserDOMWindow.h"
@@ -52,11 +54,17 @@ namespace widget {
struct IMENotification;
}
namespace gfx {
class SourceSurface;
class DataSourceSurface;
}
namespace dom {
class ClonedMessageData;
class nsIContentParent;
class Element;
class DataTransfer;
struct StructuredCloneData;
class TabParent final : public PBrowserParent
@@ -271,6 +279,8 @@ public:
int32_t aCharCode, int32_t aModifiers,
bool aPreventDefault);
bool SendRealMouseEvent(mozilla::WidgetMouseEvent& event);
bool SendRealDragEvent(mozilla::WidgetDragEvent& aEvent, uint32_t aDragAction,
uint32_t aDropEffect);
bool SendMouseWheelEvent(mozilla::WidgetWheelEvent& event);
bool SendRealKeyEvent(mozilla::WidgetKeyboardEvent& event);
bool SendRealTouchEvent(WidgetTouchEvent& event);
@@ -368,6 +378,18 @@ public:
bool RequestNotifyLayerTreeCleared();
bool LayerTreeUpdate(bool aActive);
virtual bool
RecvInvokeDragSession(nsTArray<IPCDataTransfer>&& aTransfers,
const uint32_t& aAction,
const nsCString& aVisualDnDData,
const uint32_t& aWidth, const uint32_t& aHeight,
const uint32_t& aStride, const uint8_t& aFormat,
const int32_t& aDragAreaX, const int32_t& aDragAreaY) override;
void AddInitialDnDDataTo(DataTransfer* aDataTransfer);
void TakeDragVisualization(RefPtr<mozilla::gfx::SourceSurface>& aSurface,
int32_t& aDragAreaX, int32_t& aDragAreaY);
protected:
bool ReceiveMessage(const nsString& aMessage,
bool aSync,
@@ -474,6 +496,24 @@ private:
uint32_t mChromeFlags;
struct DataTransferItem
{
nsCString mFlavor;
nsString mStringData;
nsRefPtr<mozilla::dom::FileImpl> mBlobData;
enum DataType
{
eString,
eBlob
};
DataType mType;
};
nsTArray<nsTArray<DataTransferItem>> mInitialDataTransferItems;
mozilla::RefPtr<gfx::DataSourceSurface> mDnDVisualization;
int32_t mDragAreaX;
int32_t mDragAreaY;
// When true, the TabParent is initialized without child side's request.
// When false, the TabParent is initialized by window.open() from child side.
bool mInitedByParent;
+1
View File
@@ -123,6 +123,7 @@ LOCAL_INCLUDES += [
'/embedding/components/printingui/ipc',
'/extensions/cookie',
'/extensions/spellcheck/src',
'/gfx/2d',
'/hal/sandbox',
'/layout/base',
'/netwerk/base',
+1 -1
View File
@@ -51,7 +51,7 @@ function setPref(pref, value) {
setPref('dom.ipc.processPriorityManager.testMode', true);
setPref('dom.ipc.processPriorityManager.enabled', true);
setPref('dom.ipc.processPriorityManager.backgroundLRUPoolLevels', 2);
setPref('dom.ipc.processPriorityManager.BACKGROUND.LRUPoolLevels', 2);
function runTest()
{
+1 -1
View File
@@ -51,7 +51,7 @@ function setPref(pref, value) {
setPref('dom.ipc.processPriorityManager.testMode', true);
setPref('dom.ipc.processPriorityManager.enabled', true);
setPref('dom.ipc.processPriorityManager.backgroundLRUPoolLevels', 2);
setPref('dom.ipc.processPriorityManager.BACKGROUND.LRUPoolLevels', 2);
setPref('dom.ipc.processPrelaunch.testMode', true); // For testing deadlock.
function runTest()
+2 -6
View File
@@ -14,12 +14,8 @@ namespace mozilla {
extern PRLogModuleInfo* gMediaDecoderLog;
#define SINK_LOG(msg, ...) \
PR_LOG(gMediaDecoderLog, PR_LOG_DEBUG, ("AudioSink=%p " msg, this, ##__VA_ARGS__))
#define SINK_LOG_V(msg, ...) \
PR_BEGIN_MACRO \
if (!PR_GetEnv("MOZ_QUIET")) { \
SINK_LOG(msg, ##__VA_ARGS__); \
} \
PR_END_MACRO
#define SINK_LOG_V(msg, ...) \
PR_LOG(gMediaDecoderLog, PR_LOG_DEBUG+1, ("AudioSink=%p " msg, this, ##__VA_ARGS__))
#else
#define SINK_LOG(msg, ...)
#define SINK_LOG_V(msg, ...)
+3 -2
View File
@@ -126,6 +126,7 @@ StaticRefPtr<MediaMemoryTracker> MediaMemoryTracker::sUniqueInstance;
PRLogModuleInfo* gStateWatchingLog;
PRLogModuleInfo* gMediaPromiseLog;
PRLogModuleInfo* gMediaTimerLog;
PRLogModuleInfo* gMediaSampleLog;
void
MediaDecoder::InitStatics()
@@ -134,11 +135,11 @@ MediaDecoder::InitStatics()
SharedThreadPool::InitStatics();
// Log modules.
#ifdef PR_LOGGING
gMediaDecoderLog = PR_NewLogModule("MediaDecoder");
#endif
gMediaPromiseLog = PR_NewLogModule("MediaPromise");
gStateWatchingLog = PR_NewLogModule("StateWatching");
gMediaTimerLog = PR_NewLogModule("MediaTimer");
gMediaSampleLog = PR_NewLogModule("MediaSample");
}
NS_IMPL_ISUPPORTS(MediaMemoryTracker, nsIMemoryReporter)
+10 -13
View File
@@ -52,25 +52,21 @@ using namespace mozilla::media;
#define NS_DispatchToMainThread(...) CompileError_UseAbstractThreadDispatchInstead
// avoid redefined macro in unified build
#undef LOG
#undef DECODER_LOG
#undef VERBOSE_LOG
#ifdef PR_LOGGING
extern PRLogModuleInfo* gMediaDecoderLog;
extern PRLogModuleInfo* gMediaSampleLog;
#define LOG(m, l, x, ...) \
PR_LOG(m, l, ("Decoder=%p " x, mDecoder.get(), ##__VA_ARGS__))
#define DECODER_LOG(x, ...) \
PR_LOG(gMediaDecoderLog, PR_LOG_DEBUG, ("Decoder=%p " x, mDecoder.get(), ##__VA_ARGS__))
#define VERBOSE_LOG(x, ...) \
PR_BEGIN_MACRO \
if (!PR_GetEnv("MOZ_QUIET")) { \
DECODER_LOG(x, ##__VA_ARGS__); \
} \
PR_END_MACRO
#define SAMPLE_LOG(x, ...) \
PR_BEGIN_MACRO \
if (PR_GetEnv("MEDIA_LOG_SAMPLES")) { \
DECODER_LOG(x, ##__VA_ARGS__); \
} \
PR_END_MACRO
LOG(gMediaDecoderLog, PR_LOG_DEBUG, x, ##__VA_ARGS__)
#define VERBOSE_LOG(x, ...) \
LOG(gMediaDecoderLog, PR_LOG_DEBUG+1, x, ##__VA_ARGS__)
#define SAMPLE_LOG(x, ...) \
LOG(gMediaSampleLog, PR_LOG_DEBUG, x, ##__VA_ARGS__)
#else
#define DECODER_LOG(x, ...)
#define VERBOSE_LOG(x, ...)
@@ -3592,6 +3588,7 @@ void MediaDecoderStateMachine::RecreateDecodedStream(int64_t aInitialTime)
} // namespace mozilla
// avoid redefined macro in unified build
#undef LOG
#undef DECODER_LOG
#undef VERBOSE_LOG
#undef DECODER_WARN
+180 -153
View File
@@ -26,6 +26,12 @@
#include "nsIIDNService.h"
#include "nsNetUtil.h"
#include "nsPrincipal.h"
#include "nsICryptoHash.h"
#include "nsICryptoHMAC.h"
#include "nsIKeyModule.h"
#include "nsAppDirectoryServiceDefs.h"
#include "nsIInputStream.h"
#include "nsILineInputStream.h"
#include "mozilla/Types.h"
#include "mozilla/PeerIdentity.h"
#include "mozilla/dom/ContentChild.h"
@@ -34,7 +40,11 @@
#include "mozilla/dom/MediaStreamTrackBinding.h"
#include "mozilla/dom/GetUserMediaRequestBinding.h"
#include "mozilla/Preferences.h"
#include "mozilla/Base64.h"
#include "mozilla/ipc/BackgroundChild.h"
#include "mozilla/media/MediaChild.h"
#include "MediaTrackConstraints.h"
#include "VideoUtils.h"
#include "Latency.h"
#include "nsProxyRelease.h"
@@ -117,8 +127,8 @@ using dom::SupportedVideoConstraints;
static bool
HostInDomain(const nsCString &aHost, const nsCString &aPattern)
{
PRInt32 patternOffset = 0;
PRInt32 hostOffset = 0;
int32_t patternOffset = 0;
int32_t hostOffset = 0;
// Act on '*.' wildcard in the left-most position in a domain pattern.
if (aPattern.Length() > 2 && aPattern[0] == '*' && aPattern[1] == '.') {
@@ -335,6 +345,50 @@ public:
}
}
nsresult
AnonymizeId(nsAString& aId, const nsACString& aOriginKey)
{
nsresult rv;
nsCOMPtr<nsIKeyObjectFactory> factory =
do_GetService("@mozilla.org/security/keyobjectfactory;1", &rv);
if (NS_FAILED(rv)) {
return rv;
}
nsCString rawKey;
rv = Base64Decode(aOriginKey, rawKey);
if (NS_FAILED(rv)) {
return rv;
}
nsCOMPtr<nsIKeyObject> key;
rv = factory->KeyFromString(nsIKeyObject::HMAC, rawKey, getter_AddRefs(key));
if (NS_FAILED(rv)) {
return rv;
}
nsCOMPtr<nsICryptoHMAC> hasher =
do_CreateInstance(NS_CRYPTO_HMAC_CONTRACTID, &rv);
if (NS_FAILED(rv)) {
return rv;
}
rv = hasher->Init(nsICryptoHMAC::SHA256, key);
if (NS_FAILED(rv)) {
return rv;
}
NS_ConvertUTF16toUTF8 id(aId);
rv = hasher->Update(reinterpret_cast<const uint8_t*> (id.get()), id.Length());
if (NS_FAILED(rv)) {
return rv;
}
nsCString mac;
rv = hasher->Finish(true, mac);
if (NS_FAILED(rv)) {
return rv;
}
aId = NS_ConvertUTF8toUTF16(mac);
return NS_OK;
}
NS_IMETHOD
Run()
{
@@ -348,7 +402,7 @@ public:
nsCOMPtr<nsIWritableVariant> devices =
do_CreateInstance("@mozilla.org/variant;1");
int32_t len = mDevices->Length();
size_t len = mDevices->Length();
if (len == 0) {
// XXX
// We should in the future return an empty array, and dynamically add
@@ -364,8 +418,14 @@ public:
}
nsTArray<nsIMediaDevice*> tmp(len);
for (int32_t i = 0; i < len; i++) {
tmp.AppendElement(mDevices->ElementAt(i));
for (auto& device : *mDevices) {
if (!mOriginKey.IsEmpty()) {
nsString id;
device->GetId(id);
AnonymizeId(id, mOriginKey);
device->SetId(id);
}
tmp.AppendElement(device);
}
devices->SetAsArray(nsIDataType::VTYPE_INTERFACE,
@@ -379,6 +439,7 @@ public:
return NS_OK;
}
nsCString mOriginKey;
private:
nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback> mOnSuccess;
nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mOnFailure;
@@ -424,7 +485,7 @@ MediaDevice::MediaDevice(MediaEngineSource* aSource)
VideoDevice::VideoDevice(MediaEngineVideoSource* aSource)
: MediaDevice(aSource) {
#ifdef MOZ_B2G_CAMERA
#if defined(MOZ_B2G_CAMERA) && defined(MOZ_WIDGET_GONK)
if (mName.EqualsLiteral("back")) {
mHasFacingMode = true;
mFacingMode = dom::VideoFacingModeEnum::Environment;
@@ -1167,7 +1228,7 @@ public:
void
Run()
{
NS_ASSERTION(!NS_IsMainThread(), "Don't call on main thread");
MOZ_ASSERT(!NS_IsMainThread());
MOZ_ASSERT(mOnSuccess);
MOZ_ASSERT(mOnFailure);
@@ -1371,121 +1432,33 @@ private:
};
#endif
class SanitizeDeviceIdsTask : public Task
{
public:
explicit SanitizeDeviceIdsTask(int64_t aSinceWhen)
: mSinceWhen(aSinceWhen) {}
void // NS_IMETHOD
Run()
{
MOZ_ASSERT(!NS_IsMainThread());
nsRefPtr<media::ChildPledge<bool>> p =
mozilla::media::SanitizeOriginKeys(mSinceWhen); // we fire and forget
}
private:
int64_t mSinceWhen;
};
/**
* Similar to GetUserMediaTask, but used for the chrome-only
* GetUserMediaDevices function. Enumerates a list of audio & video devices,
* wraps them up in nsIMediaDevice objects and returns it to the success
* callback.
*
* All code in this class runs on the MediaManager thread.
*/
class GetUserMediaDevicesTask : public Task
{
static unsigned char* unconst_uchar_cast(const char *s) {
return reinterpret_cast<unsigned char*>(const_cast<char*>(s));
}
// Cribbed from nricectx.cpp
static nsresult
hmac_sha1(const char *key, int keyl, const char *buf, int bufl,
unsigned char *result) {
const CK_MECHANISM_TYPE mech = CKM_SHA_1_HMAC;
PK11SlotInfo *slot = 0;
MOZ_ASSERT(keyl > 0);
SECItem keyi = { siBuffer, unconst_uchar_cast(key),
static_cast<unsigned int>(keyl) };
PK11SymKey *skey = 0;
PK11Context *hmac_ctx = 0;
SECStatus status;
unsigned int hmac_len;
SECItem param = { siBuffer, nullptr, 0 };
nsresult rv = NS_ERROR_UNEXPECTED;
slot = PK11_GetInternalKeySlot();
if (!slot) {
goto abort;
}
skey = PK11_ImportSymKey(slot, mech, PK11_OriginUnwrap, CKA_SIGN, &keyi,
nullptr);
if (!skey) {
goto abort;
}
hmac_ctx = PK11_CreateContextBySymKey(mech, CKA_SIGN, skey, &param);
if (!hmac_ctx) {
goto abort;
}
status = PK11_DigestBegin(hmac_ctx);
if (status != SECSuccess) {
goto abort;
}
status = PK11_DigestOp(hmac_ctx, unconst_uchar_cast(buf), bufl);
if (status != SECSuccess) {
goto abort;
}
status = PK11_DigestFinal(hmac_ctx, result, &hmac_len, 20);
if (status != SECSuccess) {
goto abort;
}
MOZ_ASSERT(hmac_len == 20);
rv = NS_OK;
abort:
if (hmac_ctx) {
PK11_DestroyContext(hmac_ctx, PR_TRUE);
}
if (skey) {
PK11_FreeSymKey(skey);
}
if (slot) {
PK11_FreeSlot(slot);
}
return rv;
}
nsresult AnonymizeId(nsAString& aId, const nsACString& origin) {
// deviceId would be a supercookie if we returned it. Anonymize it:
// 1. Get (or create) a persistent uuid for this origin.
// 2. Return hmac_sha1(uuid, id) - an anonymized id unique to origin.
static bool loaded = false;
if (!loaded) {
// load OriginUuids from disk.
}
OriginUuid* originUuid;
if (!mManager->mOriginUuids.Get(origin, &originUuid)) {
char uuid[NSID_LENGTH];
{
nsresult rv;
nsID id;
{
nsCOMPtr<nsIUUIDGenerator> uuidgen =
do_GetService("@mozilla.org/uuid-generator;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = uuidgen->GenerateUUIDInPlace(&id);
NS_ENSURE_SUCCESS(rv, rv);
}
id.ToProvidedString(uuid);
}
originUuid = new OriginUuid(uuid, false);
mManager->mOriginUuids.Put(origin, originUuid);
}
unsigned char mac[20];
{
NS_ConvertUTF16toUTF8 id(aId);
hmac_sha1(originUuid->mUuid.get(), originUuid->mUuid.Length(),
id.get(), id.Length(), mac);
}
char hex[sizeof(mac) * 2 + 1];
auto& m = mac;
PR_snprintf(hex, sizeof(hex), // Use first 16 bytes of hmac as id
"%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x"
"%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x",
m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7],
m[8], m[9], m[10],m[11], m[12], m[13], m[14], m[15]);
aId = NS_ConvertUTF8toUTF16(hex);
return NS_OK;
}
public:
GetUserMediaDevicesTask(
const MediaStreamConstraints& aConstraints,
@@ -1493,7 +1466,7 @@ public:
already_AddRefed<nsIDOMGetUserMediaErrorCallback> aOnFailure,
uint64_t aWindowId, nsACString& aAudioLoopbackDev,
nsACString& aVideoLoopbackDev, bool aPrivileged, const nsACString& aOrigin,
bool aUseFakeDevices)
bool aInPrivateBrowsing, bool aUseFakeDevices)
: mConstraints(aConstraints)
, mOnSuccess(aOnSuccess)
, mOnFailure(aOnFailure)
@@ -1503,12 +1476,13 @@ public:
, mLoopbackVideoDevice(aVideoLoopbackDev)
, mPrivileged(aPrivileged)
, mOrigin(aOrigin)
, mInPrivateBrowsing(aInPrivateBrowsing)
, mUseFakeDevices(aUseFakeDevices) {}
void // NS_IMETHOD
Run()
{
NS_ASSERTION(!NS_IsMainThread(), "Don't call on main thread");
MOZ_ASSERT(!NS_IsMainThread());
nsRefPtr<MediaEngine> backend;
if (mConstraints.mFake || mUseFakeDevices)
@@ -1537,35 +1511,29 @@ public:
result->AppendElement(source);
}
}
nsresult rv = NS_OK;
if (!mPrivileged) {
for (auto& source : *result) {
nsString id;
source->GetId(id);
rv = AnonymizeId(id, mOrigin);
if (NS_FAILED(rv)) {
break;
}
source->SetId(id);
}
}
if (NS_SUCCEEDED(rv)) {
NS_DispatchToMainThread(new DeviceSuccessCallbackRunnable(mWindowId,
mOnSuccess,
mOnFailure,
result.forget()));
// In the case of failure with this newly allocated runnable, we
// intentionally leak the runnable, because we've pawned mOnSuccess and
// mOnFailure onto it which are main thread objects unsafe to release here.
DeviceSuccessCallbackRunnable* runnable =
new DeviceSuccessCallbackRunnable(mWindowId, mOnSuccess, mOnFailure,
result.forget());
if (mPrivileged) {
NS_DispatchToMainThread(runnable);
} else {
nsRefPtr<MediaMgrError> error = new
MediaMgrError(NS_LITERAL_STRING("InternalError"),
NS_LITERAL_STRING("Unexpected error"));
NS_DispatchToMainThread(
new ErrorCallbackRunnable<nsIGetUserMediaDevicesSuccessCallback>(mOnSuccess,
mOnFailure,
*error,
mWindowId));
// Get persistent origin-unique uuid to anonymize deviceIds back on main.
//
// GetOriginKey is an async API that returns a pledge (as promise-like
// pattern). We use .Then() to pass in a lambda to run back on this
// thread once GetOriginKey resolves asynchronously . The "runnable"
// pointer is "captured" (passed by value) into the lambda.
nsRefPtr<media::ChildPledge<nsCString>> p =
media::GetOriginKey(mOrigin, mInPrivateBrowsing);
p->Then([runnable](nsCString result) mutable {
runnable->mOriginKey = result;
NS_DispatchToMainThread(runnable);
});
}
// DeviceSuccessCallbackRunnable should have taken these.
// One of the Runnables have taken these.
MOZ_ASSERT(!mOnSuccess && !mOnFailure);
}
@@ -1583,6 +1551,7 @@ private:
nsCString mLoopbackVideoDevice;
bool mPrivileged;
nsCString mOrigin;
bool mInPrivateBrowsing;
bool mUseFakeDevices;
};
@@ -1611,6 +1580,16 @@ NS_IMPL_ISUPPORTS(MediaManager, nsIMediaManagerService, nsIObserver)
/* static */ StaticRefPtr<MediaManager> MediaManager::sSingleton;
#ifdef DEBUG
/* static */ bool
MediaManager::IsInMediaThread()
{
return sSingleton?
(sSingleton->mMediaThread->thread_id() == PlatformThread::CurrentId()) :
false;
}
#endif
// NOTE: never Dispatch(....,NS_DISPATCH_SYNC) to the MediaManager
// thread from the MainThread, as we NS_DISPATCH_SYNC to MainThread
// from MediaManager thread.
@@ -1618,7 +1597,11 @@ NS_IMPL_ISUPPORTS(MediaManager, nsIMediaManagerService, nsIObserver)
MediaManager::Get() {
if (!sSingleton) {
NS_ASSERTION(NS_IsMainThread(), "Only create MediaManager on main thread");
#ifdef DEBUG
static int timesCreated = 0;
timesCreated++;
MOZ_ASSERT(timesCreated == 1);
#endif
sSingleton = new MediaManager();
sSingleton->mMediaThread = new base::Thread("MediaManager");
@@ -1654,6 +1637,11 @@ MediaManager::Get() {
return sSingleton;
}
/* static */ MediaManager*
MediaManager::GetIfExists() {
return sSingleton;
}
/* static */ already_AddRefed<MediaManager>
MediaManager::GetInstance()
{
@@ -1897,7 +1885,7 @@ MediaManager::GetUserMedia(
}
}
#ifdef MOZ_B2G_CAMERA
#if defined(MOZ_B2G_CAMERA) && defined(MOZ_WIDGET_GONK)
if (mCameraManager == nullptr) {
mCameraManager = nsDOMCameraManager::CreateInstance(aWindow);
}
@@ -2006,13 +1994,18 @@ MediaManager::GetUserMediaDevices(nsPIDOMWindow* aWindow,
nsCString origin;
nsPrincipal::GetOriginForURI(aWindow->GetDocumentURI(),
getter_Copies(origin));
bool inPrivateBrowsing;
{
nsCOMPtr<nsIDocument> doc = aWindow->GetDoc();
nsCOMPtr<nsILoadContext> loadContext = doc->GetLoadContext();
inPrivateBrowsing = loadContext && loadContext->UsePrivateBrowsing();
}
MediaManager::GetMessageLoop()->PostTask(FROM_HERE,
new GetUserMediaDevicesTask(
aConstraints, onSuccess.forget(), onFailure.forget(),
(aInnerWindowID ? aInnerWindowID : aWindow->WindowID()),
loopbackAudioDevice, loopbackVideoDevice, aPrivileged, origin,
useFakeStreams));
inPrivateBrowsing, useFakeStreams));
return NS_OK;
}
@@ -2229,8 +2222,34 @@ MediaManager::Observe(nsISupports* aSubject, const char* aTopic,
prefs->RemoveObserver("media.navigator.video.default_minfps", this);
}
// Close off any remaining active windows.
// Because mMediaThread is not an nsThread, we must dispatch to it so it can
// clean up BackgroundChild. Continue stopping thread once this is done.
class ShutdownTask : public Task
{
public:
explicit ShutdownTask(nsRunnable* aReply) : mReply(aReply) {}
private:
virtual void
Run()
{
MOZ_ASSERT(MediaManager::IsInMediaThread());
mozilla::ipc::BackgroundChild::CloseForCurrentThread();
NS_DispatchToMainThread(mReply);
}
nsRefPtr<nsRunnable> mReply;
};
// Post ShutdownTask to execute on mMediaThread and pass in a lambda
// callback to be executed back on this thread once it is done.
//
// The lambda callback "captures" the 'this' pointer for member access.
// This is safe since this is guaranteed to be here since sSingleton isn't
// cleared until the lambda function clears it.
MediaManager::GetMessageLoop()->PostTask(FROM_HERE, new ShutdownTask(
media::CallbackRunnable::New([this]() mutable {
// Close off any remaining active windows.
MutexAutoLock lock(mMutex);
GetActiveWindows()->Clear();
mActiveCallbacks.Clear();
@@ -2242,11 +2261,8 @@ MediaManager::Observe(nsISupports* aSubject, const char* aTopic,
mMediaThread->Stop();
}
mBackend = nullptr;
}
#ifdef MOZ_WEBRTC
StopWebRtcLog();
#endif
return NS_OK;
})));
return NS_OK;
} else if (!strcmp(aTopic, "getUserMedia:response:allow")) {
@@ -2482,6 +2498,17 @@ MediaManager::MediaCaptureWindowState(nsIDOMWindow* aWindow, bool* aVideo,
return NS_OK;
}
NS_IMETHODIMP
MediaManager::SanitizeDeviceIds(int64_t aSinceWhen)
{
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
LOG(("%s: sinceWhen = %llu", __FUNCTION__, aSinceWhen));
MediaManager::GetMessageLoop()->PostTask(FROM_HERE,
new SanitizeDeviceIdsTask(aSinceWhen));
return NS_OK;
}
static void
StopScreensharingCallback(MediaManager *aThis,
uint64_t aWindowID,
+5 -19
View File
@@ -458,17 +458,6 @@ private:
nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mOnFailure;
};
class OriginUuid
{
public:
OriginUuid(char *aUuid, bool aPrivateBrowsing)
: mPrivateBrowsing(aPrivateBrowsing) {
mUuid.Append(aUuid);
}
nsCString mUuid;
bool mPrivateBrowsing;
};
typedef nsTArray<nsRefPtr<GetUserMediaCallbackMediaStreamListener> > StreamListeners;
typedef nsClassHashtable<nsUint64HashKey, StreamListeners> WindowTable;
@@ -520,13 +509,9 @@ typedef void (*WindowListenerCallback)(MediaManager *aThis,
StreamListeners *aListeners,
void *aData);
class GetUserMediaDevicesTask;
class MediaManager final : public nsIMediaManagerService,
public nsIObserver
{
friend GetUserMediaDevicesTask;
public:
static already_AddRefed<MediaManager> GetInstance();
@@ -534,7 +519,11 @@ public:
// thread from the MainThread, as we NS_DISPATCH_SYNC to MainThread
// from MediaManager thread.
static MediaManager* Get();
static MediaManager* GetIfExists();
static MessageLoop* GetMessageLoop();
#ifdef DEBUG
static bool IsInMediaThread();
#endif
static bool Exists()
{
@@ -612,9 +601,6 @@ private:
void StopMediaStreams();
// ONLY access from MediaManagerThread so we don't need to lock
nsClassHashtable<nsCStringHashKey, OriginUuid> mOriginUuids;
// ONLY access from MainThread so we don't need to lock
WindowTable mActiveWindows;
nsClassHashtable<nsStringHashKey, GetUserMediaTask> mActiveCallbacks;
@@ -629,7 +615,7 @@ private:
static StaticRefPtr<MediaManager> sSingleton;
#ifdef MOZ_B2G_CAMERA
#if defined(MOZ_B2G_CAMERA) && defined(MOZ_WIDGET_GONK)
nsRefPtr<nsDOMCameraManager> mCameraManager;
#endif
};
+13 -10
View File
@@ -279,18 +279,16 @@ ExtractH264CodecDetails(const nsAString& aCodec,
}
nsresult
GenerateRandomPathName(nsCString& aOutSalt, uint32_t aLength)
GenerateRandomName(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.
// For each three bytes of random data we will get four bytes of ASCII.
const uint32_t requiredBytesLength =
static_cast<uint32_t>((aLength + 1) / 4 * 3);
static_cast<uint32_t>((aLength + 3) / 4 * 3);
uint8_t* buffer;
rv = rg->GenerateRandomBytes(requiredBytesLength, &buffer);
@@ -304,14 +302,19 @@ GenerateRandomPathName(nsCString& aOutSalt, uint32_t aLength)
buffer = nullptr;
if (NS_FAILED (rv)) return rv;
temp.Truncate(aLength);
aOutSalt = temp;
return NS_OK;
}
nsresult
GenerateRandomPathName(nsCString& aOutSalt, uint32_t aLength)
{
nsresult rv = GenerateRandomName(aOutSalt, aLength);
if (NS_FAILED(rv)) return rv;
// 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;
aOutSalt.ReplaceChar(FILE_PATH_SEPARATOR FILE_ILLEGAL_CHARACTERS, '_');
return NS_OK;
}
+5 -1
View File
@@ -265,7 +265,11 @@ ExtractH264CodecDetails(const nsAString& aCodecs,
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
// and convert that to a base64 string.
nsresult
GenerateRandomName(nsCString& aOutSalt, uint32_t aLength);
// This version returns a 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);
+2 -2
View File
@@ -4,7 +4,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "GMPAudioDecoderChild.h"
#include "GMPChild.h"
#include "GMPContentChild.h"
#include "GMPAudioHost.h"
#include "mozilla/unused.h"
#include <stdio.h>
@@ -12,7 +12,7 @@
namespace mozilla {
namespace gmp {
GMPAudioDecoderChild::GMPAudioDecoderChild(GMPChild* aPlugin)
GMPAudioDecoderChild::GMPAudioDecoderChild(GMPContentChild* aPlugin)
: mPlugin(aPlugin)
, mAudioDecoder(nullptr)
{
+3 -3
View File
@@ -13,13 +13,13 @@
namespace mozilla {
namespace gmp {
class GMPChild;
class GMPContentChild;
class GMPAudioDecoderChild : public PGMPAudioDecoderChild,
public GMPAudioDecoderCallback
{
public:
explicit GMPAudioDecoderChild(GMPChild* aPlugin);
explicit GMPAudioDecoderChild(GMPContentChild* aPlugin);
virtual ~GMPAudioDecoderChild();
void Init(GMPAudioDecoder* aDecoder);
@@ -40,7 +40,7 @@ private:
virtual bool RecvDrain() override;
virtual bool RecvDecodingComplete() override;
GMPChild* mPlugin;
GMPContentChild* mPlugin;
GMPAudioDecoder* mAudioDecoder;
GMPAudioHostImpl mAudioHost;
};
+9 -2
View File
@@ -4,7 +4,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "GMPAudioDecoderParent.h"
#include "GMPParent.h"
#include "GMPContentParent.h"
#include <stdio.h>
#include "mozilla/unused.h"
#include "GMPMessageUtils.h"
@@ -29,7 +29,7 @@ extern PRLogModuleInfo* GetGMPLog();
namespace gmp {
GMPAudioDecoderParent::GMPAudioDecoderParent(GMPParent* aPlugin)
GMPAudioDecoderParent::GMPAudioDecoderParent(GMPContentParent* aPlugin)
: mIsOpen(false)
, mShuttingDown(false)
, mPlugin(aPlugin)
@@ -263,6 +263,13 @@ GMPAudioDecoderParent::RecvError(const GMPErr& aError)
return true;
}
bool
GMPAudioDecoderParent::RecvShutdown()
{
Shutdown();
return true;
}
bool
GMPAudioDecoderParent::Recv__delete__()
{
+4 -3
View File
@@ -16,7 +16,7 @@
namespace mozilla {
namespace gmp {
class GMPParent;
class GMPContentParent;
class GMPAudioDecoderParent final : public GMPAudioDecoderProxy
, public PGMPAudioDecoderParent
@@ -24,7 +24,7 @@ class GMPAudioDecoderParent final : public GMPAudioDecoderProxy
public:
NS_INLINE_DECL_REFCOUNTING(GMPAudioDecoderParent)
explicit GMPAudioDecoderParent(GMPParent *aPlugin);
explicit GMPAudioDecoderParent(GMPContentParent *aPlugin);
nsresult Shutdown();
@@ -50,11 +50,12 @@ private:
virtual bool RecvDrainComplete() override;
virtual bool RecvResetComplete() override;
virtual bool RecvError(const GMPErr& aError) override;
virtual bool RecvShutdown() override;
virtual bool Recv__delete__() override;
bool mIsOpen;
bool mShuttingDown;
nsRefPtr<GMPParent> mPlugin;
nsRefPtr<GMPContentParent> mPlugin;
GMPAudioDecoderCallbackProxy* mCallback;
};
+41 -133
View File
@@ -4,6 +4,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "GMPChild.h"
#include "GMPContentChild.h"
#include "GMPProcessChild.h"
#include "GMPLoader.h"
#include "GMPVideoDecoderChild.h"
@@ -252,12 +253,6 @@ GMPChild::StartMacSandbox()
}
#endif // XP_MACOSX && MOZ_GMP_SANDBOX
void
GMPChild::CheckThread()
{
MOZ_ASSERT(mGMPMessageLoop == MessageLoop::current());
}
bool
GMPChild::Init(const std::string& aPluginPath,
const std::string& aVoucherPath,
@@ -463,6 +458,11 @@ GMPChild::ActorDestroy(ActorDestroyReason aWhy)
{
LOGD("%s reason=%d", __FUNCTION__, aWhy);
for (uint32_t i = mGMPContentChildren.Length(); i > 0; i--) {
MOZ_ASSERT_IF(aWhy == NormalShutdown, !mGMPContentChildren[i - 1]->IsUsed());
mGMPContentChildren[i - 1]->Close();
}
if (mGMPLoader) {
mGMPLoader->Shutdown();
}
@@ -497,133 +497,6 @@ GMPChild::ProcessingError(Result aCode, const char* aReason)
}
}
PGMPAudioDecoderChild*
GMPChild::AllocPGMPAudioDecoderChild()
{
return new GMPAudioDecoderChild(this);
}
bool
GMPChild::DeallocPGMPAudioDecoderChild(PGMPAudioDecoderChild* aActor)
{
delete aActor;
return true;
}
PGMPVideoDecoderChild*
GMPChild::AllocPGMPVideoDecoderChild()
{
return new GMPVideoDecoderChild(this);
}
bool
GMPChild::DeallocPGMPVideoDecoderChild(PGMPVideoDecoderChild* aActor)
{
delete aActor;
return true;
}
PGMPDecryptorChild*
GMPChild::AllocPGMPDecryptorChild()
{
GMPDecryptorChild* actor = new GMPDecryptorChild(this, mPluginVoucher, mSandboxVoucher);
actor->AddRef();
return actor;
}
bool
GMPChild::DeallocPGMPDecryptorChild(PGMPDecryptorChild* aActor)
{
static_cast<GMPDecryptorChild*>(aActor)->Release();
return true;
}
bool
GMPChild::RecvPGMPAudioDecoderConstructor(PGMPAudioDecoderChild* aActor)
{
auto vdc = static_cast<GMPAudioDecoderChild*>(aActor);
void* vd = nullptr;
GMPErr err = GetAPI(GMP_API_AUDIO_DECODER, &vdc->Host(), &vd);
if (err != GMPNoErr || !vd) {
return false;
}
vdc->Init(static_cast<GMPAudioDecoder*>(vd));
return true;
}
PGMPVideoEncoderChild*
GMPChild::AllocPGMPVideoEncoderChild()
{
return new GMPVideoEncoderChild(this);
}
bool
GMPChild::DeallocPGMPVideoEncoderChild(PGMPVideoEncoderChild* aActor)
{
delete aActor;
return true;
}
bool
GMPChild::RecvPGMPVideoDecoderConstructor(PGMPVideoDecoderChild* aActor)
{
auto vdc = static_cast<GMPVideoDecoderChild*>(aActor);
void* vd = nullptr;
GMPErr err = GetAPI(GMP_API_VIDEO_DECODER, &vdc->Host(), &vd);
if (err != GMPNoErr || !vd) {
NS_WARNING("GMPGetAPI call failed trying to construct decoder.");
return false;
}
vdc->Init(static_cast<GMPVideoDecoder*>(vd));
return true;
}
bool
GMPChild::RecvPGMPVideoEncoderConstructor(PGMPVideoEncoderChild* aActor)
{
auto vec = static_cast<GMPVideoEncoderChild*>(aActor);
void* ve = nullptr;
GMPErr err = GetAPI(GMP_API_VIDEO_ENCODER, &vec->Host(), &ve);
if (err != GMPNoErr || !ve) {
NS_WARNING("GMPGetAPI call failed trying to construct encoder.");
return false;
}
vec->Init(static_cast<GMPVideoEncoder*>(ve));
return true;
}
bool
GMPChild::RecvPGMPDecryptorConstructor(PGMPDecryptorChild* aActor)
{
GMPDecryptorChild* child = static_cast<GMPDecryptorChild*>(aActor);
GMPDecryptorHost* host = static_cast<GMPDecryptorHost*>(child);
void* session = nullptr;
GMPErr err = GetAPI(GMP_API_DECRYPTOR, host, &session);
if (err != GMPNoErr && !session) {
// XXX to remove in bug 1147692
err = GetAPI(GMP_API_DECRYPTOR_COMPAT, host, &session);
}
if (err != GMPNoErr || !session) {
return false;
}
child->Init(static_cast<GMPDecryptor*>(session));
return true;
}
PGMPTimerChild*
GMPChild::AllocPGMPTimerChild()
{
@@ -698,6 +571,15 @@ GMPChild::RecvBeginAsyncShutdown()
return true;
}
bool
GMPChild::RecvCloseActive()
{
for (uint32_t i = mGMPContentChildren.Length(); i > 0; i--) {
mGMPContentChildren[i - 1]->CloseActive();
}
return true;
}
void
GMPChild::ShutdownComplete()
{
@@ -780,6 +662,32 @@ GMPChild::PreLoadSandboxVoucher()
}
}
PGMPContentChild*
GMPChild::AllocPGMPContentChild(Transport* aTransport,
ProcessId aOtherPid)
{
GMPContentChild* child =
mGMPContentChildren.AppendElement(new GMPContentChild(this))->get();
child->Open(aTransport, aOtherPid, XRE_GetIOMessageLoop(), ipc::ChildSide);
return child;
}
void
GMPChild::GMPContentChildActorDestroy(GMPContentChild* aGMPContentChild)
{
for (uint32_t i = mGMPContentChildren.Length(); i > 0; i--) {
UniquePtr<GMPContentChild>& toDestroy = mGMPContentChildren[i - 1];
if (toDestroy.get() == aGMPContentChild) {
SendPGMPContentChildDestroyed();
MessageLoop::current()->PostTask(FROM_HERE,
new DeleteTask<GMPContentChild>(toDestroy.release()));
mGMPContentChildren.RemoveElementAt(i - 1);
break;
}
}
}
} // namespace gmp
} // namespace mozilla
+10 -21
View File
@@ -7,7 +7,6 @@
#define GMPChild_h_
#include "mozilla/gmp/PGMPChild.h"
#include "GMPSharedMemManager.h"
#include "GMPTimerChild.h"
#include "GMPStorageChild.h"
#include "GMPLoader.h"
@@ -18,8 +17,9 @@
namespace mozilla {
namespace gmp {
class GMPContentChild;
class GMPChild : public PGMPChild
, public GMPSharedMem
, public GMPAsyncShutdownHost
{
public:
@@ -40,9 +40,6 @@ public:
GMPTimerChild* GetGMPTimers();
GMPStorageChild* GetGMPStorage();
// GMPSharedMem
virtual void CheckThread() override;
// GMPAsyncShutdownHost
void ShutdownComplete() override;
@@ -51,6 +48,7 @@ public:
#endif
private:
friend class GMPContentChild;
bool PreLoadPluginVoucher(const std::string& aPluginPath);
void PreLoadSandboxVoucher();
@@ -60,36 +58,27 @@ private:
virtual bool RecvSetNodeId(const nsCString& aNodeId) override;
virtual bool RecvStartPlugin() override;
virtual PGMPVideoDecoderChild* AllocPGMPVideoDecoderChild() override;
virtual bool DeallocPGMPVideoDecoderChild(PGMPVideoDecoderChild* aActor) override;
virtual bool RecvPGMPVideoDecoderConstructor(PGMPVideoDecoderChild* aActor) override;
virtual PGMPVideoEncoderChild* AllocPGMPVideoEncoderChild() override;
virtual bool DeallocPGMPVideoEncoderChild(PGMPVideoEncoderChild* aActor) override;
virtual bool RecvPGMPVideoEncoderConstructor(PGMPVideoEncoderChild* aActor) override;
virtual PGMPDecryptorChild* AllocPGMPDecryptorChild() override;
virtual bool DeallocPGMPDecryptorChild(PGMPDecryptorChild* aActor) override;
virtual bool RecvPGMPDecryptorConstructor(PGMPDecryptorChild* aActor) override;
virtual PGMPAudioDecoderChild* AllocPGMPAudioDecoderChild() override;
virtual bool DeallocPGMPAudioDecoderChild(PGMPAudioDecoderChild* aActor) override;
virtual bool RecvPGMPAudioDecoderConstructor(PGMPAudioDecoderChild* aActor) override;
virtual PGMPTimerChild* AllocPGMPTimerChild() override;
virtual bool DeallocPGMPTimerChild(PGMPTimerChild* aActor) override;
virtual PGMPStorageChild* AllocPGMPStorageChild() override;
virtual bool DeallocPGMPStorageChild(PGMPStorageChild* aActor) override;
virtual PGMPContentChild* AllocPGMPContentChild(Transport* aTransport,
ProcessId aOtherPid) override;
void GMPContentChildActorDestroy(GMPContentChild* aGMPContentChild);
virtual bool RecvCrashPluginNow() override;
virtual bool RecvBeginAsyncShutdown() override;
virtual bool RecvCloseActive() override;
virtual void ActorDestroy(ActorDestroyReason aWhy) override;
virtual void ProcessingError(Result aCode, const char* aReason) override;
GMPErr GetAPI(const char* aAPIName, void* aHostAPI, void** aPluginAPI);
nsTArray<UniquePtr<GMPContentChild>> mGMPContentChildren;
GMPAsyncShutdown* mAsyncShutdown;
nsRefPtr<GMPTimerChild> mTimerChild;
nsRefPtr<GMPStorageChild> mStorage;
+215
View File
@@ -0,0 +1,215 @@
/* -*- 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 "GMPContentChild.h"
namespace mozilla {
namespace gmp {
GMPContentChild::GMPContentChild(GMPChild* aChild)
: mGMPChild(aChild)
{
MOZ_COUNT_CTOR(GMPContentChild);
}
GMPContentChild::~GMPContentChild()
{
MOZ_COUNT_DTOR(GMPContentChild);
XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
new DeleteTask<Transport>(GetTransport()));
}
MessageLoop*
GMPContentChild::GMPMessageLoop()
{
return mGMPChild->GMPMessageLoop();
}
void
GMPContentChild::CheckThread()
{
MOZ_ASSERT(mGMPChild->mGMPMessageLoop == MessageLoop::current());
}
void
GMPContentChild::ActorDestroy(ActorDestroyReason aWhy)
{
mGMPChild->GMPContentChildActorDestroy(this);
}
void
GMPContentChild::ProcessingError(Result aCode, const char* aReason)
{
mGMPChild->ProcessingError(aCode, aReason);
}
PGMPAudioDecoderChild*
GMPContentChild::AllocPGMPAudioDecoderChild()
{
return new GMPAudioDecoderChild(this);
}
bool
GMPContentChild::DeallocPGMPAudioDecoderChild(PGMPAudioDecoderChild* aActor)
{
delete aActor;
return true;
}
PGMPDecryptorChild*
GMPContentChild::AllocPGMPDecryptorChild()
{
GMPDecryptorChild* actor = new GMPDecryptorChild(this,
mGMPChild->mPluginVoucher,
mGMPChild->mSandboxVoucher);
actor->AddRef();
return actor;
}
bool
GMPContentChild::DeallocPGMPDecryptorChild(PGMPDecryptorChild* aActor)
{
static_cast<GMPDecryptorChild*>(aActor)->Release();
return true;
}
PGMPVideoDecoderChild*
GMPContentChild::AllocPGMPVideoDecoderChild()
{
return new GMPVideoDecoderChild(this);
}
bool
GMPContentChild::DeallocPGMPVideoDecoderChild(PGMPVideoDecoderChild* aActor)
{
delete aActor;
return true;
}
PGMPVideoEncoderChild*
GMPContentChild::AllocPGMPVideoEncoderChild()
{
return new GMPVideoEncoderChild(this);
}
bool
GMPContentChild::DeallocPGMPVideoEncoderChild(PGMPVideoEncoderChild* aActor)
{
delete aActor;
return true;
}
bool
GMPContentChild::RecvPGMPDecryptorConstructor(PGMPDecryptorChild* aActor)
{
GMPDecryptorChild* child = static_cast<GMPDecryptorChild*>(aActor);
GMPDecryptorHost* host = static_cast<GMPDecryptorHost*>(child);
void* session = nullptr;
GMPErr err = mGMPChild->GetAPI(GMP_API_DECRYPTOR, host, &session);
if (err != GMPNoErr && !session) {
// XXX to remove in bug 1147692
err = mGMPChild->GetAPI(GMP_API_DECRYPTOR_COMPAT, host, &session);
}
if (err != GMPNoErr || !session) {
return false;
}
child->Init(static_cast<GMPDecryptor*>(session));
return true;
}
bool
GMPContentChild::RecvPGMPAudioDecoderConstructor(PGMPAudioDecoderChild* aActor)
{
auto vdc = static_cast<GMPAudioDecoderChild*>(aActor);
void* vd = nullptr;
GMPErr err = mGMPChild->GetAPI(GMP_API_AUDIO_DECODER, &vdc->Host(), &vd);
if (err != GMPNoErr || !vd) {
return false;
}
vdc->Init(static_cast<GMPAudioDecoder*>(vd));
return true;
}
bool
GMPContentChild::RecvPGMPVideoDecoderConstructor(PGMPVideoDecoderChild* aActor)
{
auto vdc = static_cast<GMPVideoDecoderChild*>(aActor);
void* vd = nullptr;
GMPErr err = mGMPChild->GetAPI(GMP_API_VIDEO_DECODER, &vdc->Host(), &vd);
if (err != GMPNoErr || !vd) {
NS_WARNING("GMPGetAPI call failed trying to construct decoder.");
return false;
}
vdc->Init(static_cast<GMPVideoDecoder*>(vd));
return true;
}
bool
GMPContentChild::RecvPGMPVideoEncoderConstructor(PGMPVideoEncoderChild* aActor)
{
auto vec = static_cast<GMPVideoEncoderChild*>(aActor);
void* ve = nullptr;
GMPErr err = mGMPChild->GetAPI(GMP_API_VIDEO_ENCODER, &vec->Host(), &ve);
if (err != GMPNoErr || !ve) {
NS_WARNING("GMPGetAPI call failed trying to construct encoder.");
return false;
}
vec->Init(static_cast<GMPVideoEncoder*>(ve));
return true;
}
void
GMPContentChild::CloseActive()
{
// Invalidate and remove any remaining API objects.
const nsTArray<PGMPAudioDecoderChild*>& audioDecoders =
ManagedPGMPAudioDecoderChild();
for (uint32_t i = audioDecoders.Length(); i > 0; i--) {
audioDecoders[i - 1]->SendShutdown();
}
const nsTArray<PGMPDecryptorChild*>& decryptors =
ManagedPGMPDecryptorChild();
for (uint32_t i = decryptors.Length(); i > 0; i--) {
decryptors[i - 1]->SendShutdown();
}
const nsTArray<PGMPVideoDecoderChild*>& videoDecoders =
ManagedPGMPVideoDecoderChild();
for (uint32_t i = videoDecoders.Length(); i > 0; i--) {
videoDecoders[i - 1]->SendShutdown();
}
const nsTArray<PGMPVideoEncoderChild*>& videoEncoders =
ManagedPGMPVideoEncoderChild();
for (uint32_t i = videoEncoders.Length(); i > 0; i--) {
videoEncoders[i - 1]->SendShutdown();
}
}
bool
GMPContentChild::IsUsed()
{
return !ManagedPGMPAudioDecoderChild().IsEmpty() ||
!ManagedPGMPDecryptorChild().IsEmpty() ||
!ManagedPGMPVideoDecoderChild().IsEmpty() ||
!ManagedPGMPVideoEncoderChild().IsEmpty();
}
} // namespace gmp
} // namespace mozilla
+58
View File
@@ -0,0 +1,58 @@
/* -*- 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 GMPContentChild_h_
#define GMPContentChild_h_
#include "mozilla/gmp/PGMPContentChild.h"
#include "GMPSharedMemManager.h"
namespace mozilla {
namespace gmp {
class GMPChild;
class GMPContentChild : public PGMPContentChild
, public GMPSharedMem
{
public:
explicit GMPContentChild(GMPChild* aChild);
virtual ~GMPContentChild();
MessageLoop* GMPMessageLoop();
virtual bool RecvPGMPAudioDecoderConstructor(PGMPAudioDecoderChild* aActor) override;
virtual bool RecvPGMPDecryptorConstructor(PGMPDecryptorChild* aActor) override;
virtual bool RecvPGMPVideoDecoderConstructor(PGMPVideoDecoderChild* aActor) override;
virtual bool RecvPGMPVideoEncoderConstructor(PGMPVideoEncoderChild* aActor) override;
virtual PGMPAudioDecoderChild* AllocPGMPAudioDecoderChild() override;
virtual bool DeallocPGMPAudioDecoderChild(PGMPAudioDecoderChild* aActor) override;
virtual PGMPDecryptorChild* AllocPGMPDecryptorChild() override;
virtual bool DeallocPGMPDecryptorChild(PGMPDecryptorChild* aActor) override;
virtual PGMPVideoDecoderChild* AllocPGMPVideoDecoderChild() override;
virtual bool DeallocPGMPVideoDecoderChild(PGMPVideoDecoderChild* aActor) override;
virtual PGMPVideoEncoderChild* AllocPGMPVideoEncoderChild() override;
virtual bool DeallocPGMPVideoEncoderChild(PGMPVideoEncoderChild* aActor) override;
virtual void ActorDestroy(ActorDestroyReason aWhy) override;
virtual void ProcessingError(Result aCode, const char* aReason) override;
// GMPSharedMem
virtual void CheckThread() override;
void CloseActive();
bool IsUsed();
GMPChild* mGMPChild;
};
} // namespace gmp
} // namespace mozilla
#endif // GMPContentChild_h_
+302
View File
@@ -0,0 +1,302 @@
/* -*- 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 "GMPContentParent.h"
#include "GMPAudioDecoderParent.h"
#include "GMPDecryptorParent.h"
#include "GMPParent.h"
#include "GMPServiceChild.h"
#include "GMPVideoDecoderParent.h"
#include "GMPVideoEncoderParent.h"
#include "mozIGeckoMediaPluginService.h"
#include "prlog.h"
namespace mozilla {
#ifdef LOG
#undef LOG
#endif
#ifdef PR_LOGGING
extern PRLogModuleInfo* GetGMPLog();
#define LOGD(msg) PR_LOG(GetGMPLog(), PR_LOG_DEBUG, msg)
#define LOG(level, msg) PR_LOG(GetGMPLog(), (level), msg)
#else
#define LOGD(msg)
#define LOG(level, msg)
#endif
#ifdef __CLASS__
#undef __CLASS__
#endif
#define __CLASS__ "GMPContentParent"
namespace gmp {
GMPContentParent::GMPContentParent(GMPParent* aParent)
: mParent(aParent)
{
if (mParent) {
SetDisplayName(mParent->GetDisplayName());
SetPluginId(mParent->GetPluginId());
}
}
GMPContentParent::~GMPContentParent()
{
XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
new DeleteTask<Transport>(GetTransport()));
}
class ReleaseGMPContentParent : public nsRunnable
{
public:
explicit ReleaseGMPContentParent(GMPContentParent* aToRelease)
: mToRelease(aToRelease)
{
}
NS_IMETHOD Run()
{
return NS_OK;
}
private:
nsRefPtr<GMPContentParent> mToRelease;
};
void
GMPContentParent::ActorDestroy(ActorDestroyReason aWhy)
{
MOZ_ASSERT(mAudioDecoders.IsEmpty() &&
mDecryptors.IsEmpty() &&
mVideoDecoders.IsEmpty() &&
mVideoEncoders.IsEmpty());
NS_DispatchToCurrentThread(new ReleaseGMPContentParent(this));
}
void
GMPContentParent::CheckThread()
{
MOZ_ASSERT(mGMPThread == NS_GetCurrentThread());
}
void
GMPContentParent::AudioDecoderDestroyed(GMPAudioDecoderParent* aDecoder)
{
MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
MOZ_ALWAYS_TRUE(mAudioDecoders.RemoveElement(aDecoder));
CloseIfUnused();
}
void
GMPContentParent::VideoDecoderDestroyed(GMPVideoDecoderParent* aDecoder)
{
MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
// If the constructor fails, we'll get called before it's added
unused << NS_WARN_IF(!mVideoDecoders.RemoveElement(aDecoder));
CloseIfUnused();
}
void
GMPContentParent::VideoEncoderDestroyed(GMPVideoEncoderParent* aEncoder)
{
MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
// If the constructor fails, we'll get called before it's added
unused << NS_WARN_IF(!mVideoEncoders.RemoveElement(aEncoder));
CloseIfUnused();
}
void
GMPContentParent::DecryptorDestroyed(GMPDecryptorParent* aSession)
{
MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
MOZ_ALWAYS_TRUE(mDecryptors.RemoveElement(aSession));
CloseIfUnused();
}
void
GMPContentParent::CloseIfUnused()
{
if (mAudioDecoders.IsEmpty() &&
mDecryptors.IsEmpty() &&
mVideoDecoders.IsEmpty() &&
mVideoEncoders.IsEmpty()) {
nsRefPtr<GMPContentParent> toClose;
if (mParent) {
toClose = mParent->ForgetGMPContentParent();
} else {
toClose = this;
nsRefPtr<GeckoMediaPluginServiceChild> gmp(
GeckoMediaPluginServiceChild::GetSingleton());
gmp->RemoveGMPContentParent(toClose);
}
NS_DispatchToCurrentThread(NS_NewRunnableMethod(toClose,
&GMPContentParent::Close));
}
}
nsresult
GMPContentParent::GetGMPDecryptor(GMPDecryptorParent** aGMPDP)
{
PGMPDecryptorParent* pdp = SendPGMPDecryptorConstructor();
if (!pdp) {
return NS_ERROR_FAILURE;
}
GMPDecryptorParent* dp = static_cast<GMPDecryptorParent*>(pdp);
// This addref corresponds to the Proxy pointer the consumer is returned.
// It's dropped by calling Close() on the interface.
NS_ADDREF(dp);
mDecryptors.AppendElement(dp);
*aGMPDP = dp;
return NS_OK;
}
nsIThread*
GMPContentParent::GMPThread()
{
if (!mGMPThread) {
nsCOMPtr<mozIGeckoMediaPluginService> mps = do_GetService("@mozilla.org/gecko-media-plugin-service;1");
MOZ_ASSERT(mps);
if (!mps) {
return nullptr;
}
// Not really safe if we just grab to the mGMPThread, as we don't know
// what thread we're running on and other threads may be trying to
// access this without locks! However, debug only, and primary failure
// mode outside of compiler-helped TSAN is a leak. But better would be
// to use swap() under a lock.
mps->GetThread(getter_AddRefs(mGMPThread));
MOZ_ASSERT(mGMPThread);
}
return mGMPThread;
}
nsresult
GMPContentParent::GetGMPAudioDecoder(GMPAudioDecoderParent** aGMPAD)
{
PGMPAudioDecoderParent* pvap = SendPGMPAudioDecoderConstructor();
if (!pvap) {
return NS_ERROR_FAILURE;
}
GMPAudioDecoderParent* vap = static_cast<GMPAudioDecoderParent*>(pvap);
// This addref corresponds to the Proxy pointer the consumer is returned.
// It's dropped by calling Close() on the interface.
NS_ADDREF(vap);
*aGMPAD = vap;
mAudioDecoders.AppendElement(vap);
return NS_OK;
}
nsresult
GMPContentParent::GetGMPVideoDecoder(GMPVideoDecoderParent** aGMPVD)
{
// returned with one anonymous AddRef that locks it until Destroy
PGMPVideoDecoderParent* pvdp = SendPGMPVideoDecoderConstructor();
if (!pvdp) {
return NS_ERROR_FAILURE;
}
GMPVideoDecoderParent *vdp = static_cast<GMPVideoDecoderParent*>(pvdp);
// This addref corresponds to the Proxy pointer the consumer is returned.
// It's dropped by calling Close() on the interface.
NS_ADDREF(vdp);
*aGMPVD = vdp;
mVideoDecoders.AppendElement(vdp);
return NS_OK;
}
nsresult
GMPContentParent::GetGMPVideoEncoder(GMPVideoEncoderParent** aGMPVE)
{
// returned with one anonymous AddRef that locks it until Destroy
PGMPVideoEncoderParent* pvep = SendPGMPVideoEncoderConstructor();
if (!pvep) {
return NS_ERROR_FAILURE;
}
GMPVideoEncoderParent *vep = static_cast<GMPVideoEncoderParent*>(pvep);
// This addref corresponds to the Proxy pointer the consumer is returned.
// It's dropped by calling Close() on the interface.
NS_ADDREF(vep);
*aGMPVE = vep;
mVideoEncoders.AppendElement(vep);
return NS_OK;
}
PGMPVideoDecoderParent*
GMPContentParent::AllocPGMPVideoDecoderParent()
{
GMPVideoDecoderParent* vdp = new GMPVideoDecoderParent(this);
NS_ADDREF(vdp);
return vdp;
}
bool
GMPContentParent::DeallocPGMPVideoDecoderParent(PGMPVideoDecoderParent* aActor)
{
GMPVideoDecoderParent* vdp = static_cast<GMPVideoDecoderParent*>(aActor);
NS_RELEASE(vdp);
return true;
}
PGMPVideoEncoderParent*
GMPContentParent::AllocPGMPVideoEncoderParent()
{
GMPVideoEncoderParent* vep = new GMPVideoEncoderParent(this);
NS_ADDREF(vep);
return vep;
}
bool
GMPContentParent::DeallocPGMPVideoEncoderParent(PGMPVideoEncoderParent* aActor)
{
GMPVideoEncoderParent* vep = static_cast<GMPVideoEncoderParent*>(aActor);
NS_RELEASE(vep);
return true;
}
PGMPDecryptorParent*
GMPContentParent::AllocPGMPDecryptorParent()
{
GMPDecryptorParent* ksp = new GMPDecryptorParent(this);
NS_ADDREF(ksp);
return ksp;
}
bool
GMPContentParent::DeallocPGMPDecryptorParent(PGMPDecryptorParent* aActor)
{
GMPDecryptorParent* ksp = static_cast<GMPDecryptorParent*>(aActor);
NS_RELEASE(ksp);
return true;
}
PGMPAudioDecoderParent*
GMPContentParent::AllocPGMPAudioDecoderParent()
{
GMPAudioDecoderParent* vdp = new GMPAudioDecoderParent(this);
NS_ADDREF(vdp);
return vdp;
}
bool
GMPContentParent::DeallocPGMPAudioDecoderParent(PGMPAudioDecoderParent* aActor)
{
GMPAudioDecoderParent* vdp = static_cast<GMPAudioDecoderParent*>(aActor);
NS_RELEASE(vdp);
return true;
}
} // namespace gmp
} // namespace mozilla
+105
View File
@@ -0,0 +1,105 @@
/* -*- 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 GMPContentParent_h_
#define GMPContentParent_h_
#include "mozilla/gmp/PGMPContentParent.h"
#include "nsISupportsImpl.h"
class nsITimer;
namespace mozilla {
namespace gmp {
class GeckoMediaPluginService;
class GMPAudioDecoderParent;
class GMPCapability;
class GMPDecryptorParent;
class GMPParent;
class GMPVideoDecoderParent;
class GMPVideoEncoderParent;
class GMPContentParent final : public PGMPContentParent,
public GMPSharedMem
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GMPContentParent)
explicit GMPContentParent(GMPParent* aParent = nullptr);
nsresult GetGMPVideoDecoder(GMPVideoDecoderParent** aGMPVD);
void VideoDecoderDestroyed(GMPVideoDecoderParent* aDecoder);
nsresult GetGMPVideoEncoder(GMPVideoEncoderParent** aGMPVE);
void VideoEncoderDestroyed(GMPVideoEncoderParent* aEncoder);
nsresult GetGMPDecryptor(GMPDecryptorParent** aGMPKS);
void DecryptorDestroyed(GMPDecryptorParent* aSession);
nsresult GetGMPAudioDecoder(GMPAudioDecoderParent** aGMPAD);
void AudioDecoderDestroyed(GMPAudioDecoderParent* aDecoder);
nsIThread* GMPThread();
// GMPSharedMem
virtual void CheckThread() override;
void SetDisplayName(const nsCString& aDisplayName)
{
mDisplayName = aDisplayName;
}
const nsCString& GetDisplayName()
{
return mDisplayName;
}
void SetPluginId(const nsCString& aPluginId)
{
mPluginId = aPluginId;
}
const nsCString& GetPluginId()
{
return mPluginId;
}
private:
~GMPContentParent();
virtual void ActorDestroy(ActorDestroyReason aWhy) override;
virtual PGMPVideoDecoderParent* AllocPGMPVideoDecoderParent() override;
virtual bool DeallocPGMPVideoDecoderParent(PGMPVideoDecoderParent* aActor) override;
virtual PGMPVideoEncoderParent* AllocPGMPVideoEncoderParent() override;
virtual bool DeallocPGMPVideoEncoderParent(PGMPVideoEncoderParent* aActor) override;
virtual PGMPDecryptorParent* AllocPGMPDecryptorParent() override;
virtual bool DeallocPGMPDecryptorParent(PGMPDecryptorParent* aActor) override;
virtual PGMPAudioDecoderParent* AllocPGMPAudioDecoderParent() override;
virtual bool DeallocPGMPAudioDecoderParent(PGMPAudioDecoderParent* aActor) override;
void CloseIfUnused();
// Needed because NS_NewRunnableMethod tried to use the class that the method
// lives on to store the receiver, but PGMPContentParent isn't refcounted.
void Close()
{
PGMPContentParent::Close();
}
nsTArray<nsRefPtr<GMPVideoDecoderParent>> mVideoDecoders;
nsTArray<nsRefPtr<GMPVideoEncoderParent>> mVideoEncoders;
nsTArray<nsRefPtr<GMPDecryptorParent>> mDecryptors;
nsTArray<nsRefPtr<GMPAudioDecoderParent>> mAudioDecoders;
nsCOMPtr<nsIThread> mGMPThread;
nsRefPtr<GMPParent> mParent;
nsCString mDisplayName;
nsCString mPluginId;
};
} // namespace gmp
} // namespace mozilla
#endif // GMPParent_h_
+1 -1
View File
@@ -26,7 +26,7 @@
namespace mozilla {
namespace gmp {
GMPDecryptorChild::GMPDecryptorChild(GMPChild* aPlugin,
GMPDecryptorChild::GMPDecryptorChild(GMPContentChild* aPlugin,
const nsTArray<uint8_t>& aPluginVoucher,
const nsTArray<uint8_t>& aSandboxVoucher)
: mSession(nullptr)
+3 -3
View File
@@ -15,7 +15,7 @@
namespace mozilla {
namespace gmp {
class GMPChild;
class GMPContentChild;
class GMPDecryptorChild : public GMPDecryptorCallback
, public GMPDecryptorHost
@@ -24,7 +24,7 @@ class GMPDecryptorChild : public GMPDecryptorCallback
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GMPDecryptorChild);
explicit GMPDecryptorChild(GMPChild* aPlugin,
explicit GMPDecryptorChild(GMPContentChild* aPlugin,
const nsTArray<uint8_t>& aPluginVoucher,
const nsTArray<uint8_t>& aSandboxVoucher);
@@ -117,7 +117,7 @@ private:
// GMP's GMPDecryptor implementation.
// Only call into this on the (GMP process) main thread.
GMPDecryptor* mSession;
GMPChild* mPlugin;
GMPContentChild* mPlugin;
// Reference to the vouchers owned by the GMPChild.
const nsTArray<uint8_t>& mPluginVoucher;
+9 -2
View File
@@ -4,14 +4,14 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "GMPDecryptorParent.h"
#include "GMPParent.h"
#include "GMPContentParent.h"
#include "MediaData.h"
#include "mozilla/unused.h"
namespace mozilla {
namespace gmp {
GMPDecryptorParent::GMPDecryptorParent(GMPParent* aPlugin)
GMPDecryptorParent::GMPDecryptorParent(GMPContentParent* aPlugin)
: mIsOpen(false)
, mShuttingDown(false)
, mPlugin(aPlugin)
@@ -307,6 +307,13 @@ GMPDecryptorParent::RecvDecrypted(const uint32_t& aId,
return true;
}
bool
GMPDecryptorParent::RecvShutdown()
{
Shutdown();
return true;
}
// Note: may be called via Terminated()
void
GMPDecryptorParent::Close()
+5 -3
View File
@@ -17,7 +17,7 @@ class CryptoSample;
namespace gmp {
class GMPParent;
class GMPContentParent;
class GMPDecryptorParent final : public GMPDecryptorProxy
, public PGMPDecryptorParent
@@ -25,7 +25,7 @@ class GMPDecryptorParent final : public GMPDecryptorProxy
public:
NS_INLINE_DECL_REFCOUNTING(GMPDecryptorParent)
explicit GMPDecryptorParent(GMPParent *aPlugin);
explicit GMPDecryptorParent(GMPContentParent *aPlugin);
// GMPDecryptorProxy
virtual const nsACString& GetPluginId() const override;
@@ -103,12 +103,14 @@ private:
virtual bool RecvSetCaps(const uint64_t& aCaps) override;
virtual bool RecvShutdown() override;
virtual void ActorDestroy(ActorDestroyReason aWhy) override;
virtual bool Recv__delete__() override;
bool mIsOpen;
bool mShuttingDown;
nsRefPtr<GMPParent> mPlugin;
nsRefPtr<GMPContentParent> mPlugin;
nsCString mPluginId;
GMPDecryptorProxyCallback* mCallback;
#ifdef DEBUG
+178 -304
View File
@@ -14,6 +14,7 @@
#include "nsThreadUtils.h"
#include "nsIRunnable.h"
#include "mozIGeckoMediaPluginService.h"
#include "mozilla/SyncRunnable.h"
#include "mozilla/unused.h"
#include "nsIObserverService.h"
#include "GMPTimerParent.h"
@@ -26,25 +27,18 @@
namespace mozilla {
#ifdef LOG
#undef LOG
#endif
#undef LOGD
#ifdef PR_LOGGING
extern PRLogModuleInfo* GetGMPLog();
#define LOGD(msg) PR_LOG(GetGMPLog(), PR_LOG_DEBUG, msg)
#define LOG(level, msg) PR_LOG(GetGMPLog(), (level), msg)
#define LOG(level, x, ...) PR_LOG(GetGMPLog(), (level), (x, ##__VA_ARGS__))
#define LOGD(x, ...) LOG(PR_LOG_DEBUG, "GMPParent[%p|childPid=%d] " x, this, mChildPid, ##__VA_ARGS__)
#else
#define LOGD(msg)
#define LOG(level, msg)
#define LOG(level, x, ...)
#define LOGD(x, ...)
#endif
#ifdef __CLASS__
#undef __CLASS__
#endif
#define __CLASS__ "GMPParent"
namespace gmp {
GMPParent::GMPParent()
@@ -54,9 +48,14 @@ GMPParent::GMPParent()
, mAbnormalShutdownInProgress(false)
, mIsBlockingDeletion(false)
, mCanDecrypt(false)
, mGMPContentChildCount(0)
, mAsyncShutdownRequired(false)
, mAsyncShutdownInProgress(false)
#ifdef PR_LOGGING
, mChildPid(0)
#endif
{
LOGD("GMPParent ctor");
// Use the parent address to identify it.
// We could use any unique-to-the-parent value.
mPluginId.AppendInt(reinterpret_cast<uint64_t>(this));
@@ -66,12 +65,7 @@ GMPParent::~GMPParent()
{
// Can't Close or Destroy the process here, since destruction is MainThread only
MOZ_ASSERT(NS_IsMainThread());
}
void
GMPParent::CheckThread()
{
MOZ_ASSERT(mGMPThread == NS_GetCurrentThread());
LOGD("GMPParent dtor");
}
nsresult
@@ -83,7 +77,7 @@ GMPParent::CloneFrom(const GMPParent* aOther)
}
nsresult
GMPParent::Init(GeckoMediaPluginService *aService, nsIFile* aPluginDir)
GMPParent::Init(GeckoMediaPluginServiceParent* aService, nsIFile* aPluginDir)
{
MOZ_ASSERT(aPluginDir);
MOZ_ASSERT(aService);
@@ -104,8 +98,7 @@ GMPParent::Init(GeckoMediaPluginService *aService, nsIFile* aPluginDir)
if (NS_FAILED(rv)) {
return rv;
}
LOGD(("%s::%s: %p for %s", __CLASS__, __FUNCTION__, this,
NS_LossyConvertUTF16toASCII(parentLeafName).get()));
LOGD("%s: for %s", __FUNCTION__, NS_LossyConvertUTF16toASCII(parentLeafName).get());
MOZ_ASSERT(parentLeafName.Length() > 4);
mName = Substring(parentLeafName, 4);
@@ -132,7 +125,7 @@ GMPParent::LoadProcess()
if (NS_FAILED(mDirectory->GetPath(path))) {
return NS_ERROR_FAILURE;
}
LOGD(("%s::%s: %p for %s", __CLASS__, __FUNCTION__, this, path.get()));
LOGD("%s: for %s", __FUNCTION__, NS_ConvertUTF16toUTF8(path).get());
if (!mProcess) {
mProcess = new GMPProcessParent(NS_ConvertUTF16toUTF8(path).get());
@@ -142,33 +135,37 @@ GMPParent::LoadProcess()
return NS_ERROR_FAILURE;
}
#ifdef PR_LOGGING
mChildPid = base::GetProcId(mProcess->GetChildProcessHandle());
#endif
bool opened = Open(mProcess->GetChannel(),
base::GetProcId(mProcess->GetChildProcessHandle()));
if (!opened) {
LOGD(("%s::%s: Failed to create new child process %p", __CLASS__, __FUNCTION__, (void *)mProcess));
LOGD("%s: Failed to create new child process", __FUNCTION__);
mProcess->Delete();
mProcess = nullptr;
return NS_ERROR_FAILURE;
}
LOGD(("%s::%s: Created new child process %p", __CLASS__, __FUNCTION__, (void *)mProcess));
LOGD("%s: Created new child process", __FUNCTION__);
bool ok = SendSetNodeId(mNodeId);
if (!ok) {
LOGD(("%s::%s: Failed to send node id to child process %p", __CLASS__, __FUNCTION__, (void *)mProcess));
LOGD("%s: Failed to send node id to child process", __FUNCTION__);
mProcess->Delete();
mProcess = nullptr;
return NS_ERROR_FAILURE;
}
LOGD(("%s::%s: Sent node id to child process %p", __CLASS__, __FUNCTION__, (void *)mProcess));
LOGD("%s: Sent node id to child process", __FUNCTION__);
ok = SendStartPlugin();
if (!ok) {
LOGD(("%s::%s: Failed to send start to child process %p", __CLASS__, __FUNCTION__, (void *)mProcess));
LOGD("%s: Failed to send start to child process", __FUNCTION__);
mProcess->Delete();
mProcess = nullptr;
return NS_ERROR_FAILURE;
}
LOGD(("%s::%s: Sent StartPlugin to child process %p", __CLASS__, __FUNCTION__, (void *)mProcess));
LOGD("%s: Sent StartPlugin to child process", __FUNCTION__);
}
mState = GMPStateLoaded;
@@ -181,8 +178,8 @@ AbortWaitingForGMPAsyncShutdown(nsITimer* aTimer, void* aClosure)
{
NS_WARNING("Timed out waiting for GMP async shutdown!");
GMPParent* parent = reinterpret_cast<GMPParent*>(aClosure);
nsRefPtr<GeckoMediaPluginService> service =
GeckoMediaPluginService::GetGeckoMediaPluginService();
nsRefPtr<GeckoMediaPluginServiceParent> service =
GeckoMediaPluginServiceParent::GetSingleton();
if (service) {
service->AsyncShutdownComplete(parent);
}
@@ -209,8 +206,8 @@ GMPParent::EnsureAsyncShutdownTimeoutSet()
}
int32_t timeout = GMP_DEFAULT_ASYNC_SHUTDONW_TIMEOUT;
nsRefPtr<GeckoMediaPluginService> service =
GeckoMediaPluginService::GetGeckoMediaPluginService();
nsRefPtr<GeckoMediaPluginServiceParent> service =
GeckoMediaPluginServiceParent::GetSingleton();
if (service) {
timeout = service->AsyncShutdownTimeoutMs();
}
@@ -219,21 +216,26 @@ GMPParent::EnsureAsyncShutdownTimeoutSet()
nsITimer::TYPE_ONE_SHOT);
}
bool
GMPParent::RecvPGMPContentChildDestroyed()
{
--mGMPContentChildCount;
if (!IsUsed()) {
CloseIfUnused();
}
return true;
}
void
GMPParent::CloseIfUnused()
{
MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
LOGD(("%s::%s: %p mAsyncShutdownRequired=%d", __CLASS__, __FUNCTION__, this,
mAsyncShutdownRequired));
LOGD("%s: mAsyncShutdownRequired=%d", __FUNCTION__, mAsyncShutdownRequired);
if ((mDeleteProcessOnlyOnUnload ||
mState == GMPStateLoaded ||
mState == GMPStateUnloading) &&
mVideoDecoders.IsEmpty() &&
mVideoEncoders.IsEmpty() &&
mDecryptors.IsEmpty() &&
mAudioDecoders.IsEmpty()) {
!IsUsed()) {
// Ensure all timers are killed.
for (uint32_t i = mTimers.Length(); i > 0; i--) {
mTimers[i - 1]->Shutdown();
@@ -241,8 +243,7 @@ GMPParent::CloseIfUnused()
if (mAsyncShutdownRequired) {
if (!mAsyncShutdownInProgress) {
LOGD(("%s::%s: %p sending async shutdown notification", __CLASS__,
__FUNCTION__, this));
LOGD("%s: sending async shutdown notification", __FUNCTION__);
mAsyncShutdownInProgress = true;
if (!SendBeginAsyncShutdown() ||
NS_FAILED(EnsureAsyncShutdownTimeoutSet())) {
@@ -263,7 +264,7 @@ void
GMPParent::AbortAsyncShutdown()
{
MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
LOGD(("%s::%s: %p", __CLASS__, __FUNCTION__, this));
LOGD("%s", __FUNCTION__);
if (mAsyncShutdownTimeout) {
mAsyncShutdownTimeout->Cancel();
@@ -281,57 +282,21 @@ GMPParent::AbortAsyncShutdown()
CloseIfUnused();
}
void
GMPParent::AudioDecoderDestroyed(GMPAudioDecoderParent* aDecoder)
{
MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
MOZ_ALWAYS_TRUE(mAudioDecoders.RemoveElement(aDecoder));
// Recv__delete__ is on the stack, don't potentially destroy the top-level actor
// until after this has completed.
nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethod(this, &GMPParent::CloseIfUnused);
NS_DispatchToCurrentThread(event);
}
void
GMPParent::CloseActive(bool aDieWhenUnloaded)
{
LOGD(("%s::%s: %p state %d", __CLASS__, __FUNCTION__, this, mState));
LOGD("%s: state %d", __FUNCTION__, mState);
MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
if (aDieWhenUnloaded) {
mDeleteProcessOnlyOnUnload = true; // don't allow this to go back...
}
if (mState == GMPStateLoaded) {
mState = GMPStateUnloading;
}
// Invalidate and remove any remaining API objects.
for (uint32_t i = mVideoDecoders.Length(); i > 0; i--) {
mVideoDecoders[i - 1]->Shutdown();
if (mState != GMPStateNotLoaded && IsUsed()) {
unused << SendCloseActive();
}
for (uint32_t i = mVideoEncoders.Length(); i > 0; i--) {
mVideoEncoders[i - 1]->Shutdown();
}
for (uint32_t i = mDecryptors.Length(); i > 0; i--) {
mDecryptors[i - 1]->Shutdown();
}
for (uint32_t i = mAudioDecoders.Length(); i > 0; i--) {
mAudioDecoders[i - 1]->Shutdown();
}
// Note: we don't shutdown timers here, we do that in CloseIfUnused(),
// as there are multiple entry points to CloseIfUnused().
// Note: We don't shutdown storage API objects here, as they need to
// work during async shutdown of GMPs.
// Note: the shutdown of the codecs is async! don't kill
// the plugin-container until they're all safely shut down via
// CloseIfUnused();
CloseIfUnused();
}
void
@@ -350,7 +315,7 @@ GMPParent::IsMarkedForDeletion()
void
GMPParent::Shutdown()
{
LOGD(("%s::%s: %p", __CLASS__, __FUNCTION__, this));
LOGD("%s", __FUNCTION__);
MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
MOZ_ASSERT(!mAsyncShutdownTimeout, "Should have canceled shutdown timeout");
@@ -358,7 +323,8 @@ GMPParent::Shutdown()
if (mAbnormalShutdownInProgress) {
return;
}
MOZ_ASSERT(mVideoDecoders.IsEmpty() && mVideoEncoders.IsEmpty());
MOZ_ASSERT(!IsUsed());
if (mState == GMPStateNotLoaded || mState == GMPStateClosing) {
return;
}
@@ -395,18 +361,29 @@ public:
void
GMPParent::ChildTerminated()
{
nsRefPtr<GMPParent> self(this);
GMPThread()->Dispatch(NS_NewRunnableMethodWithArg<nsRefPtr<GMPParent>>(
mService,
&GeckoMediaPluginService::PluginTerminated,
self),
NS_DISPATCH_NORMAL);
RefPtr<GMPParent> self(this);
nsIThread* gmpThread = GMPThread();
if (!gmpThread) {
// Bug 1163239 - this can happen on shutdown.
// PluginTerminated removes the GMP from the GMPService.
// On shutdown we can have this case where it is already been
// removed so there is no harm in not trying to remove it again.
//LOGD("%s::%s: GMPThread() returned nullptr.", __CLASS__, __FUNCTION__);
LOGD("%s: GMPThread() returned nullptr.", __FUNCTION__);
} else {
gmpThread->Dispatch(NS_NewRunnableMethodWithArg<RefPtr<GMPParent>>(
mService,
&GeckoMediaPluginServiceParent::PluginTerminated,
self),
NS_DISPATCH_NORMAL);
}
}
void
GMPParent::DeleteProcess()
{
LOGD(("%s::%s: %p", __CLASS__, __FUNCTION__, this));
LOGD("%s", __FUNCTION__);
if (mState != GMPStateClosing) {
// Don't Close() twice!
@@ -415,7 +392,7 @@ GMPParent::DeleteProcess()
Close();
}
mProcess->Delete(NS_NewRunnableMethod(this, &GMPParent::ChildTerminated));
LOGD(("%s::%s: Shut down process %p", __CLASS__, __FUNCTION__, (void *) mProcess));
LOGD("%s: Shut down process", __FUNCTION__);
mProcess = nullptr;
mState = GMPStateNotLoaded;
@@ -425,78 +402,6 @@ GMPParent::DeleteProcess()
}
void
GMPParent::VideoDecoderDestroyed(GMPVideoDecoderParent* aDecoder)
{
MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
// If the constructor fails, we'll get called before it's added
unused << NS_WARN_IF(!mVideoDecoders.RemoveElement(aDecoder));
if (mVideoDecoders.IsEmpty() &&
mVideoEncoders.IsEmpty()) {
// Recv__delete__ is on the stack, don't potentially destroy the top-level actor
// until after this has completed.
nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethod(this, &GMPParent::CloseIfUnused);
NS_DispatchToCurrentThread(event);
}
}
void
GMPParent::VideoEncoderDestroyed(GMPVideoEncoderParent* aEncoder)
{
MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
// If the constructor fails, we'll get called before it's added
unused << NS_WARN_IF(!mVideoEncoders.RemoveElement(aEncoder));
if (mVideoDecoders.IsEmpty() &&
mVideoEncoders.IsEmpty()) {
// Recv__delete__ is on the stack, don't potentially destroy the top-level actor
// until after this has completed.
nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethod(this, &GMPParent::CloseIfUnused);
NS_DispatchToCurrentThread(event);
}
}
void
GMPParent::DecryptorDestroyed(GMPDecryptorParent* aSession)
{
MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
MOZ_ALWAYS_TRUE(mDecryptors.RemoveElement(aSession));
// Recv__delete__ is on the stack, don't potentially destroy the top-level actor
// until after this has completed.
if (mDecryptors.IsEmpty()) {
nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethod(this, &GMPParent::CloseIfUnused);
NS_DispatchToCurrentThread(event);
}
}
nsresult
GMPParent::GetGMPDecryptor(GMPDecryptorParent** aGMPDP)
{
MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
if (!EnsureProcessLoaded()) {
return NS_ERROR_FAILURE;
}
PGMPDecryptorParent* pdp = SendPGMPDecryptorConstructor();
if (!pdp) {
return NS_ERROR_FAILURE;
}
GMPDecryptorParent* dp = static_cast<GMPDecryptorParent*>(pdp);
// This addref corresponds to the Proxy pointer the consumer is returned.
// It's dropped by calling Close() on the interface.
NS_ADDREF(dp);
mDecryptors.AppendElement(dp);
*aGMPDP = dp;
return NS_OK;
}
GMPState
GMPParent::State() const
{
@@ -558,81 +463,10 @@ GMPParent::EnsureProcessLoaded()
return NS_SUCCEEDED(rv);
}
nsresult
GMPParent::GetGMPAudioDecoder(GMPAudioDecoderParent** aGMPAD)
{
MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
if (!EnsureProcessLoaded()) {
return NS_ERROR_FAILURE;
}
PGMPAudioDecoderParent* pvap = SendPGMPAudioDecoderConstructor();
if (!pvap) {
return NS_ERROR_FAILURE;
}
GMPAudioDecoderParent* vap = static_cast<GMPAudioDecoderParent*>(pvap);
// This addref corresponds to the Proxy pointer the consumer is returned.
// It's dropped by calling Close() on the interface.
NS_ADDREF(vap);
*aGMPAD = vap;
mAudioDecoders.AppendElement(vap);
return NS_OK;
}
nsresult
GMPParent::GetGMPVideoDecoder(GMPVideoDecoderParent** aGMPVD)
{
MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
if (!EnsureProcessLoaded()) {
return NS_ERROR_FAILURE;
}
// returned with one anonymous AddRef that locks it until Destroy
PGMPVideoDecoderParent* pvdp = SendPGMPVideoDecoderConstructor();
if (!pvdp) {
return NS_ERROR_FAILURE;
}
GMPVideoDecoderParent *vdp = static_cast<GMPVideoDecoderParent*>(pvdp);
// This addref corresponds to the Proxy pointer the consumer is returned.
// It's dropped by calling Close() on the interface.
NS_ADDREF(vdp);
*aGMPVD = vdp;
mVideoDecoders.AppendElement(vdp);
return NS_OK;
}
nsresult
GMPParent::GetGMPVideoEncoder(GMPVideoEncoderParent** aGMPVE)
{
MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
if (!EnsureProcessLoaded()) {
return NS_ERROR_FAILURE;
}
// returned with one anonymous AddRef that locks it until Destroy
PGMPVideoEncoderParent* pvep = SendPGMPVideoEncoderConstructor();
if (!pvep) {
return NS_ERROR_FAILURE;
}
GMPVideoEncoderParent *vep = static_cast<GMPVideoEncoderParent*>(pvep);
// This addref corresponds to the Proxy pointer the consumer is returned.
// It's dropped by calling Close() on the interface.
NS_ADDREF(vep);
*aGMPVE = vep;
mVideoEncoders.AppendElement(vep);
return NS_OK;
}
void
GMPParent::ActorDestroy(ActorDestroyReason aWhy)
{
LOGD(("%s::%s: %p (%d)", __CLASS__, __FUNCTION__, this, (int) aWhy));
LOGD("%s: (%d)", __FUNCTION__, (int)aWhy);
// warn us off trying to close again
mState = GMPStateClosing;
mAbnormalShutdownInProgress = true;
@@ -654,70 +488,6 @@ GMPParent::ActorDestroy(ActorDestroyReason aWhy)
}
}
PGMPVideoDecoderParent*
GMPParent::AllocPGMPVideoDecoderParent()
{
GMPVideoDecoderParent* vdp = new GMPVideoDecoderParent(this);
NS_ADDREF(vdp);
return vdp;
}
bool
GMPParent::DeallocPGMPVideoDecoderParent(PGMPVideoDecoderParent* aActor)
{
GMPVideoDecoderParent* vdp = static_cast<GMPVideoDecoderParent*>(aActor);
NS_RELEASE(vdp);
return true;
}
PGMPVideoEncoderParent*
GMPParent::AllocPGMPVideoEncoderParent()
{
GMPVideoEncoderParent* vep = new GMPVideoEncoderParent(this);
NS_ADDREF(vep);
return vep;
}
bool
GMPParent::DeallocPGMPVideoEncoderParent(PGMPVideoEncoderParent* aActor)
{
GMPVideoEncoderParent* vep = static_cast<GMPVideoEncoderParent*>(aActor);
NS_RELEASE(vep);
return true;
}
PGMPDecryptorParent*
GMPParent::AllocPGMPDecryptorParent()
{
GMPDecryptorParent* ksp = new GMPDecryptorParent(this);
NS_ADDREF(ksp);
return ksp;
}
bool
GMPParent::DeallocPGMPDecryptorParent(PGMPDecryptorParent* aActor)
{
GMPDecryptorParent* ksp = static_cast<GMPDecryptorParent*>(aActor);
NS_RELEASE(ksp);
return true;
}
PGMPAudioDecoderParent*
GMPParent::AllocPGMPAudioDecoderParent()
{
GMPAudioDecoderParent* vdp = new GMPAudioDecoderParent(this);
NS_ADDREF(vdp);
return vdp;
}
bool
GMPParent::DeallocPGMPAudioDecoderParent(PGMPAudioDecoderParent* aActor)
{
GMPAudioDecoderParent* vdp = static_cast<GMPAudioDecoderParent*>(aActor);
NS_RELEASE(vdp);
return true;
}
PGMPStorageParent*
GMPParent::AllocPGMPStorageParent()
{
@@ -963,7 +733,7 @@ GMPParent::GetVersion() const
return mVersion;
}
const nsACString&
const nsCString&
GMPParent::GetPluginId() const
{
return mPluginId;
@@ -972,7 +742,7 @@ GMPParent::GetPluginId() const
bool
GMPParent::RecvAsyncShutdownRequired()
{
LOGD(("%s::%s: %p", __CLASS__, __FUNCTION__, this));
LOGD("%s", __FUNCTION__);
if (mAsyncShutdownRequired) {
NS_WARNING("Received AsyncShutdownRequired message more than once!");
return true;
@@ -985,12 +755,116 @@ GMPParent::RecvAsyncShutdownRequired()
bool
GMPParent::RecvAsyncShutdownComplete()
{
LOGD(("%s::%s: %p", __CLASS__, __FUNCTION__, this));
LOGD("%s", __FUNCTION__);
MOZ_ASSERT(mAsyncShutdownRequired);
AbortAsyncShutdown();
return true;
}
class RunCreateContentParentCallbacks : public nsRunnable
{
public:
explicit RunCreateContentParentCallbacks(GMPContentParent* aGMPContentParent)
: mGMPContentParent(aGMPContentParent)
{
}
void TakeCallbacks(nsTArray<UniquePtr<GetGMPContentParentCallback>>& aCallbacks)
{
mCallbacks.SwapElements(aCallbacks);
}
NS_IMETHOD
Run()
{
for (uint32_t i = 0, length = mCallbacks.Length(); i < length; ++i) {
mCallbacks[i]->Done(mGMPContentParent);
}
return NS_OK;
}
private:
nsRefPtr<GMPContentParent> mGMPContentParent;
nsTArray<UniquePtr<GetGMPContentParentCallback>> mCallbacks;
};
PGMPContentParent*
GMPParent::AllocPGMPContentParent(Transport* aTransport, ProcessId aOtherPid)
{
MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
MOZ_ASSERT(!mGMPContentParent);
mGMPContentParent = new GMPContentParent(this);
mGMPContentParent->Open(aTransport, aOtherPid, XRE_GetIOMessageLoop(),
ipc::ParentSide);
nsRefPtr<RunCreateContentParentCallbacks> runCallbacks =
new RunCreateContentParentCallbacks(mGMPContentParent);
runCallbacks->TakeCallbacks(mCallbacks);
NS_DispatchToCurrentThread(runCallbacks);
MOZ_ASSERT(mCallbacks.IsEmpty());
return mGMPContentParent;
}
bool
GMPParent::GetGMPContentParent(UniquePtr<GetGMPContentParentCallback>&& aCallback)
{
LOGD("%s %p", __FUNCTION__, this);
MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
if (mGMPContentParent) {
aCallback->Done(mGMPContentParent);
} else {
mCallbacks.AppendElement(Move(aCallback));
// If we don't have a GMPContentParent and we try to get one for the first
// time (mCallbacks.Length() == 1) then call PGMPContent::Open. If more
// calls to GetGMPContentParent happen before mGMPContentParent has been
// set then we should just store them, so that they get called when we set
// mGMPContentParent as a result of the PGMPContent::Open call.
if (mCallbacks.Length() == 1) {
if (!EnsureProcessLoaded() || !PGMPContent::Open(this)) {
return false;
}
// We want to increment this as soon as possible, to avoid that we'd try
// to shut down the GMP process while we're still trying to get a
// PGMPContentParent actor.
++mGMPContentChildCount;
}
}
return true;
}
already_AddRefed<GMPContentParent>
GMPParent::ForgetGMPContentParent()
{
MOZ_ASSERT(mCallbacks.IsEmpty());
return Move(mGMPContentParent.forget());
}
bool
GMPParent::EnsureProcessLoaded(base::ProcessId* aID)
{
if (!EnsureProcessLoaded()) {
return false;
}
*aID = OtherPid();
return true;
}
bool
GMPParent::Bridge(GMPServiceParent* aGMPServiceParent)
{
if (!PGMPContent::Bridge(aGMPServiceParent, this)) {
return false;
}
++mGMPContentChildCount;
return true;
}
} // namespace gmp
} // namespace mozilla
#undef LOG
#undef LOGD
+47 -37
View File
@@ -7,7 +7,7 @@
#define GMPParent_h_
#include "GMPProcessParent.h"
#include "GMPService.h"
#include "GMPServiceParent.h"
#include "GMPAudioDecoderParent.h"
#include "GMPDecryptorParent.h"
#include "GMPVideoDecoderParent.h"
@@ -43,15 +43,30 @@ enum GMPState {
GMPStateClosing
};
class GMPParent final : public PGMPParent,
public GMPSharedMem
class GMPContentParent;
class GetGMPContentParentCallback
{
public:
GetGMPContentParentCallback()
{
MOZ_COUNT_CTOR(GetGMPContentParentCallback);
};
virtual ~GetGMPContentParentCallback()
{
MOZ_COUNT_DTOR(GetGMPContentParentCallback);
};
virtual void Done(GMPContentParent* aGMPContentParent) = 0;
};
class GMPParent final : public PGMPParent
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(GMPParent)
GMPParent();
nsresult Init(GeckoMediaPluginService *aService, nsIFile* aPluginDir);
nsresult Init(GeckoMediaPluginServiceParent* aService, nsIFile* aPluginDir);
nsresult CloneFrom(const GMPParent* aOther);
void Crash();
@@ -77,18 +92,6 @@ public:
bool SupportsAPI(const nsCString& aAPI, const nsCString& aTag);
nsresult GetGMPVideoDecoder(GMPVideoDecoderParent** aGMPVD);
void VideoDecoderDestroyed(GMPVideoDecoderParent* aDecoder);
nsresult GetGMPVideoEncoder(GMPVideoEncoderParent** aGMPVE);
void VideoEncoderDestroyed(GMPVideoEncoderParent* aEncoder);
nsresult GetGMPDecryptor(GMPDecryptorParent** aGMPKS);
void DecryptorDestroyed(GMPDecryptorParent* aSession);
nsresult GetGMPAudioDecoder(GMPAudioDecoderParent** aGMPAD);
void AudioDecoderDestroyed(GMPAudioDecoderParent* aDecoder);
GMPState State() const;
nsIThread* GMPThread();
@@ -110,7 +113,7 @@ public:
const nsCString& GetDisplayName() const;
const nsCString& GetVersion() const;
const nsACString& GetPluginId() const;
const nsCString& GetPluginId() const;
// Returns true if a plugin can be or is being used across multiple NodeIds.
bool CanBeSharedCrossNodeIds() const;
@@ -124,37 +127,32 @@ public:
return nsCOMPtr<nsIFile>(mDirectory).forget();
}
// GMPSharedMem
virtual void CheckThread() override;
void AbortAsyncShutdown();
// Called when the child process has died.
void ChildTerminated();
bool GetGMPContentParent(UniquePtr<GetGMPContentParentCallback>&& aCallback);
already_AddRefed<GMPContentParent> ForgetGMPContentParent();
bool EnsureProcessLoaded(base::ProcessId* aID);
bool Bridge(GMPServiceParent* aGMPServiceParent);
private:
~GMPParent();
nsRefPtr<GeckoMediaPluginService> mService;
nsRefPtr<GeckoMediaPluginServiceParent> mService;
bool EnsureProcessLoaded();
nsresult ReadGMPMetaData();
virtual void ActorDestroy(ActorDestroyReason aWhy) override;
virtual PGMPVideoDecoderParent* AllocPGMPVideoDecoderParent() override;
virtual bool DeallocPGMPVideoDecoderParent(PGMPVideoDecoderParent* aActor) override;
virtual PGMPVideoEncoderParent* AllocPGMPVideoEncoderParent() override;
virtual bool DeallocPGMPVideoEncoderParent(PGMPVideoEncoderParent* aActor) override;
virtual PGMPDecryptorParent* AllocPGMPDecryptorParent() override;
virtual bool DeallocPGMPDecryptorParent(PGMPDecryptorParent* aActor) override;
virtual PGMPAudioDecoderParent* AllocPGMPAudioDecoderParent() override;
virtual bool DeallocPGMPAudioDecoderParent(PGMPAudioDecoderParent* aActor) override;
virtual bool RecvPGMPStorageConstructor(PGMPStorageParent* actor) override;
virtual PGMPStorageParent* AllocPGMPStorageParent() override;
virtual bool DeallocPGMPStorageParent(PGMPStorageParent* aActor) override;
virtual PGMPContentParent* AllocPGMPContentParent(Transport* aTransport,
ProcessId aOtherPid) override;
virtual bool RecvPGMPTimerConstructor(PGMPTimerParent* actor) override;
virtual PGMPTimerParent* AllocPGMPTimerParent() override;
virtual bool DeallocPGMPTimerParent(PGMPTimerParent* aActor) override;
@@ -162,6 +160,13 @@ private:
virtual bool RecvAsyncShutdownComplete() override;
virtual bool RecvAsyncShutdownRequired() override;
virtual bool RecvPGMPContentChildDestroyed() override;
bool IsUsed()
{
return mGMPContentChildCount > 0;
}
nsresult EnsureAsyncShutdownTimeoutSet();
GMPState mState;
@@ -179,10 +184,6 @@ private:
bool mCanDecrypt;
nsTArray<nsRefPtr<GMPVideoDecoderParent>> mVideoDecoders;
nsTArray<nsRefPtr<GMPVideoEncoderParent>> mVideoEncoders;
nsTArray<nsRefPtr<GMPDecryptorParent>> mDecryptors;
nsTArray<nsRefPtr<GMPAudioDecoderParent>> mAudioDecoders;
nsTArray<nsRefPtr<GMPTimerParent>> mTimers;
nsTArray<nsRefPtr<GMPStorageParent>> mStorage;
nsCOMPtr<nsIThread> mGMPThread;
@@ -190,9 +191,18 @@ private:
// NodeId the plugin is assigned to, or empty if the the plugin is not
// assigned to a NodeId.
nsAutoCString mNodeId;
// This is used for GMP content in the parent, there may be more of these in
// the content processes.
nsRefPtr<GMPContentParent> mGMPContentParent;
nsTArray<UniquePtr<GetGMPContentParentCallback>> mCallbacks;
uint32_t mGMPContentChildCount;
bool mAsyncShutdownRequired;
bool mAsyncShutdownInProgress;
#ifdef PR_LOGGING
int mChildPid;
#endif
};
} // namespace gmp
+141 -1360
View File
File diff suppressed because it is too large Load Diff
+40 -126
View File
@@ -15,37 +15,49 @@
#include "nsString.h"
#include "nsCOMPtr.h"
#include "nsIThread.h"
#include "nsThreadUtils.h"
#include "nsITimer.h"
#include "nsClassHashtable.h"
#include "nsDataHashtable.h"
#include "mozilla/Atomics.h"
template <class> struct already_AddRefed;
namespace mozilla {
extern PRLogModuleInfo* GetGMPLog();
namespace gmp {
class GMPParent;
class GetGMPContentParentCallback;
#define GMP_DEFAULT_ASYNC_SHUTDONW_TIMEOUT 3000
class GeckoMediaPluginService final : public mozIGeckoMediaPluginService
, public nsIObserver
class GeckoMediaPluginService : public mozIGeckoMediaPluginService
, public nsIObserver
{
public:
static already_AddRefed<GeckoMediaPluginService> GetGeckoMediaPluginService();
GeckoMediaPluginService();
nsresult Init();
virtual nsresult Init();
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_MOZIGECKOMEDIAPLUGINSERVICE
NS_DECL_NSIOBSERVER
void AsyncShutdownNeeded(GMPParent* aParent);
void AsyncShutdownComplete(GMPParent* aParent);
void AbortAsyncShutdown();
// mozIGeckoMediaPluginService
NS_IMETHOD GetThread(nsIThread** aThread) override;
NS_IMETHOD HasPluginForAPI(const nsACString& aAPI, nsTArray<nsCString>* aTags,
bool *aRetVal) override;
NS_IMETHOD GetGMPVideoDecoder(nsTArray<nsCString>* aTags,
const nsACString& aNodeId,
UniquePtr<GetGMPVideoDecoderCallback>&& aCallback)
override;
NS_IMETHOD GetGMPVideoEncoder(nsTArray<nsCString>* aTags,
const nsACString& aNodeId,
UniquePtr<GetGMPVideoEncoderCallback>&& aCallback)
override;
NS_IMETHOD GetGMPAudioDecoder(nsTArray<nsCString>* aTags,
const nsACString& aNodeId,
UniquePtr<GetGMPAudioDecoderCallback>&& aCallback)
override;
NS_IMETHOD GetGMPDecryptor(nsTArray<nsCString>* aTags,
const nsACString& aNodeId,
UniquePtr<GetGMPDecryptorCallback>&& aCallback)
override;
int32_t AsyncShutdownTimeoutMs();
@@ -77,127 +89,29 @@ public:
const nsACString& aPluginName,
const nsAString& aPluginDumpId);
private:
~GeckoMediaPluginService();
protected:
GeckoMediaPluginService();
virtual ~GeckoMediaPluginService();
virtual void InitializePlugins() = 0;
virtual bool GetContentParentFrom(const nsACString& aNodeId,
const nsCString& aAPI,
const nsTArray<nsCString>& aTags,
UniquePtr<GetGMPContentParentCallback>&& aCallback) = 0;
nsresult GMPDispatch(nsIRunnable* event, uint32_t flags = NS_DISPATCH_NORMAL);
void ClearStorage();
GMPParent* SelectPluginForAPI(const nsACString& aNodeId,
const nsCString& aAPI,
const nsTArray<nsCString>& aTags);
GMPParent* FindPluginForAPIFrom(size_t aSearchStartIndex,
const nsCString& aAPI,
const nsTArray<nsCString>& aTags,
size_t* aOutPluginIndex);
void UnloadPlugins();
void CrashPlugins();
void SetAsyncShutdownComplete();
void LoadFromEnvironment();
void ProcessPossiblePlugin(nsIFile* aDir);
void AddOnGMPThread(const nsAString& aDirectory);
void RemoveOnGMPThread(const nsAString& aDirectory,
const bool aDeleteFromDisk,
const bool aCanDefer);
nsresult SetAsyncShutdownTimeout();
struct DirectoryFilter {
virtual bool operator()(nsIFile* aPath) = 0;
~DirectoryFilter() {}
};
void ClearNodeIdAndPlugin(DirectoryFilter& aFilter);
void ForgetThisSiteOnGMPThread(const nsACString& aOrigin);
void ClearRecentHistoryOnGMPThread(PRTime aSince);
void ShutdownGMPThread();
protected:
friend class GMPParent;
void ReAddOnGMPThread(const nsRefPtr<GMPParent>& aOld);
void PluginTerminated(const nsRefPtr<GMPParent>& aOld);
private:
GMPParent* ClonePlugin(const GMPParent* aOriginal);
nsresult EnsurePluginsOnDiskScanned();
class PathRunnable : public nsRunnable
{
public:
enum EOperation {
ADD,
REMOVE,
REMOVE_AND_DELETE_FROM_DISK,
};
PathRunnable(GeckoMediaPluginService* aService, const nsAString& aPath,
EOperation aOperation, bool aDefer = false)
: mService(aService)
, mPath(aPath)
, mOperation(aOperation)
, mDefer(aDefer)
{ }
NS_DECL_NSIRUNNABLE
private:
nsRefPtr<GeckoMediaPluginService> mService;
nsString mPath;
EOperation mOperation;
bool mDefer;
};
Mutex mMutex; // Protects mGMPThread and mShuttingDown and mPlugins
nsTArray<nsRefPtr<GMPParent>> mPlugins;
Mutex mMutex; // Protects mGMPThread and mGMPThreadShutdown and some members
// in derived classes.
nsCOMPtr<nsIThread> mGMPThread;
bool mShuttingDown;
bool mGMPThreadShutdown;
bool mShuttingDownOnGMPThread;
nsTArray<nsRefPtr<PluginCrashCallback>> mPluginCrashCallbacks;
// True if we've inspected MOZ_GMP_PATH on the GMP thread and loaded any
// plugins found there into mPlugins.
Atomic<bool> mScannedPluginOnDisk;
template<typename T>
class MainThreadOnly {
public:
MOZ_IMPLICIT MainThreadOnly(T aValue)
: mValue(aValue)
{}
operator T&() {
MOZ_ASSERT(NS_IsMainThread());
return mValue;
}
private:
T mValue;
};
MainThreadOnly<bool> mWaitingForPluginsAsyncShutdown;
nsTArray<nsRefPtr<GMPParent>> mAsyncShutdownPlugins; // GMP Thread only.
nsTArray<nsString> mPluginsWaitingForDeletion;
#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;
};
nsresult ReadSalt(nsIFile* aPath, nsACString& aOutData);
bool MatchOrigin(nsIFile* aPath, const nsACString& aSite);
} // namespace gmp
} // namespace mozilla
+382
View File
@@ -0,0 +1,382 @@
/* -*- 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 "GMPService.h"
#include "mozilla/dom/ContentChild.h"
namespace mozilla {
#ifdef LOG
#undef LOG
#endif
#ifdef PR_LOGGING
#define LOGD(msg) PR_LOG(GetGMPLog(), PR_LOG_DEBUG, msg)
#define LOG(level, msg) PR_LOG(GetGMPLog(), (level), msg)
#else
#define LOGD(msg)
#define LOG(leve1, msg)
#endif
#ifdef __CLASS__
#undef __CLASS__
#endif
#define __CLASS__ "GMPService"
namespace gmp {
already_AddRefed<GeckoMediaPluginServiceChild>
GeckoMediaPluginServiceChild::GetSingleton()
{
MOZ_ASSERT(XRE_GetProcessType() != GeckoProcessType_Default);
nsRefPtr<GeckoMediaPluginService> service(
GeckoMediaPluginService::GetGeckoMediaPluginService());
#ifdef DEBUG
if (service) {
nsCOMPtr<mozIGeckoMediaPluginChromeService> chromeService;
CallQueryInterface(service.get(), getter_AddRefs(chromeService));
MOZ_ASSERT(!chromeService);
}
#endif
return service.forget().downcast<GeckoMediaPluginServiceChild>();
}
class GetServiceChildCallback
{
public:
GetServiceChildCallback()
{
MOZ_COUNT_CTOR(GetServiceChildCallback);
}
virtual ~GetServiceChildCallback()
{
MOZ_COUNT_DTOR(GetServiceChildCallback);
}
virtual void Done(GMPServiceChild* aGMPServiceChild) = 0;
};
class GetContentParentFromDone : public GetServiceChildCallback
{
public:
GetContentParentFromDone(const nsACString& aNodeId, const nsCString& aAPI,
const nsTArray<nsCString>& aTags,
UniquePtr<GetGMPContentParentCallback>&& aCallback)
: mNodeId(aNodeId),
mAPI(aAPI),
mTags(aTags),
mCallback(Move(aCallback))
{
}
virtual void Done(GMPServiceChild* aGMPServiceChild)
{
if (!aGMPServiceChild) {
mCallback->Done(nullptr);
return;
}
nsTArray<base::ProcessId> alreadyBridgedTo;
aGMPServiceChild->GetAlreadyBridgedTo(alreadyBridgedTo);
base::ProcessId otherProcess;
nsCString displayName;
nsCString pluginId;
bool ok = aGMPServiceChild->SendLoadGMP(mNodeId, mAPI, mTags,
alreadyBridgedTo, &otherProcess,
&displayName, &pluginId);
if (!ok) {
mCallback->Done(nullptr);
return;
}
nsRefPtr<GMPContentParent> parent;
aGMPServiceChild->GetBridgedGMPContentParent(otherProcess,
getter_AddRefs(parent));
if (!alreadyBridgedTo.Contains(otherProcess)) {
parent->SetDisplayName(displayName);
parent->SetPluginId(pluginId);
}
mCallback->Done(parent);
}
private:
nsCString mNodeId;
nsCString mAPI;
const nsTArray<nsCString> mTags;
UniquePtr<GetGMPContentParentCallback> mCallback;
};
bool
GeckoMediaPluginServiceChild::GetContentParentFrom(const nsACString& aNodeId,
const nsCString& aAPI,
const nsTArray<nsCString>& aTags,
UniquePtr<GetGMPContentParentCallback>&& aCallback)
{
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
UniquePtr<GetServiceChildCallback> callback(
new GetContentParentFromDone(aNodeId, aAPI, aTags, Move(aCallback)));
GetServiceChild(Move(callback));
return true;
}
NS_IMETHODIMP
GeckoMediaPluginServiceChild::GetPluginVersionForAPI(const nsACString& aAPI,
nsTArray<nsCString>* aTags,
bool* aHasPlugin,
nsACString& aOutVersion)
{
dom::ContentChild* contentChild = dom::ContentChild::GetSingleton();
if (!contentChild) {
return NS_ERROR_FAILURE;
}
MOZ_ASSERT(NS_IsMainThread());
nsCString version;
bool ok = contentChild->SendGetGMPPluginVersionForAPI(nsCString(aAPI), *aTags,
aHasPlugin, &version);
aOutVersion = version;
return ok ? NS_OK : NS_ERROR_FAILURE;
}
class GetNodeIdDone : public GetServiceChildCallback
{
public:
GetNodeIdDone(const nsAString& aOrigin, const nsAString& aTopLevelOrigin,
bool aInPrivateBrowsing,
UniquePtr<GetNodeIdCallback>&& aCallback)
: mOrigin(aOrigin),
mTopLevelOrigin(aTopLevelOrigin),
mInPrivateBrowsing(aInPrivateBrowsing),
mCallback(Move(aCallback))
{
}
virtual void Done(GMPServiceChild* aGMPServiceChild)
{
if (!aGMPServiceChild) {
mCallback->Done(NS_ERROR_FAILURE, EmptyCString());
return;
}
nsCString outId;
if (!aGMPServiceChild->SendGetGMPNodeId(mOrigin, mTopLevelOrigin,
mInPrivateBrowsing, &outId)) {
mCallback->Done(NS_ERROR_FAILURE, EmptyCString());
return;
}
mCallback->Done(NS_OK, outId);
}
private:
nsString mOrigin;
nsString mTopLevelOrigin;
bool mInPrivateBrowsing;
UniquePtr<GetNodeIdCallback> mCallback;
};
NS_IMETHODIMP
GeckoMediaPluginServiceChild::GetNodeId(const nsAString& aOrigin,
const nsAString& aTopLevelOrigin,
bool aInPrivateBrowsing,
UniquePtr<GetNodeIdCallback>&& aCallback)
{
UniquePtr<GetServiceChildCallback> callback(
new GetNodeIdDone(aOrigin, aTopLevelOrigin, aInPrivateBrowsing,
Move(aCallback)));
GetServiceChild(Move(callback));
return NS_OK;
}
NS_IMETHODIMP
GeckoMediaPluginServiceChild::Observe(nsISupports* aSubject,
const char* aTopic,
const char16_t* aSomeData)
{
LOGD(("%s::%s: %s", __CLASS__, __FUNCTION__, aTopic));
if (!strcmp(NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID, aTopic)) {
if (mServiceChild) {
mozilla::SyncRunnable::DispatchToThread(mGMPThread,
WrapRunnable(mServiceChild.get(),
&PGMPServiceChild::Close));
mServiceChild = nullptr;
}
ShutdownGMPThread();
}
return NS_OK;
}
void
GeckoMediaPluginServiceChild::GetServiceChild(UniquePtr<GetServiceChildCallback>&& aCallback)
{
MOZ_ASSERT(!NS_IsMainThread());
if (!mServiceChild) {
dom::ContentChild* contentChild = dom::ContentChild::GetSingleton();
if (!contentChild) {
return;
}
mGetServiceChildCallbacks.AppendElement(Move(aCallback));
if (mGetServiceChildCallbacks.Length() == 1) {
NS_DispatchToMainThread(WrapRunnable(contentChild,
&dom::ContentChild::SendCreateGMPService));
}
return;
}
aCallback->Done(mServiceChild.get());
}
void
GeckoMediaPluginServiceChild::SetServiceChild(UniquePtr<GMPServiceChild>&& aServiceChild)
{
mServiceChild = Move(aServiceChild);
nsTArray<UniquePtr<GetServiceChildCallback>> getServiceChildCallbacks;
getServiceChildCallbacks.SwapElements(mGetServiceChildCallbacks);
for (uint32_t i = 0, length = getServiceChildCallbacks.Length(); i < length; ++i) {
getServiceChildCallbacks[i]->Done(mServiceChild.get());
}
}
void
GeckoMediaPluginServiceChild::RemoveGMPContentParent(GMPContentParent* aGMPContentParent)
{
if (mServiceChild) {
mServiceChild->RemoveGMPContentParent(aGMPContentParent);
}
}
GMPServiceChild::GMPServiceChild()
{
}
GMPServiceChild::~GMPServiceChild()
{
XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
new DeleteTask<Transport>(GetTransport()));
}
PGMPContentParent*
GMPServiceChild::AllocPGMPContentParent(Transport* aTransport,
ProcessId aOtherPid)
{
MOZ_ASSERT(!mContentParents.GetWeak(aOtherPid));
nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
MOZ_ASSERT(mainThread);
nsRefPtr<GMPContentParent> parent = new GMPContentParent();
DebugOnly<bool> ok = parent->Open(aTransport, aOtherPid,
XRE_GetIOMessageLoop(),
mozilla::ipc::ParentSide);
MOZ_ASSERT(ok);
mContentParents.Put(aOtherPid, parent);
return parent;
}
void
GMPServiceChild::GetBridgedGMPContentParent(ProcessId aOtherPid,
GMPContentParent** aGMPContentParent)
{
mContentParents.Get(aOtherPid, aGMPContentParent);
}
static PLDHashOperator
FindAndRemoveGMPContentParent(const uint64_t& aKey,
nsRefPtr<GMPContentParent>& aData,
void* aUserArg)
{
return aData == aUserArg ?
(PLDHashOperator)(PL_DHASH_STOP | PL_DHASH_REMOVE) :
PL_DHASH_NEXT;
}
void
GMPServiceChild::RemoveGMPContentParent(GMPContentParent* aGMPContentParent)
{
mContentParents.Enumerate(FindAndRemoveGMPContentParent, aGMPContentParent);
}
static PLDHashOperator
FillProcessIDArray(const uint64_t& aKey, GMPContentParent*, void* aUserArg)
{
static_cast<nsTArray<base::ProcessId>*>(aUserArg)->AppendElement(aKey);
return PL_DHASH_NEXT;
}
void
GMPServiceChild::GetAlreadyBridgedTo(nsTArray<base::ProcessId>& aAlreadyBridgedTo)
{
aAlreadyBridgedTo.SetCapacity(mContentParents.Count());
mContentParents.EnumerateRead(FillProcessIDArray, &aAlreadyBridgedTo);
}
class OpenPGMPServiceChild : public nsRunnable
{
public:
OpenPGMPServiceChild(UniquePtr<GMPServiceChild>&& aGMPServiceChild,
mozilla::ipc::Transport* aTransport,
base::ProcessId aOtherPid)
: mGMPServiceChild(Move(aGMPServiceChild)),
mTransport(aTransport),
mOtherPid(aOtherPid)
{
}
NS_IMETHOD Run()
{
nsRefPtr<GeckoMediaPluginServiceChild> gmp =
GeckoMediaPluginServiceChild::GetSingleton();
MOZ_ASSERT(!gmp->mServiceChild);
if (mGMPServiceChild->Open(mTransport, mOtherPid, XRE_GetIOMessageLoop(),
ipc::ChildSide)) {
gmp->SetServiceChild(Move(mGMPServiceChild));
} else {
gmp->SetServiceChild(nullptr);
}
return NS_OK;
}
private:
UniquePtr<GMPServiceChild> mGMPServiceChild;
mozilla::ipc::Transport* mTransport;
base::ProcessId mOtherPid;
};
/* static */
PGMPServiceChild*
GMPServiceChild::Create(Transport* aTransport, ProcessId aOtherPid)
{
nsRefPtr<GeckoMediaPluginServiceChild> gmp =
GeckoMediaPluginServiceChild::GetSingleton();
MOZ_ASSERT(!gmp->mServiceChild);
UniquePtr<GMPServiceChild> serviceChild(new GMPServiceChild());
nsCOMPtr<nsIThread> gmpThread;
nsresult rv = gmp->GetThread(getter_AddRefs(gmpThread));
NS_ENSURE_SUCCESS(rv, nullptr);
GMPServiceChild* result = serviceChild.get();
rv = gmpThread->Dispatch(new OpenPGMPServiceChild(Move(serviceChild),
aTransport,
aOtherPid),
NS_DISPATCH_NORMAL);
if (NS_FAILED(rv)) {
return nullptr;
}
return result;
}
} // namespace gmp
} // namespace mozilla
+90
View File
@@ -0,0 +1,90 @@
/* -*- 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 GMPServiceChild_h_
#define GMPServiceChild_h_
#include "GMPService.h"
#include "base/process.h"
#include "mozilla/ipc/Transport.h"
#include "mozilla/gmp/PGMPServiceChild.h"
namespace mozilla {
namespace gmp {
#define GMP_DEFAULT_ASYNC_SHUTDONW_TIMEOUT 3000
class GMPContentParent;
class GMPServiceChild;
class GetServiceChildCallback;
class GeckoMediaPluginServiceChild : public GeckoMediaPluginService
{
friend class GMPServiceChild;
public:
static already_AddRefed<GeckoMediaPluginServiceChild> GetSingleton();
NS_IMETHOD GetPluginVersionForAPI(const nsACString& aAPI,
nsTArray<nsCString>* aTags,
bool* aHasPlugin,
nsACString& aOutVersion) override;
NS_IMETHOD GetNodeId(const nsAString& aOrigin,
const nsAString& aTopLevelOrigin,
bool aInPrivateBrowsingMode,
UniquePtr<GetNodeIdCallback>&& aCallback) override;
NS_DECL_NSIOBSERVER
void SetServiceChild(UniquePtr<GMPServiceChild>&& aServiceChild);
void RemoveGMPContentParent(GMPContentParent* aGMPContentParent);
protected:
virtual void InitializePlugins() override
{
// Nothing to do here.
}
virtual bool GetContentParentFrom(const nsACString& aNodeId,
const nsCString& aAPI,
const nsTArray<nsCString>& aTags,
UniquePtr<GetGMPContentParentCallback>&& aCallback)
override;
private:
friend class OpenPGMPServiceChild;
void GetServiceChild(UniquePtr<GetServiceChildCallback>&& aCallback);
UniquePtr<GMPServiceChild> mServiceChild;
nsTArray<UniquePtr<GetServiceChildCallback>> mGetServiceChildCallbacks;
};
class GMPServiceChild : public PGMPServiceChild
{
public:
explicit GMPServiceChild();
virtual ~GMPServiceChild();
virtual PGMPContentParent* AllocPGMPContentParent(Transport* aTransport,
ProcessId aOtherPid)
override;
void GetBridgedGMPContentParent(ProcessId aOtherPid,
GMPContentParent** aGMPContentParent);
void RemoveGMPContentParent(GMPContentParent* aGMPContentParent);
void GetAlreadyBridgedTo(nsTArray<ProcessId>& aAlreadyBridgedTo);
static PGMPServiceChild* Create(Transport* aTransport, ProcessId aOtherPid);
private:
nsRefPtrHashtable<nsUint64HashKey, GMPContentParent> mContentParents;
};
} // namespace gmp
} // namespace mozilla
#endif // GMPServiceChild_h_
File diff suppressed because it is too large Load Diff
+214
View File
@@ -0,0 +1,214 @@
/* -*- 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 GMPServiceParent_h_
#define GMPServiceParent_h_
#include "GMPService.h"
#include "mozilla/gmp/PGMPServiceParent.h"
#include "mozIGeckoMediaPluginChromeService.h"
#include "nsClassHashtable.h"
#include "nsDataHashtable.h"
#include "mozilla/Atomics.h"
#include "nsThreadUtils.h"
template <class> struct already_AddRefed;
namespace mozilla {
namespace gmp {
class GMPParent;
#define GMP_DEFAULT_ASYNC_SHUTDONW_TIMEOUT 3000
class GeckoMediaPluginServiceParent final : public GeckoMediaPluginService
, public mozIGeckoMediaPluginChromeService
{
public:
static already_AddRefed<GeckoMediaPluginServiceParent> GetSingleton();
GeckoMediaPluginServiceParent();
virtual nsresult Init() override;
NS_DECL_ISUPPORTS_INHERITED
// mozIGeckoMediaPluginService
NS_IMETHOD GetPluginVersionForAPI(const nsACString& aAPI,
nsTArray<nsCString>* aTags,
bool* aHasPlugin,
nsACString& aOutVersion) override;
NS_IMETHOD GetNodeId(const nsAString& aOrigin,
const nsAString& aTopLevelOrigin,
bool aInPrivateBrowsingMode,
UniquePtr<GetNodeIdCallback>&& aCallback) override;
NS_DECL_MOZIGECKOMEDIAPLUGINCHROMESERVICE
NS_DECL_NSIOBSERVER
void AsyncShutdownNeeded(GMPParent* aParent);
void AsyncShutdownComplete(GMPParent* aParent);
void AbortAsyncShutdown();
int32_t AsyncShutdownTimeoutMs();
private:
friend class GMPServiceParent;
virtual ~GeckoMediaPluginServiceParent();
void ClearStorage();
GMPParent* SelectPluginForAPI(const nsACString& aNodeId,
const nsCString& aAPI,
const nsTArray<nsCString>& aTags);
GMPParent* FindPluginForAPIFrom(size_t aSearchStartIndex,
const nsCString& aAPI,
const nsTArray<nsCString>& aTags,
size_t* aOutPluginIndex);
nsresult GetNodeId(const nsAString& aOrigin, const nsAString& aTopLevelOrigin,
bool aInPrivateBrowsing, nsACString& aOutId);
void UnloadPlugins();
void CrashPlugins();
void SetAsyncShutdownComplete();
void LoadFromEnvironment();
void ProcessPossiblePlugin(nsIFile* aDir);
void AddOnGMPThread(const nsAString& aDirectory);
void RemoveOnGMPThread(const nsAString& aDirectory,
const bool aDeleteFromDisk);
nsresult SetAsyncShutdownTimeout();
struct DirectoryFilter {
virtual bool operator()(nsIFile* aPath) = 0;
~DirectoryFilter() {}
};
void ClearNodeIdAndPlugin(DirectoryFilter& aFilter);
void ForgetThisSiteOnGMPThread(const nsACString& aOrigin);
void ClearRecentHistoryOnGMPThread(PRTime aSince);
protected:
friend class GMPParent;
void ReAddOnGMPThread(nsRefPtr<GMPParent>& aOld);
void PluginTerminated(const RefPtr<GMPParent>& aOld);
virtual void InitializePlugins() override;
virtual bool GetContentParentFrom(const nsACString& aNodeId,
const nsCString& aAPI,
const nsTArray<nsCString>& aTags,
UniquePtr<GetGMPContentParentCallback>&& aCallback)
override;
private:
GMPParent* ClonePlugin(const GMPParent* aOriginal);
nsresult EnsurePluginsOnDiskScanned();
nsresult InitStorage();
class PathRunnable : public nsRunnable
{
public:
enum EOperation {
ADD,
REMOVE,
REMOVE_AND_DELETE_FROM_DISK,
};
PathRunnable(GeckoMediaPluginServiceParent* aService, const nsAString& aPath,
EOperation aOperation)
: mService(aService)
, mPath(aPath)
, mOperation(aOperation)
{ }
NS_DECL_NSIRUNNABLE
private:
nsRefPtr<GeckoMediaPluginServiceParent> mService;
nsString mPath;
EOperation mOperation;
};
// Protected by mMutex from the base class.
nsTArray<nsRefPtr<GMPParent>> mPlugins;
bool mShuttingDown;
// True if we've inspected MOZ_GMP_PATH on the GMP thread and loaded any
// plugins found there into mPlugins.
Atomic<bool> mScannedPluginOnDisk;
template<typename T>
class MainThreadOnly {
public:
MOZ_IMPLICIT MainThreadOnly(T aValue)
: mValue(aValue)
{}
operator T&() {
MOZ_ASSERT(NS_IsMainThread());
return mValue;
}
private:
T mValue;
};
MainThreadOnly<bool> mWaitingForPluginsAsyncShutdown;
nsTArray<nsString> mPluginsWaitingForDeletion;
nsTArray<nsRefPtr<GMPParent>> mAsyncShutdownPlugins; // GMP Thread only.
nsCOMPtr<nsIFile> mStorageBaseDir;
// 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;
};
nsresult ReadSalt(nsIFile* aPath, nsACString& aOutData);
bool MatchOrigin(nsIFile* aPath, const nsACString& aOrigin);
class GMPServiceParent final : public PGMPServiceParent
{
public:
explicit GMPServiceParent(GeckoMediaPluginServiceParent* aService)
: mService(aService)
{
}
virtual ~GMPServiceParent();
virtual bool RecvLoadGMP(const nsCString& aNodeId,
const nsCString& aApi,
nsTArray<nsCString>&& aTags,
nsTArray<ProcessId>&& aAlreadyBridgedTo,
base::ProcessId* aID,
nsCString* aDisplayName,
nsCString* aPluginId) override;
virtual bool RecvGetGMPNodeId(const nsString& aOrigin,
const nsString& aTopLevelOrigin,
const bool& aInPrivateBrowsing,
nsCString* aID) override;
static bool RecvGetGMPPluginVersionForAPI(const nsCString& aAPI,
nsTArray<nsCString>&& aTags,
bool* aHasPlugin,
nsCString* aVersion);
virtual void ActorDestroy(ActorDestroyReason aWhy) override;
static PGMPServiceParent* Create(Transport* aTransport, ProcessId aOtherPid);
private:
nsRefPtr<GeckoMediaPluginServiceParent> mService;
};
} // namespace gmp
} // namespace mozilla
#endif // GMPServiceParent_h_
+3 -3
View File
@@ -39,7 +39,7 @@ extern PRLogModuleInfo* GetGMPLog();
#ifdef __CLASS__
#undef __CLASS__
#endif
#define __CLASS__ "GMPParent"
#define __CLASS__ "GMPStorageParent"
namespace gmp {
@@ -52,7 +52,7 @@ GetGMPStorageDir(nsIFile** aTempDir, const nsCString& aNodeId)
return NS_ERROR_INVALID_ARG;
}
nsCOMPtr<mozIGeckoMediaPluginService> mps =
nsCOMPtr<mozIGeckoMediaPluginChromeService> mps =
do_GetService("@mozilla.org/gecko-media-plugin-service;1");
if (NS_WARN_IF(!mps)) {
return NS_ERROR_FAILURE;
@@ -468,7 +468,7 @@ GMPStorageParent::Init()
if (NS_WARN_IF(mNodeId.IsEmpty())) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<mozIGeckoMediaPluginService> mps =
nsCOMPtr<mozIGeckoMediaPluginChromeService> mps =
do_GetService("@mozilla.org/gecko-media-plugin-service;1");
if (NS_WARN_IF(!mps)) {
return NS_ERROR_FAILURE;
+2 -2
View File
@@ -5,7 +5,7 @@
#include "GMPVideoDecoderChild.h"
#include "GMPVideoi420FrameImpl.h"
#include "GMPChild.h"
#include "GMPContentChild.h"
#include <stdio.h>
#include "mozilla/unused.h"
#include "GMPVideoEncodedFrameImpl.h"
@@ -13,7 +13,7 @@
namespace mozilla {
namespace gmp {
GMPVideoDecoderChild::GMPVideoDecoderChild(GMPChild* aPlugin)
GMPVideoDecoderChild::GMPVideoDecoderChild(GMPContentChild* aPlugin)
: GMPSharedMemManager(aPlugin),
mPlugin(aPlugin),
mVideoDecoder(nullptr),
+3 -3
View File
@@ -16,14 +16,14 @@
namespace mozilla {
namespace gmp {
class GMPChild;
class GMPContentChild;
class GMPVideoDecoderChild : public PGMPVideoDecoderChild,
public GMPVideoDecoderCallback,
public GMPSharedMemManager
{
public:
explicit GMPVideoDecoderChild(GMPChild* aPlugin);
explicit GMPVideoDecoderChild(GMPContentChild* aPlugin);
virtual ~GMPVideoDecoderChild();
void Init(GMPVideoDecoder* aDecoder);
@@ -74,7 +74,7 @@ private:
virtual bool RecvDrain() override;
virtual bool RecvDecodingComplete() override;
GMPChild* mPlugin;
GMPContentChild* mPlugin;
GMPVideoDecoder* mVideoDecoder;
GMPVideoHostImpl mVideoHost;
};
+9 -2
View File
@@ -11,7 +11,7 @@
#include "GMPUtils.h"
#include "GMPVideoEncodedFrameImpl.h"
#include "GMPVideoi420FrameImpl.h"
#include "GMPParent.h"
#include "GMPContentParent.h"
#include "GMPMessageUtils.h"
#include "mozilla/gmp/GMPTypes.h"
@@ -43,7 +43,7 @@ namespace gmp {
// on Shutdown -> Dead
// Dead: mIsOpen == false
GMPVideoDecoderParent::GMPVideoDecoderParent(GMPParent* aPlugin)
GMPVideoDecoderParent::GMPVideoDecoderParent(GMPContentParent* aPlugin)
: GMPSharedMemManager(aPlugin)
, mIsOpen(false)
, mShuttingDown(false)
@@ -335,6 +335,13 @@ GMPVideoDecoderParent::RecvError(const GMPErr& aError)
return true;
}
bool
GMPVideoDecoderParent::RecvShutdown()
{
Shutdown();
return true;
}
bool
GMPVideoDecoderParent::RecvParentShmemForPool(Shmem&& aEncodedBuffer)
{
+4 -3
View File
@@ -18,7 +18,7 @@
namespace mozilla {
namespace gmp {
class GMPParent;
class GMPContentParent;
class GMPVideoDecoderParent final : public PGMPVideoDecoderParent
, public GMPVideoDecoderProxy
@@ -27,7 +27,7 @@ class GMPVideoDecoderParent final : public PGMPVideoDecoderParent
public:
NS_INLINE_DECL_REFCOUNTING(GMPVideoDecoderParent)
explicit GMPVideoDecoderParent(GMPParent *aPlugin);
explicit GMPVideoDecoderParent(GMPContentParent *aPlugin);
GMPVideoHostImpl& Host();
nsresult Shutdown();
@@ -73,6 +73,7 @@ private:
virtual bool RecvDrainComplete() override;
virtual bool RecvResetComplete() override;
virtual bool RecvError(const GMPErr& aError) override;
virtual bool RecvShutdown() override;
virtual bool RecvParentShmemForPool(Shmem&& aEncodedBuffer) override;
virtual bool AnswerNeedShmem(const uint32_t& aFrameBufferSize,
Shmem* aMem) override;
@@ -80,7 +81,7 @@ private:
bool mIsOpen;
bool mShuttingDown;
nsRefPtr<GMPParent> mPlugin;
nsRefPtr<GMPContentParent> mPlugin;
GMPVideoDecoderCallbackProxy* mCallback;
GMPVideoHostImpl mVideoHost;
};
+2 -2
View File
@@ -4,7 +4,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "GMPVideoEncoderChild.h"
#include "GMPChild.h"
#include "GMPContentChild.h"
#include <stdio.h>
#include "mozilla/unused.h"
#include "GMPVideoEncodedFrameImpl.h"
@@ -13,7 +13,7 @@
namespace mozilla {
namespace gmp {
GMPVideoEncoderChild::GMPVideoEncoderChild(GMPChild* aPlugin)
GMPVideoEncoderChild::GMPVideoEncoderChild(GMPContentChild* aPlugin)
: GMPSharedMemManager(aPlugin),
mPlugin(aPlugin),
mVideoEncoder(nullptr),
+3 -3
View File
@@ -15,14 +15,14 @@
namespace mozilla {
namespace gmp {
class GMPChild;
class GMPContentChild;
class GMPVideoEncoderChild : public PGMPVideoEncoderChild,
public GMPVideoEncoderCallback,
public GMPSharedMemManager
{
public:
explicit GMPVideoEncoderChild(GMPChild* aPlugin);
explicit GMPVideoEncoderChild(GMPContentChild* aPlugin);
virtual ~GMPVideoEncoderChild();
void Init(GMPVideoEncoder* aEncoder);
@@ -73,7 +73,7 @@ private:
virtual bool RecvSetPeriodicKeyFrames(const bool& aEnable) override;
virtual bool RecvEncodingComplete() override;
GMPChild* mPlugin;
GMPContentChild* mPlugin;
GMPVideoEncoder* mVideoEncoder;
GMPVideoHostImpl mVideoHost;
};

Some files were not shown because too many files have changed in this diff Show More