mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 05:37:11 +00:00
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:
+5
-4
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(){
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -80,6 +80,8 @@ protected:
|
||||
|
||||
static bool sPrefCameraParametersIsLowMemory;
|
||||
|
||||
static bool sPrefCameraParametersPermission;
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
static StaticRefPtr<CameraPreferences> sObserver;
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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,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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
@@ -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',
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -94,9 +94,6 @@ protected:
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIOutputStream> mOutputStream;
|
||||
#ifdef DEBUG
|
||||
void* mWriteThread;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -123,6 +123,7 @@ LOCAL_INCLUDES += [
|
||||
'/embedding/components/printingui/ipc',
|
||||
'/extensions/cookie',
|
||||
'/extensions/spellcheck/src',
|
||||
'/gfx/2d',
|
||||
'/hal/sandbox',
|
||||
'/layout/base',
|
||||
'/netwerk/base',
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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, ...)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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, ¶m);
|
||||
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,
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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__()
|
||||
{
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+40
-126
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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_
|
||||
@@ -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;
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user