mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1046245 - enumerateDevices w/non-blocking e10s, nsICryptoHMAC, clear cookies, lambdas. r=keeler, florian, billm, jesup
This commit is contained in:
parent
b85f19dba3
commit
ab8a60ff50
@ -199,6 +199,11 @@ Sanitizer.prototype = {
|
|||||||
cookieMgr.removeAll();
|
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.
|
// Clear plugin data.
|
||||||
const phInterface = Ci.nsIPluginHost;
|
const phInterface = Ci.nsIPluginHost;
|
||||||
const FLAG_CLEAR_ALL = phInterface.FLAG_CLEAR_ALL;
|
const FLAG_CLEAR_ALL = phInterface.FLAG_CLEAR_ALL;
|
||||||
|
@ -26,6 +26,9 @@
|
|||||||
#include "nsIIDNService.h"
|
#include "nsIIDNService.h"
|
||||||
#include "nsNetUtil.h"
|
#include "nsNetUtil.h"
|
||||||
#include "nsPrincipal.h"
|
#include "nsPrincipal.h"
|
||||||
|
#include "nsICryptoHash.h"
|
||||||
|
#include "nsICryptoHMAC.h"
|
||||||
|
#include "nsIKeyModule.h"
|
||||||
#include "nsAppDirectoryServiceDefs.h"
|
#include "nsAppDirectoryServiceDefs.h"
|
||||||
#include "nsIInputStream.h"
|
#include "nsIInputStream.h"
|
||||||
#include "nsILineInputStream.h"
|
#include "nsILineInputStream.h"
|
||||||
@ -37,8 +40,10 @@
|
|||||||
#include "mozilla/dom/MediaStreamTrackBinding.h"
|
#include "mozilla/dom/MediaStreamTrackBinding.h"
|
||||||
#include "mozilla/dom/GetUserMediaRequestBinding.h"
|
#include "mozilla/dom/GetUserMediaRequestBinding.h"
|
||||||
#include "mozilla/Preferences.h"
|
#include "mozilla/Preferences.h"
|
||||||
|
#include "mozilla/Base64.h"
|
||||||
|
#include "mozilla/media/MediaChild.h"
|
||||||
#include "MediaTrackConstraints.h"
|
#include "MediaTrackConstraints.h"
|
||||||
|
#include "VideoUtils.h"
|
||||||
#include "Latency.h"
|
#include "Latency.h"
|
||||||
|
|
||||||
// For PR_snprintf
|
// For PR_snprintf
|
||||||
@ -326,6 +331,50 @@ public:
|
|||||||
mOnFailure.swap(aOnFailure);
|
mOnFailure.swap(aOnFailure);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
NS_IMETHOD
|
||||||
Run()
|
Run()
|
||||||
{
|
{
|
||||||
@ -339,7 +388,7 @@ public:
|
|||||||
nsCOMPtr<nsIWritableVariant> devices =
|
nsCOMPtr<nsIWritableVariant> devices =
|
||||||
do_CreateInstance("@mozilla.org/variant;1");
|
do_CreateInstance("@mozilla.org/variant;1");
|
||||||
|
|
||||||
int32_t len = mDevices->Length();
|
size_t len = mDevices->Length();
|
||||||
if (len == 0) {
|
if (len == 0) {
|
||||||
// XXX
|
// XXX
|
||||||
// We should in the future return an empty array, and dynamically add
|
// We should in the future return an empty array, and dynamically add
|
||||||
@ -355,8 +404,14 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
nsTArray<nsIMediaDevice*> tmp(len);
|
nsTArray<nsIMediaDevice*> tmp(len);
|
||||||
for (int32_t i = 0; i < len; i++) {
|
for (auto& device : *mDevices) {
|
||||||
tmp.AppendElement(mDevices->ElementAt(i));
|
if (!mOriginKey.IsEmpty()) {
|
||||||
|
nsString id;
|
||||||
|
device->GetId(id);
|
||||||
|
AnonymizeId(id, mOriginKey);
|
||||||
|
device->SetId(id);
|
||||||
|
}
|
||||||
|
tmp.AppendElement(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
devices->SetAsArray(nsIDataType::VTYPE_INTERFACE,
|
devices->SetAsArray(nsIDataType::VTYPE_INTERFACE,
|
||||||
@ -370,6 +425,7 @@ public:
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsCString mOriginKey;
|
||||||
private:
|
private:
|
||||||
nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback> mOnSuccess;
|
nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback> mOnSuccess;
|
||||||
nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mOnFailure;
|
nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mOnFailure;
|
||||||
@ -1158,7 +1214,7 @@ public:
|
|||||||
void
|
void
|
||||||
Run()
|
Run()
|
||||||
{
|
{
|
||||||
NS_ASSERTION(!NS_IsMainThread(), "Don't call on main thread");
|
MOZ_ASSERT(!NS_IsMainThread());
|
||||||
MOZ_ASSERT(mOnSuccess);
|
MOZ_ASSERT(mOnSuccess);
|
||||||
MOZ_ASSERT(mOnFailure);
|
MOZ_ASSERT(mOnFailure);
|
||||||
|
|
||||||
@ -1362,13 +1418,22 @@ private:
|
|||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// A file in the profile dir is used to persist mOriginUuids used to anonymize
|
class SanitizeDeviceIdsTask : public Task
|
||||||
// deviceIds to be unique per origin, to avoid them being supercookies.
|
{
|
||||||
|
public:
|
||||||
|
explicit SanitizeDeviceIdsTask(int64_t aSinceWhen)
|
||||||
|
: mSinceWhen(aSinceWhen) {}
|
||||||
|
|
||||||
#define ORIGINUUIDS_FILE "enumerate_devices.txt"
|
void // NS_IMETHOD
|
||||||
#define ORIGINUUIDS_VERSION "1"
|
Run()
|
||||||
|
{
|
||||||
#define HMAC_LENGTH 20
|
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
|
* Similar to GetUserMediaTask, but used for the chrome-only
|
||||||
@ -1380,291 +1445,6 @@ private:
|
|||||||
*/
|
*/
|
||||||
class GetUserMediaDevicesTask : public Task
|
class GetUserMediaDevicesTask : public Task
|
||||||
{
|
{
|
||||||
class OriginUuidsLoader
|
|
||||||
{
|
|
||||||
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, HMAC_LENGTH);
|
|
||||||
if (status != SECSuccess) {
|
|
||||||
goto abort;
|
|
||||||
}
|
|
||||||
MOZ_ASSERT(hmac_len == HMAC_LENGTH);
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
OriginUuidsLoader()
|
|
||||||
: mUnsaved(false), mManager(MediaManager::GetInstance()) {}
|
|
||||||
|
|
||||||
nsresult
|
|
||||||
AnonymizeId(nsAString& aId, const nsACString& origin, bool aInPrivateBrowsing)
|
|
||||||
{
|
|
||||||
// The persistent deviceId would be a supercookie if we returned it. See
|
|
||||||
// http://w3c.github.io/mediacapture-main/getusermedia.html#attributes-8
|
|
||||||
//
|
|
||||||
// 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();
|
|
||||||
loaded = true;
|
|
||||||
}
|
|
||||||
OriginUuid* originUuid;
|
|
||||||
if (!mManager->mOriginUuids.Get(origin, &originUuid)) {
|
|
||||||
nsresult rv;
|
|
||||||
nsCOMPtr<nsIUUIDGenerator> uuidgen =
|
|
||||||
do_GetService("@mozilla.org/uuid-generator;1", &rv);
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
|
|
||||||
nsID nsid;
|
|
||||||
rv = uuidgen->GenerateUUIDInPlace(&nsid);
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
char uuid[NSID_LENGTH];
|
|
||||||
nsid.ToProvidedString(uuid);
|
|
||||||
|
|
||||||
originUuid = new OriginUuid(uuid, aInPrivateBrowsing);
|
|
||||||
mManager->mOriginUuids.Put(origin, originUuid);
|
|
||||||
mUnsaved = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned char mac[HMAC_LENGTH];
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
already_AddRefed<nsIFile>
|
|
||||||
GetFile()
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(mManager->mProfileDir);
|
|
||||||
nsCOMPtr<nsIFile> file;
|
|
||||||
nsresult rv = mManager->mProfileDir->Clone(getter_AddRefs(file));
|
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
file->Append(NS_LITERAL_STRING(ORIGINUUIDS_FILE));
|
|
||||||
return file.forget();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Format of file is (first line is version #):
|
|
||||||
//
|
|
||||||
// 1
|
|
||||||
// {54b1d3ad-18ad-0546-a551-80c1bf425057} http://fiddle.jshell.net
|
|
||||||
// {f9c2a045-53b4-0546-bdd0-b96f41850f8a} http://mozilla.github.io
|
|
||||||
// etc.
|
|
||||||
|
|
||||||
nsresult Read()
|
|
||||||
{
|
|
||||||
nsCOMPtr<nsIFile> file = GetFile();
|
|
||||||
if (NS_WARN_IF(!file)) {
|
|
||||||
return NS_ERROR_UNEXPECTED;
|
|
||||||
}
|
|
||||||
bool exists;
|
|
||||||
nsresult rv = file->Exists(&exists);
|
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
if (!exists) {
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsCOMPtr<nsIInputStream> stream;
|
|
||||||
rv = NS_NewLocalFileInputStream(getter_AddRefs(stream), file);
|
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
nsCOMPtr<nsILineInputStream> i = do_QueryInterface(stream);
|
|
||||||
MOZ_ASSERT(i);
|
|
||||||
|
|
||||||
nsCString line;
|
|
||||||
bool hasMoreLines;
|
|
||||||
rv = i->ReadLine(line, &hasMoreLines);
|
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
if (!line.EqualsLiteral(ORIGINUUIDS_VERSION)) {
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (hasMoreLines) {
|
|
||||||
rv = i->ReadLine(line, &hasMoreLines); \
|
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
int32_t f = line.FindChar(' ');
|
|
||||||
// Ignore any line that has no space, per format in the comment above.
|
|
||||||
if (f >= 0) {
|
|
||||||
const nsACString& uuid = Substring(line, 0, f);
|
|
||||||
const nsACString& origin = Substring(line, f+1);
|
|
||||||
mManager->mOriginUuids.Put(origin, new OriginUuid(uuid, false));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static PLDHashOperator
|
|
||||||
HashWriter(const nsACString& aOrigin, OriginUuid* aOriginUuid, void *aUserArg)
|
|
||||||
{
|
|
||||||
auto* stream = static_cast<nsIOutputStream *>(aUserArg);
|
|
||||||
|
|
||||||
if (!aOriginUuid->mPrivateBrowsing) {
|
|
||||||
nsCString buffer;
|
|
||||||
buffer.Append(aOriginUuid->mUuid);
|
|
||||||
buffer.Append(' ');
|
|
||||||
buffer.Append(aOrigin);
|
|
||||||
buffer.Append('\n');
|
|
||||||
|
|
||||||
uint32_t count;
|
|
||||||
nsresult rv = stream->Write(buffer.Data(), buffer.Length(), &count);
|
|
||||||
if (NS_WARN_IF(NS_FAILED(rv)) || count != buffer.Length()) {
|
|
||||||
return PL_DHASH_STOP;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return PL_DHASH_NEXT;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult
|
|
||||||
Write()
|
|
||||||
{
|
|
||||||
nsCOMPtr<nsIFile> file = GetFile();
|
|
||||||
if (NS_WARN_IF(!file)) {
|
|
||||||
return NS_ERROR_UNEXPECTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsCOMPtr<nsIOutputStream> stream;
|
|
||||||
nsresult rv = NS_NewSafeLocalFileOutputStream(getter_AddRefs(stream), file);
|
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
nsAutoCString buffer;
|
|
||||||
buffer.AppendLiteral(ORIGINUUIDS_VERSION);
|
|
||||||
buffer.Append('\n');
|
|
||||||
|
|
||||||
uint32_t count;
|
|
||||||
rv = stream->Write(buffer.Data(), buffer.Length(), &count);
|
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
if (count != buffer.Length()) {
|
|
||||||
return NS_ERROR_UNEXPECTED;
|
|
||||||
}
|
|
||||||
mManager->mOriginUuids.EnumerateRead(HashWriter, stream.get());
|
|
||||||
|
|
||||||
nsCOMPtr<nsISafeOutputStream> safeStream = do_QueryInterface(stream);
|
|
||||||
MOZ_ASSERT(safeStream);
|
|
||||||
|
|
||||||
rv = safeStream->Finish();
|
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult Load()
|
|
||||||
{
|
|
||||||
nsresult rv = Read();
|
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
||||||
Delete();
|
|
||||||
}
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult Save()
|
|
||||||
{
|
|
||||||
nsresult rv = Write();
|
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
NS_WARNING("Failed to write data for EnumerateDevices id-persistence.");
|
|
||||||
Delete();
|
|
||||||
}
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult Delete()
|
|
||||||
{
|
|
||||||
nsCOMPtr<nsIFile> file = GetFile();
|
|
||||||
if (NS_WARN_IF(!file)) {
|
|
||||||
return NS_ERROR_UNEXPECTED;
|
|
||||||
}
|
|
||||||
nsresult rv = file->Remove(false);
|
|
||||||
if (rv == NS_ERROR_FILE_NOT_FOUND) {
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool mUnsaved;
|
|
||||||
private:
|
|
||||||
nsRefPtr<MediaManager> mManager;
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GetUserMediaDevicesTask(
|
GetUserMediaDevicesTask(
|
||||||
const MediaStreamConstraints& aConstraints,
|
const MediaStreamConstraints& aConstraints,
|
||||||
@ -1688,7 +1468,7 @@ public:
|
|||||||
void // NS_IMETHOD
|
void // NS_IMETHOD
|
||||||
Run()
|
Run()
|
||||||
{
|
{
|
||||||
NS_ASSERTION(!NS_IsMainThread(), "Don't call on main thread");
|
MOZ_ASSERT(!NS_IsMainThread());
|
||||||
|
|
||||||
nsRefPtr<MediaEngine> backend;
|
nsRefPtr<MediaEngine> backend;
|
||||||
if (mConstraints.mFake || mUseFakeDevices)
|
if (mConstraints.mFake || mUseFakeDevices)
|
||||||
@ -1717,39 +1497,26 @@ public:
|
|||||||
result->AppendElement(source);
|
result->AppendElement(source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
nsRefPtr<DeviceSuccessCallbackRunnable> runnable
|
||||||
nsresult rv = NS_OK;
|
(new DeviceSuccessCallbackRunnable(mWindowId, mOnSuccess, mOnFailure,
|
||||||
if (!mPrivileged) {
|
result.forget()));
|
||||||
OriginUuidsLoader loader;
|
if (mPrivileged) {
|
||||||
for (auto& source : *result) {
|
NS_DispatchToMainThread(runnable);
|
||||||
nsString id;
|
|
||||||
source->GetId(id);
|
|
||||||
rv = loader.AnonymizeId(id, mOrigin, mInPrivateBrowsing);
|
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
source->SetId(id);
|
|
||||||
}
|
|
||||||
if (loader.mUnsaved) {
|
|
||||||
loader.Save();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (NS_SUCCEEDED(rv)) {
|
|
||||||
NS_DispatchToMainThread(new DeviceSuccessCallbackRunnable(mWindowId,
|
|
||||||
mOnSuccess,
|
|
||||||
mOnFailure,
|
|
||||||
result.forget()));
|
|
||||||
} else {
|
} else {
|
||||||
nsRefPtr<MediaMgrError> error = new
|
// Get persistent origin-unique uuid to anonymize deviceIds back on main.
|
||||||
MediaMgrError(NS_LITERAL_STRING("InternalError"),
|
//
|
||||||
NS_LITERAL_STRING("Unexpected error"));
|
// GetOriginKey is an async API that returns a pledge (as promise-like
|
||||||
NS_DispatchToMainThread(
|
// pattern). We use .Then() to pass in a lambda to run back on this
|
||||||
new ErrorCallbackRunnable<nsIGetUserMediaDevicesSuccessCallback>(mOnSuccess,
|
// thread once GetOriginKey resolves asynchronously . The "runnable"
|
||||||
mOnFailure,
|
// nsRefPtr is "captured" (passed by value) into the lambda.
|
||||||
*error,
|
nsRefPtr<media::ChildPledge<nsCString>> p =
|
||||||
mWindowId));
|
media::GetOriginKey(mOrigin, mInPrivateBrowsing);
|
||||||
|
p->Then([runnable](nsCString result) mutable {
|
||||||
|
runnable->mOriginKey = result;
|
||||||
|
NS_DispatchToMainThread(runnable);
|
||||||
|
}, [](nsresult rv){});
|
||||||
}
|
}
|
||||||
// DeviceSuccessCallbackRunnable should have taken these.
|
// One of the Runnables have taken these.
|
||||||
MOZ_ASSERT(!mOnSuccess && !mOnFailure);
|
MOZ_ASSERT(!mOnSuccess && !mOnFailure);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1796,6 +1563,16 @@ NS_IMPL_ISUPPORTS(MediaManager, nsIMediaManagerService, nsIObserver)
|
|||||||
|
|
||||||
/* static */ StaticRefPtr<MediaManager> MediaManager::sSingleton;
|
/* 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
|
// NOTE: never Dispatch(....,NS_DISPATCH_SYNC) to the MediaManager
|
||||||
// thread from the MainThread, as we NS_DISPATCH_SYNC to MainThread
|
// thread from the MainThread, as we NS_DISPATCH_SYNC to MainThread
|
||||||
// from MediaManager thread.
|
// from MediaManager thread.
|
||||||
@ -2223,12 +2000,6 @@ MediaManager::EnumerateDevices(nsPIDOMWindow* aWindow,
|
|||||||
{
|
{
|
||||||
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
|
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
|
||||||
|
|
||||||
if (!mProfileDir) {
|
|
||||||
nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
|
|
||||||
getter_AddRefs(mProfileDir));
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
}
|
|
||||||
|
|
||||||
MediaStreamConstraints c;
|
MediaStreamConstraints c;
|
||||||
c.mVideo.SetAsBoolean() = true;
|
c.mVideo.SetAsBoolean() = true;
|
||||||
c.mAudio.SetAsBoolean() = true;
|
c.mAudio.SetAsBoolean() = true;
|
||||||
@ -2684,6 +2455,17 @@ MediaManager::MediaCaptureWindowState(nsIDOMWindow* aWindow, bool* aVideo,
|
|||||||
return NS_OK;
|
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
|
static void
|
||||||
StopScreensharingCallback(MediaManager *aThis,
|
StopScreensharingCallback(MediaManager *aThis,
|
||||||
uint64_t aWindowID,
|
uint64_t aWindowID,
|
||||||
|
@ -458,20 +458,6 @@ private:
|
|||||||
nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mOnFailure;
|
nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mOnFailure;
|
||||||
};
|
};
|
||||||
|
|
||||||
class OriginUuid
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
OriginUuid(char *aUuid, bool aPrivateBrowsing)
|
|
||||||
: mPrivateBrowsing(aPrivateBrowsing) {
|
|
||||||
mUuid.Append(aUuid);
|
|
||||||
}
|
|
||||||
OriginUuid(const nsACString& aUuid, bool aPrivateBrowsing)
|
|
||||||
: mUuid(aUuid), mPrivateBrowsing(aPrivateBrowsing) {}
|
|
||||||
|
|
||||||
nsCString mUuid;
|
|
||||||
bool mPrivateBrowsing;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef nsTArray<nsRefPtr<GetUserMediaCallbackMediaStreamListener> > StreamListeners;
|
typedef nsTArray<nsRefPtr<GetUserMediaCallbackMediaStreamListener> > StreamListeners;
|
||||||
typedef nsClassHashtable<nsUint64HashKey, StreamListeners> WindowTable;
|
typedef nsClassHashtable<nsUint64HashKey, StreamListeners> WindowTable;
|
||||||
|
|
||||||
@ -523,13 +509,9 @@ typedef void (*WindowListenerCallback)(MediaManager *aThis,
|
|||||||
StreamListeners *aListeners,
|
StreamListeners *aListeners,
|
||||||
void *aData);
|
void *aData);
|
||||||
|
|
||||||
class GetUserMediaDevicesTask;
|
|
||||||
|
|
||||||
class MediaManager final : public nsIMediaManagerService,
|
class MediaManager final : public nsIMediaManagerService,
|
||||||
public nsIObserver
|
public nsIObserver
|
||||||
{
|
{
|
||||||
friend GetUserMediaDevicesTask;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static already_AddRefed<MediaManager> GetInstance();
|
static already_AddRefed<MediaManager> GetInstance();
|
||||||
|
|
||||||
@ -539,6 +521,9 @@ public:
|
|||||||
static MediaManager* Get();
|
static MediaManager* Get();
|
||||||
static MediaManager* GetIfExists();
|
static MediaManager* GetIfExists();
|
||||||
static MessageLoop* GetMessageLoop();
|
static MessageLoop* GetMessageLoop();
|
||||||
|
#ifdef DEBUG
|
||||||
|
static bool IsInMediaThread();
|
||||||
|
#endif
|
||||||
|
|
||||||
static bool Exists()
|
static bool Exists()
|
||||||
{
|
{
|
||||||
@ -616,10 +601,6 @@ private:
|
|||||||
|
|
||||||
void StopMediaStreams();
|
void StopMediaStreams();
|
||||||
|
|
||||||
// ONLY access from MediaManagerThread so we don't need to lock
|
|
||||||
nsClassHashtable<nsCStringHashKey, OriginUuid> mOriginUuids;
|
|
||||||
nsCOMPtr<nsIFile> mProfileDir;
|
|
||||||
|
|
||||||
// ONLY access from MainThread so we don't need to lock
|
// ONLY access from MainThread so we don't need to lock
|
||||||
WindowTable mActiveWindows;
|
WindowTable mActiveWindows;
|
||||||
nsClassHashtable<nsStringHashKey, GetUserMediaTask> mActiveCallbacks;
|
nsClassHashtable<nsStringHashKey, GetUserMediaTask> mActiveCallbacks;
|
||||||
|
@ -261,18 +261,16 @@ ExtractH264CodecDetails(const nsAString& aCodec,
|
|||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
GenerateRandomPathName(nsCString& aOutSalt, uint32_t aLength)
|
GenerateRandomName(nsCString& aOutSalt, uint32_t aLength)
|
||||||
{
|
{
|
||||||
nsresult rv;
|
nsresult rv;
|
||||||
nsCOMPtr<nsIRandomGenerator> rg =
|
nsCOMPtr<nsIRandomGenerator> rg =
|
||||||
do_GetService("@mozilla.org/security/random-generator;1", &rv);
|
do_GetService("@mozilla.org/security/random-generator;1", &rv);
|
||||||
if (NS_FAILED(rv)) return rv;
|
if (NS_FAILED(rv)) return rv;
|
||||||
|
|
||||||
// For each three bytes of random data we will get four bytes of
|
// For each three bytes of random data we will get four bytes of ASCII.
|
||||||
// ASCII. Request a bit more to be safe and truncate to the length
|
|
||||||
// we want at the end.
|
|
||||||
const uint32_t requiredBytesLength =
|
const uint32_t requiredBytesLength =
|
||||||
static_cast<uint32_t>((aLength + 1) / 4 * 3);
|
static_cast<uint32_t>((aLength + 3) / 4 * 3);
|
||||||
|
|
||||||
uint8_t* buffer;
|
uint8_t* buffer;
|
||||||
rv = rg->GenerateRandomBytes(requiredBytesLength, &buffer);
|
rv = rg->GenerateRandomBytes(requiredBytesLength, &buffer);
|
||||||
@ -286,14 +284,19 @@ GenerateRandomPathName(nsCString& aOutSalt, uint32_t aLength)
|
|||||||
buffer = nullptr;
|
buffer = nullptr;
|
||||||
if (NS_FAILED (rv)) return rv;
|
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
|
// Base64 characters are alphanumeric (a-zA-Z0-9) and '+' and '/', so we need
|
||||||
// to replace illegal characters -- notably '/'
|
// to replace illegal characters -- notably '/'
|
||||||
temp.ReplaceChar(FILE_PATH_SEPARATOR FILE_ILLEGAL_CHARACTERS, '_');
|
aOutSalt.ReplaceChar(FILE_PATH_SEPARATOR FILE_ILLEGAL_CHARACTERS, '_');
|
||||||
|
|
||||||
aOutSalt = temp;
|
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -261,7 +261,11 @@ ExtractH264CodecDetails(const nsAString& aCodecs,
|
|||||||
int16_t& aLevel);
|
int16_t& aLevel);
|
||||||
|
|
||||||
// Use a cryptographic quality PRNG to generate raw random bytes
|
// 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.
|
// path. This is based on code from nsExternalAppHandler::SetUpTempFile.
|
||||||
nsresult
|
nsresult
|
||||||
GenerateRandomPathName(nsCString& aOutSalt, uint32_t aLength);
|
GenerateRandomPathName(nsCString& aOutSalt, uint32_t aLength);
|
||||||
|
@ -12,7 +12,7 @@ interface nsIDOMWindow;
|
|||||||
#define MEDIAMANAGERSERVICE_CONTRACTID "@mozilla.org/mediaManagerService;1"
|
#define MEDIAMANAGERSERVICE_CONTRACTID "@mozilla.org/mediaManagerService;1"
|
||||||
%}
|
%}
|
||||||
|
|
||||||
[scriptable, builtinclass, uuid(9b10661f-77b3-47f7-a8de-ee58daaff5d2)]
|
[scriptable, builtinclass, uuid(24b23e01-33fd-401f-ba25-6e52658750b0)]
|
||||||
interface nsIMediaManagerService : nsISupports
|
interface nsIMediaManagerService : nsISupports
|
||||||
{
|
{
|
||||||
/* return a array of inner windows that have active captures */
|
/* return a array of inner windows that have active captures */
|
||||||
@ -22,4 +22,8 @@ interface nsIMediaManagerService : nsISupports
|
|||||||
void mediaCaptureWindowState(in nsIDOMWindow aWindow, out boolean aVideo, out boolean aAudio,
|
void mediaCaptureWindowState(in nsIDOMWindow aWindow, out boolean aVideo, out boolean aAudio,
|
||||||
[optional] out boolean aScreenShare, [optional] out boolean aWindowShare,
|
[optional] out boolean aScreenShare, [optional] out boolean aWindowShare,
|
||||||
[optional] out boolean aAppShare, [optional] out boolean aBrowserShare);
|
[optional] out boolean aAppShare, [optional] out boolean aBrowserShare);
|
||||||
|
|
||||||
|
/* Clear per-orgin list of persistent DeviceIds stored for enumerateDevices
|
||||||
|
sinceTime is milliseconds since 1 January 1970 00:00:00 UTC. 0 = clear all */
|
||||||
|
void sanitizeDeviceIds(in long long sinceWhen);
|
||||||
};
|
};
|
||||||
|
134
dom/media/systemservices/MediaChild.cpp
Normal file
134
dom/media/systemservices/MediaChild.cpp
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set sw=2 ts=8 et ft=cpp : */
|
||||||
|
/* 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 "MediaChild.h"
|
||||||
|
|
||||||
|
#include "mozilla/ipc/BackgroundChild.h"
|
||||||
|
#include "mozilla/ipc/PBackgroundChild.h"
|
||||||
|
#include "nsGlobalWindow.h"
|
||||||
|
#include "mozilla/MediaManager.h"
|
||||||
|
#include "prlog.h"
|
||||||
|
|
||||||
|
#undef LOG
|
||||||
|
#if defined(PR_LOGGING)
|
||||||
|
PRLogModuleInfo *gMediaChildLog;
|
||||||
|
#define LOG(args) PR_LOG(gMediaChildLog, PR_LOG_DEBUG, args)
|
||||||
|
#else
|
||||||
|
#define LOG(args)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace media {
|
||||||
|
|
||||||
|
static PMediaChild* sChild = nullptr;
|
||||||
|
|
||||||
|
template<typename ValueType>
|
||||||
|
ChildPledge<ValueType>::ChildPledge()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(MediaManager::IsInMediaThread());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename ValueType> void
|
||||||
|
ChildPledge<ValueType>::ActorCreated(PBackgroundChild* aActor)
|
||||||
|
{
|
||||||
|
if (!sChild) {
|
||||||
|
// Create PMedia by sending a message to the parent
|
||||||
|
sChild = aActor->SendPMediaConstructor();
|
||||||
|
}
|
||||||
|
Run(static_cast<Child*>(sChild));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename ValueType> void
|
||||||
|
ChildPledge<ValueType>::ActorFailed()
|
||||||
|
{
|
||||||
|
Pledge<ValueType>::Reject(NS_ERROR_UNEXPECTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename ValueType> NS_IMPL_ADDREF(ChildPledge<ValueType>)
|
||||||
|
template<typename ValueType> NS_IMPL_RELEASE(ChildPledge<ValueType>)
|
||||||
|
template<typename ValueType> NS_INTERFACE_MAP_BEGIN(ChildPledge<ValueType>)
|
||||||
|
NS_INTERFACE_MAP_ENTRY(nsIIPCBackgroundChildCreateCallback)
|
||||||
|
NS_INTERFACE_MAP_END
|
||||||
|
|
||||||
|
already_AddRefed<ChildPledge<nsCString>>
|
||||||
|
GetOriginKey(const nsCString& aOrigin, bool aPrivateBrowsing)
|
||||||
|
{
|
||||||
|
class Pledge : public ChildPledge<nsCString>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit Pledge(const nsCString& aOrigin, bool aPrivateBrowsing)
|
||||||
|
: mOrigin(aOrigin), mPrivateBrowsing(aPrivateBrowsing) {}
|
||||||
|
private:
|
||||||
|
~Pledge() {}
|
||||||
|
void Run(PMediaChild* aMedia)
|
||||||
|
{
|
||||||
|
aMedia->SendGetOriginKey(mOrigin, mPrivateBrowsing, &mValue);
|
||||||
|
LOG(("GetOriginKey for %s, result:", mOrigin.get(), mValue.get()));
|
||||||
|
Resolve();
|
||||||
|
}
|
||||||
|
const nsCString mOrigin;
|
||||||
|
const bool mPrivateBrowsing;
|
||||||
|
};
|
||||||
|
|
||||||
|
nsRefPtr<ChildPledge<nsCString>> p = new Pledge(aOrigin, aPrivateBrowsing);
|
||||||
|
nsCOMPtr<nsIIPCBackgroundChildCreateCallback> cb = do_QueryObject(p);
|
||||||
|
bool ok = ipc::BackgroundChild::GetOrCreateForCurrentThread(cb);
|
||||||
|
MOZ_RELEASE_ASSERT(ok);
|
||||||
|
return p.forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
already_AddRefed<ChildPledge<bool>>
|
||||||
|
SanitizeOriginKeys(const uint64_t& aSinceWhen)
|
||||||
|
{
|
||||||
|
class Pledge : public ChildPledge<bool>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit Pledge(const uint64_t& aSinceWhen) : mSinceWhen(aSinceWhen) {}
|
||||||
|
private:
|
||||||
|
void Run(PMediaChild* aMedia)
|
||||||
|
{
|
||||||
|
aMedia->SendSanitizeOriginKeys(mSinceWhen);
|
||||||
|
mValue = true;
|
||||||
|
LOG(("SanitizeOriginKeys since %llu", mSinceWhen));
|
||||||
|
Resolve();
|
||||||
|
}
|
||||||
|
const uint64_t mSinceWhen;
|
||||||
|
};
|
||||||
|
|
||||||
|
nsRefPtr<ChildPledge<bool>> p = new Pledge(aSinceWhen);
|
||||||
|
nsCOMPtr<nsIIPCBackgroundChildCreateCallback> cb = do_QueryObject(p);
|
||||||
|
bool ok = ipc::BackgroundChild::GetOrCreateForCurrentThread(cb);
|
||||||
|
MOZ_RELEASE_ASSERT(ok);
|
||||||
|
return p.forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
Child::Child()
|
||||||
|
{
|
||||||
|
#if defined(PR_LOGGING)
|
||||||
|
if (!gMediaChildLog) {
|
||||||
|
gMediaChildLog = PR_NewLogModule("MediaChild");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
LOG(("media::Child: %p", this));
|
||||||
|
MOZ_COUNT_CTOR(Child);
|
||||||
|
}
|
||||||
|
|
||||||
|
Child::~Child()
|
||||||
|
{
|
||||||
|
LOG(("~media::Child: %p", this));
|
||||||
|
sChild = nullptr;
|
||||||
|
MOZ_COUNT_DTOR(Child);
|
||||||
|
}
|
||||||
|
|
||||||
|
PMediaChild*
|
||||||
|
CreateMediaChild()
|
||||||
|
{
|
||||||
|
return new Child();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
59
dom/media/systemservices/MediaChild.h
Normal file
59
dom/media/systemservices/MediaChild.h
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set sw=2 ts=8 et ft=cpp : */
|
||||||
|
/* 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 mozilla_MediaChild_h
|
||||||
|
#define mozilla_MediaChild_h
|
||||||
|
|
||||||
|
#include "mozilla/dom/ContentChild.h"
|
||||||
|
#include "mozilla/media/PMediaChild.h"
|
||||||
|
#include "mozilla/media/PMediaParent.h"
|
||||||
|
#include "nsIIPCBackgroundChildCreateCallback.h"
|
||||||
|
#include "MediaUtils.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace media {
|
||||||
|
|
||||||
|
// media::Child implements proxying to the chrome process for some media-related
|
||||||
|
// functions, for the moment just:
|
||||||
|
//
|
||||||
|
// GetOriginKey() - get a cookie-like persisted unique key for a given origin.
|
||||||
|
// SanitizeOriginKeys() - reset persisted unique keys.
|
||||||
|
|
||||||
|
// GetOriginKey and SanitizeOriginKeys are asynchronous APIs that return pledges
|
||||||
|
// (promise-like objects) with the future value. Use pledge.Then(func) to access.
|
||||||
|
|
||||||
|
template<typename ValueType>
|
||||||
|
class ChildPledge : public Pledge<ValueType>,
|
||||||
|
public nsIIPCBackgroundChildCreateCallback
|
||||||
|
{
|
||||||
|
NS_DECL_NSIIPCBACKGROUNDCHILDCREATECALLBACK
|
||||||
|
NS_DECL_ISUPPORTS
|
||||||
|
public:
|
||||||
|
explicit ChildPledge();
|
||||||
|
protected:
|
||||||
|
virtual ~ChildPledge() {}
|
||||||
|
virtual void Run(PMediaChild* aMedia) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
already_AddRefed<ChildPledge<nsCString>>
|
||||||
|
GetOriginKey(const nsCString& aOrigin, bool aPrivateBrowsing);
|
||||||
|
|
||||||
|
already_AddRefed<ChildPledge<bool>>
|
||||||
|
SanitizeOriginKeys(const uint64_t& aSinceWhen);
|
||||||
|
|
||||||
|
class Child : public PMediaChild
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Child();
|
||||||
|
virtual ~Child();
|
||||||
|
};
|
||||||
|
|
||||||
|
PMediaChild* CreateMediaChild();
|
||||||
|
|
||||||
|
} // namespace media
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
#endif // mozilla_MediaChild_h
|
400
dom/media/systemservices/MediaParent.cpp
Normal file
400
dom/media/systemservices/MediaParent.cpp
Normal file
@ -0,0 +1,400 @@
|
|||||||
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set sw=2 ts=8 et ft=cpp : */
|
||||||
|
/* 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 "MediaParent.h"
|
||||||
|
|
||||||
|
#include "mozilla/Base64.h"
|
||||||
|
|
||||||
|
#include "MediaUtils.h"
|
||||||
|
#include "MediaEngine.h"
|
||||||
|
#include "VideoUtils.h"
|
||||||
|
#include "nsThreadUtils.h"
|
||||||
|
#include "nsNetUtil.h"
|
||||||
|
#include "nsILineInputStream.h"
|
||||||
|
#include "nsAppDirectoryServiceDefs.h"
|
||||||
|
#include "nsISupportsImpl.h"
|
||||||
|
#include "prlog.h"
|
||||||
|
|
||||||
|
#undef LOG
|
||||||
|
#if defined(PR_LOGGING)
|
||||||
|
PRLogModuleInfo *gMediaParentLog;
|
||||||
|
#define LOG(args) PR_LOG(gMediaParentLog, PR_LOG_DEBUG, args)
|
||||||
|
#else
|
||||||
|
#define LOG(args)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// A file in the profile dir is used to persist mOriginKeys used to anonymize
|
||||||
|
// deviceIds to be unique per origin, to avoid them being supercookies.
|
||||||
|
|
||||||
|
#define ORIGINKEYS_FILE "enumerate_devices.txt"
|
||||||
|
#define ORIGINKEYS_VERSION "1"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace media {
|
||||||
|
|
||||||
|
static ParentSingleton* sParentSingleton = nullptr;
|
||||||
|
|
||||||
|
class ParentSingleton : public nsISupports
|
||||||
|
{
|
||||||
|
NS_DECL_ISUPPORTS
|
||||||
|
|
||||||
|
class OriginKey
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static const size_t DecodedLength = 18;
|
||||||
|
|
||||||
|
OriginKey(const nsACString& aKey, int64_t aSecondsStamp)
|
||||||
|
: mKey(aKey)
|
||||||
|
, mSecondsStamp(aSecondsStamp) {}
|
||||||
|
|
||||||
|
nsCString mKey; // Base64 encoded.
|
||||||
|
int64_t mSecondsStamp;
|
||||||
|
};
|
||||||
|
|
||||||
|
class OriginKeysTable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
OriginKeysTable() {}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
GetOriginKey(const nsACString& aOrigin, nsCString& result)
|
||||||
|
{
|
||||||
|
OriginKey* key;
|
||||||
|
if (!mKeys.Get(aOrigin, &key)) {
|
||||||
|
nsCString salt; // Make a new one
|
||||||
|
nsresult rv = GenerateRandomName(salt, key->DecodedLength * 4 / 3);
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
key = new OriginKey(salt, PR_Now() / PR_USEC_PER_SEC);
|
||||||
|
mKeys.Put(aOrigin, key);
|
||||||
|
}
|
||||||
|
result = key->mKey;
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PLDHashOperator
|
||||||
|
HashCleaner(const nsACString& aOrigin, nsAutoPtr<OriginKey>& aOriginKey,
|
||||||
|
void *aUserArg)
|
||||||
|
{
|
||||||
|
OriginKey* since = static_cast<OriginKey*>(aUserArg);
|
||||||
|
|
||||||
|
LOG((((aOriginKey->mSecondsStamp >= since->mSecondsStamp)?
|
||||||
|
"%s: REMOVE %lld >= %lld" :
|
||||||
|
"%s: KEEP %lld < %lld"),
|
||||||
|
__FUNCTION__, aOriginKey->mSecondsStamp, since->mSecondsStamp));
|
||||||
|
|
||||||
|
return (aOriginKey->mSecondsStamp >= since->mSecondsStamp)?
|
||||||
|
PL_DHASH_REMOVE : PL_DHASH_NEXT;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clear(int64_t aSinceWhen)
|
||||||
|
{
|
||||||
|
// Avoid int64_t* <-> void* casting offset
|
||||||
|
OriginKey since(nsCString(), aSinceWhen / PR_USEC_PER_SEC);
|
||||||
|
mKeys.Enumerate(HashCleaner, &since);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
nsClassHashtable<nsCStringHashKey, OriginKey> mKeys;
|
||||||
|
};
|
||||||
|
|
||||||
|
class OriginKeysLoader : public OriginKeysTable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
OriginKeysLoader()
|
||||||
|
{
|
||||||
|
Load();
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
GetOriginKey(const nsACString& aOrigin, nsCString& result)
|
||||||
|
{
|
||||||
|
auto before = mKeys.Count();
|
||||||
|
OriginKeysTable::GetOriginKey(aOrigin, result);
|
||||||
|
if (mKeys.Count() != before) {
|
||||||
|
Save();
|
||||||
|
}
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
already_AddRefed<nsIFile>
|
||||||
|
GetFile()
|
||||||
|
{
|
||||||
|
if (!mProfileDir) {
|
||||||
|
nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
|
||||||
|
getter_AddRefs(mProfileDir));
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nsCOMPtr<nsIFile> file;
|
||||||
|
nsresult rv = mProfileDir->Clone(getter_AddRefs(file));
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
file->Append(NS_LITERAL_STRING(ORIGINKEYS_FILE));
|
||||||
|
return file.forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format of file is key secondsstamp origin (first line is version #):
|
||||||
|
//
|
||||||
|
// 1
|
||||||
|
// rOMAAbFujNwKyIpj4RJ3Wt5Q 1424733961 http://fiddle.jshell.net
|
||||||
|
// rOMAAbFujNwKyIpj4RJ3Wt5Q 1424734841 http://mozilla.github.io
|
||||||
|
// etc.
|
||||||
|
|
||||||
|
nsresult Read()
|
||||||
|
{
|
||||||
|
nsCOMPtr<nsIFile> file = GetFile();
|
||||||
|
if (NS_WARN_IF(!file)) {
|
||||||
|
return NS_ERROR_UNEXPECTED;
|
||||||
|
}
|
||||||
|
bool exists;
|
||||||
|
nsresult rv = file->Exists(&exists);
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
if (!exists) {
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIInputStream> stream;
|
||||||
|
rv = NS_NewLocalFileInputStream(getter_AddRefs(stream), file);
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
nsCOMPtr<nsILineInputStream> i = do_QueryInterface(stream);
|
||||||
|
MOZ_ASSERT(i);
|
||||||
|
|
||||||
|
nsCString line;
|
||||||
|
bool hasMoreLines;
|
||||||
|
rv = i->ReadLine(line, &hasMoreLines);
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
if (!line.EqualsLiteral(ORIGINKEYS_VERSION)) {
|
||||||
|
// If version on disk is newer than we can understand then ignore it.
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (hasMoreLines) {
|
||||||
|
rv = i->ReadLine(line, &hasMoreLines);
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
// Read key secondsstamp origin.
|
||||||
|
// Ignore any lines that don't fit format in the comment above exactly.
|
||||||
|
int32_t f = line.FindChar(' ');
|
||||||
|
if (f < 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const nsACString& key = Substring(line, 0, f);
|
||||||
|
const nsACString& s = Substring(line, f+1);
|
||||||
|
f = s.FindChar(' ');
|
||||||
|
if (f < 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int64_t secondsstamp = nsCString(Substring(s, 0, f)).ToInteger64(&rv);
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const nsACString& origin = Substring(s, f+1);
|
||||||
|
|
||||||
|
// Validate key
|
||||||
|
if (key.Length() != OriginKey::DecodedLength) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
nsCString dummy;
|
||||||
|
rv = Base64Decode(key, dummy);
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
mKeys.Put(origin, new OriginKey(key, secondsstamp));
|
||||||
|
}
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PLDHashOperator
|
||||||
|
HashWriter(const nsACString& aOrigin, OriginKey* aOriginKey, void *aUserArg)
|
||||||
|
{
|
||||||
|
auto* stream = static_cast<nsIOutputStream *>(aUserArg);
|
||||||
|
|
||||||
|
nsCString buffer;
|
||||||
|
buffer.Append(aOriginKey->mKey);
|
||||||
|
buffer.Append(' ');
|
||||||
|
buffer.AppendInt(aOriginKey->mSecondsStamp);
|
||||||
|
buffer.Append(' ');
|
||||||
|
buffer.Append(aOrigin);
|
||||||
|
buffer.Append('\n');
|
||||||
|
|
||||||
|
uint32_t count;
|
||||||
|
nsresult rv = stream->Write(buffer.Data(), buffer.Length(), &count);
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv)) || count != buffer.Length()) {
|
||||||
|
return PL_DHASH_STOP;
|
||||||
|
}
|
||||||
|
return PL_DHASH_NEXT;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
Write()
|
||||||
|
{
|
||||||
|
nsCOMPtr<nsIFile> file = GetFile();
|
||||||
|
if (NS_WARN_IF(!file)) {
|
||||||
|
return NS_ERROR_UNEXPECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIOutputStream> stream;
|
||||||
|
nsresult rv = NS_NewSafeLocalFileOutputStream(getter_AddRefs(stream), file);
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
nsAutoCString buffer;
|
||||||
|
buffer.AppendLiteral(ORIGINKEYS_VERSION);
|
||||||
|
buffer.Append('\n');
|
||||||
|
|
||||||
|
uint32_t count;
|
||||||
|
rv = stream->Write(buffer.Data(), buffer.Length(), &count);
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
if (count != buffer.Length()) {
|
||||||
|
return NS_ERROR_UNEXPECTED;
|
||||||
|
}
|
||||||
|
mKeys.EnumerateRead(HashWriter, stream.get());
|
||||||
|
|
||||||
|
nsCOMPtr<nsISafeOutputStream> safeStream = do_QueryInterface(stream);
|
||||||
|
MOZ_ASSERT(safeStream);
|
||||||
|
|
||||||
|
rv = safeStream->Finish();
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult Load()
|
||||||
|
{
|
||||||
|
nsresult rv = Read();
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
Delete();
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult Save()
|
||||||
|
{
|
||||||
|
nsresult rv = Write();
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
NS_WARNING("Failed to write data for EnumerateDevices id-persistence.");
|
||||||
|
Delete();
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clear(int64_t aSinceWhen)
|
||||||
|
{
|
||||||
|
OriginKeysTable::Clear(aSinceWhen);
|
||||||
|
Delete();
|
||||||
|
Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult Delete()
|
||||||
|
{
|
||||||
|
nsCOMPtr<nsIFile> file = GetFile();
|
||||||
|
if (NS_WARN_IF(!file)) {
|
||||||
|
return NS_ERROR_UNEXPECTED;
|
||||||
|
}
|
||||||
|
nsresult rv = file->Remove(false);
|
||||||
|
if (rv == NS_ERROR_FILE_NOT_FOUND) {
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
nsCOMPtr<nsIFile> mProfileDir;
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual ~ParentSingleton()
|
||||||
|
{
|
||||||
|
sParentSingleton = nullptr;
|
||||||
|
LOG((__FUNCTION__));
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
static ParentSingleton* Get()
|
||||||
|
{
|
||||||
|
if (!sParentSingleton) {
|
||||||
|
sParentSingleton = new ParentSingleton();
|
||||||
|
}
|
||||||
|
return sParentSingleton;
|
||||||
|
}
|
||||||
|
|
||||||
|
OriginKeysLoader mOriginKeys;
|
||||||
|
OriginKeysTable mPrivateBrowsingOriginKeys;
|
||||||
|
};
|
||||||
|
|
||||||
|
NS_IMPL_ISUPPORTS0(ParentSingleton)
|
||||||
|
|
||||||
|
bool
|
||||||
|
Parent::RecvGetOriginKey(const nsCString& aOrigin,
|
||||||
|
const bool& aPrivateBrowsing,
|
||||||
|
nsCString* aKey)
|
||||||
|
{
|
||||||
|
if (aPrivateBrowsing) {
|
||||||
|
mSingleton->mPrivateBrowsingOriginKeys.GetOriginKey(aOrigin, *aKey);
|
||||||
|
} else {
|
||||||
|
mSingleton->mOriginKeys.GetOriginKey(aOrigin, *aKey);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Parent::RecvSanitizeOriginKeys(const uint64_t& aSinceWhen)
|
||||||
|
{
|
||||||
|
mSingleton->mPrivateBrowsingOriginKeys.Clear(aSinceWhen);
|
||||||
|
mSingleton->mOriginKeys.Clear(aSinceWhen);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Parent::ActorDestroy(ActorDestroyReason aWhy)
|
||||||
|
{
|
||||||
|
// No more IPC from here
|
||||||
|
LOG((__FUNCTION__));
|
||||||
|
}
|
||||||
|
|
||||||
|
Parent::Parent()
|
||||||
|
: mSingleton(ParentSingleton::Get())
|
||||||
|
{
|
||||||
|
#if defined(PR_LOGGING)
|
||||||
|
if (!gMediaParentLog)
|
||||||
|
gMediaParentLog = PR_NewLogModule("MediaParent");
|
||||||
|
#endif
|
||||||
|
LOG(("media::Parent: %p", this));
|
||||||
|
|
||||||
|
MOZ_COUNT_CTOR(Parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
Parent::~Parent()
|
||||||
|
{
|
||||||
|
LOG(("~media::Parent: %p", this));
|
||||||
|
|
||||||
|
MOZ_COUNT_DTOR(Parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
PMediaParent* CreateParent()
|
||||||
|
{
|
||||||
|
return new Parent();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
42
dom/media/systemservices/MediaParent.h
Normal file
42
dom/media/systemservices/MediaParent.h
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set sw=2 ts=8 et ft=cpp : */
|
||||||
|
/* 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 mozilla_MediaParent_h
|
||||||
|
#define mozilla_MediaParent_h
|
||||||
|
|
||||||
|
#include "MediaChild.h"
|
||||||
|
|
||||||
|
#include "mozilla/dom/ContentParent.h"
|
||||||
|
#include "mozilla/media/PMediaParent.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace media {
|
||||||
|
|
||||||
|
// media::Parent implements the chrome-process side of ipc for media::Child APIs
|
||||||
|
|
||||||
|
class ParentSingleton;
|
||||||
|
|
||||||
|
class Parent : public PMediaParent
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual bool RecvGetOriginKey(const nsCString& aOrigin,
|
||||||
|
const bool& aPrivateBrowsing,
|
||||||
|
nsCString* aKey) override;
|
||||||
|
virtual bool RecvSanitizeOriginKeys(const uint64_t& aSinceWhen) override;
|
||||||
|
virtual void ActorDestroy(ActorDestroyReason aWhy) override;
|
||||||
|
|
||||||
|
Parent();
|
||||||
|
virtual ~Parent();
|
||||||
|
private:
|
||||||
|
nsRefPtr<ParentSingleton> mSingleton;
|
||||||
|
};
|
||||||
|
|
||||||
|
PMediaParent* CreateParent();
|
||||||
|
|
||||||
|
} // namespace media
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
#endif // mozilla_MediaParent_h
|
23
dom/media/systemservices/MediaUtils.cpp
Normal file
23
dom/media/systemservices/MediaUtils.cpp
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set sw=2 ts=8 et ft=cpp : */
|
||||||
|
/* 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 "MediaUtils.h"
|
||||||
|
|
||||||
|
#include "mozilla/MediaManager.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace media {
|
||||||
|
|
||||||
|
template<typename ValueType>
|
||||||
|
Pledge<ValueType>::Pledge()
|
||||||
|
: mDone(false)
|
||||||
|
, mResult(NS_OK)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(MediaManager::IsInMediaThread());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
106
dom/media/systemservices/MediaUtils.h
Normal file
106
dom/media/systemservices/MediaUtils.h
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set sw=2 ts=8 et ft=cpp : */
|
||||||
|
/* 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 mozilla_MediaUtils_h
|
||||||
|
#define mozilla_MediaUtils_h
|
||||||
|
|
||||||
|
#include "nsAutoPtr.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace media {
|
||||||
|
|
||||||
|
// A media::Pledge is a promise-like pattern for c++ that takes lambda functions.
|
||||||
|
//
|
||||||
|
// Asynchronous APIs that proxy to the chrome process and back, may return a
|
||||||
|
// pledge to allow callers to use pledge.Then() to specify a lambda function to
|
||||||
|
// invoke with the result once the asynchronous API resolves later back on the
|
||||||
|
// same thread.
|
||||||
|
//
|
||||||
|
// An advantage of this pattern is that lambdas allow "capturing" of local
|
||||||
|
// variables, much like closures in JavaScript.
|
||||||
|
|
||||||
|
template<typename ValueType>
|
||||||
|
class Pledge
|
||||||
|
{
|
||||||
|
// TODO: Remove workaround once mozilla allows std::function from <functional>
|
||||||
|
class FunctorsBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FunctorsBase() {}
|
||||||
|
virtual void Succeed(const ValueType& result) = 0;
|
||||||
|
virtual void Fail(nsresult rv) = 0;
|
||||||
|
virtual ~FunctorsBase() {};
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit Pledge();
|
||||||
|
|
||||||
|
template<typename OnSuccessType, typename OnFailureType>
|
||||||
|
void Then(OnSuccessType aOnSuccess, OnFailureType aOnFailure)
|
||||||
|
{
|
||||||
|
class F : public FunctorsBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
F(OnSuccessType& aOnSuccess, OnFailureType& aOnFailure)
|
||||||
|
: mOnSuccess(aOnSuccess), mOnFailure(aOnFailure) {}
|
||||||
|
|
||||||
|
void Succeed(const ValueType& result)
|
||||||
|
{
|
||||||
|
mOnSuccess(result);
|
||||||
|
}
|
||||||
|
void Fail(nsresult rv)
|
||||||
|
{
|
||||||
|
mOnFailure(rv);
|
||||||
|
};
|
||||||
|
|
||||||
|
OnSuccessType mOnSuccess;
|
||||||
|
OnFailureType mOnFailure;
|
||||||
|
};
|
||||||
|
mFunctors = new F(aOnSuccess, aOnFailure);
|
||||||
|
|
||||||
|
if (mDone) {
|
||||||
|
if (mResult == NS_OK) {
|
||||||
|
mFunctors->Succeed(mValue);
|
||||||
|
} else {
|
||||||
|
mFunctors->Fail(mResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void Resolve()
|
||||||
|
{
|
||||||
|
if (!mDone) {
|
||||||
|
mDone = true;
|
||||||
|
MOZ_ASSERT(mResult == NS_OK);
|
||||||
|
if (mFunctors) {
|
||||||
|
mFunctors->Succeed(mValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Reject(nsresult rv)
|
||||||
|
{
|
||||||
|
if (!mDone) {
|
||||||
|
mDone = true;
|
||||||
|
mResult = rv;
|
||||||
|
if (mFunctors) {
|
||||||
|
mFunctors->Fail(mResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueType mValue;
|
||||||
|
private:
|
||||||
|
bool mDone;
|
||||||
|
nsresult mResult;
|
||||||
|
nsAutoPtr<FunctorsBase> mFunctors;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // mozilla_MediaUtils_h
|
33
dom/media/systemservices/PMedia.ipdl
Normal file
33
dom/media/systemservices/PMedia.ipdl
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
include protocol PContent;
|
||||||
|
include protocol PBackground;
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace media {
|
||||||
|
|
||||||
|
sync protocol PMedia
|
||||||
|
{
|
||||||
|
manager PBackground;
|
||||||
|
|
||||||
|
parent:
|
||||||
|
/**
|
||||||
|
* Returns a persistent unique secret key for each origin.
|
||||||
|
* Has no expiry, but is cleared by age along with cookies.
|
||||||
|
* This is needed by mediaDevices.enumerateDevices() to produce persistent
|
||||||
|
* deviceIds that wont work cross-origin.
|
||||||
|
*/
|
||||||
|
sync GetOriginKey(nsCString origin, bool privateBrowsing) returns (nsCString key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* On clear cookies.
|
||||||
|
*/
|
||||||
|
sync SanitizeOriginKeys(uint64_t sinceWhen);
|
||||||
|
|
||||||
|
async __delete__();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace media
|
||||||
|
} // namespace mozilla
|
@ -37,6 +37,22 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
|
EXPORTS.mozilla.media += ['MediaChild.h',
|
||||||
|
'MediaParent.h',
|
||||||
|
'MediaUtils.h'
|
||||||
|
]
|
||||||
|
UNIFIED_SOURCES += ['MediaChild.cpp',
|
||||||
|
'MediaParent.cpp',
|
||||||
|
'MediaUtils.cpp'
|
||||||
|
]
|
||||||
|
IPDL_SOURCES += [
|
||||||
|
'PMedia.ipdl',
|
||||||
|
]
|
||||||
|
# /dom/base needed for nsGlobalWindow.h in MediaChild.cpp
|
||||||
|
LOCAL_INCLUDES += [
|
||||||
|
'/dom/base',
|
||||||
|
]
|
||||||
|
|
||||||
include('/ipc/chromium/chromium-config.mozbuild')
|
include('/ipc/chromium/chromium-config.mozbuild')
|
||||||
|
|
||||||
FINAL_LIBRARY = 'xul'
|
FINAL_LIBRARY = 'xul'
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "ActorsChild.h" // IndexedDB
|
#include "ActorsChild.h" // IndexedDB
|
||||||
#include "BroadcastChannelChild.h"
|
#include "BroadcastChannelChild.h"
|
||||||
#include "FileDescriptorSetChild.h"
|
#include "FileDescriptorSetChild.h"
|
||||||
|
#include "mozilla/media/MediaChild.h"
|
||||||
#include "mozilla/Assertions.h"
|
#include "mozilla/Assertions.h"
|
||||||
#include "mozilla/dom/PBlobChild.h"
|
#include "mozilla/dom/PBlobChild.h"
|
||||||
#include "mozilla/dom/cache/ActorUtils.h"
|
#include "mozilla/dom/cache/ActorUtils.h"
|
||||||
@ -281,6 +282,19 @@ BackgroundChildImpl::DeallocPCacheStreamControlChild(PCacheStreamControlChild* a
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
media::PMediaChild*
|
||||||
|
BackgroundChildImpl::AllocPMediaChild()
|
||||||
|
{
|
||||||
|
return media::CreateMediaChild();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
BackgroundChildImpl::DeallocPMediaChild(media::PMediaChild *aActor)
|
||||||
|
{
|
||||||
|
delete aActor;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ipc
|
} // namespace ipc
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
||||||
|
@ -71,6 +71,12 @@ protected:
|
|||||||
virtual bool
|
virtual bool
|
||||||
DeallocPFileDescriptorSetChild(PFileDescriptorSetChild* aActor) override;
|
DeallocPFileDescriptorSetChild(PFileDescriptorSetChild* aActor) override;
|
||||||
|
|
||||||
|
virtual PMediaChild*
|
||||||
|
AllocPMediaChild() override;
|
||||||
|
|
||||||
|
virtual bool
|
||||||
|
DeallocPMediaChild(PMediaChild* aActor) override;
|
||||||
|
|
||||||
virtual PVsyncChild*
|
virtual PVsyncChild*
|
||||||
AllocPVsyncChild() override;
|
AllocPVsyncChild() override;
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include "BroadcastChannelParent.h"
|
#include "BroadcastChannelParent.h"
|
||||||
#include "FileDescriptorSetParent.h"
|
#include "FileDescriptorSetParent.h"
|
||||||
|
#include "mozilla/media/MediaParent.h"
|
||||||
#include "mozilla/AppProcessChecker.h"
|
#include "mozilla/AppProcessChecker.h"
|
||||||
#include "mozilla/Assertions.h"
|
#include "mozilla/Assertions.h"
|
||||||
#include "mozilla/dom/ContentParent.h"
|
#include "mozilla/dom/ContentParent.h"
|
||||||
@ -360,6 +361,19 @@ BackgroundParentImpl::DeallocPBroadcastChannelParent(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
media::PMediaParent*
|
||||||
|
BackgroundParentImpl::AllocPMediaParent()
|
||||||
|
{
|
||||||
|
return media::CreateParent();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
BackgroundParentImpl::DeallocPMediaParent(media::PMediaParent *aActor)
|
||||||
|
{
|
||||||
|
delete aActor;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
class RegisterServiceWorkerCallback final : public nsRunnable
|
class RegisterServiceWorkerCallback final : public nsRunnable
|
||||||
|
@ -84,6 +84,12 @@ protected:
|
|||||||
virtual bool
|
virtual bool
|
||||||
DeallocPBroadcastChannelParent(PBroadcastChannelParent* aActor) override;
|
DeallocPBroadcastChannelParent(PBroadcastChannelParent* aActor) override;
|
||||||
|
|
||||||
|
virtual PMediaParent*
|
||||||
|
AllocPMediaParent() override;
|
||||||
|
|
||||||
|
virtual bool
|
||||||
|
DeallocPMediaParent(PMediaParent* aActor) override;
|
||||||
|
|
||||||
virtual bool
|
virtual bool
|
||||||
RecvRegisterServiceWorker(const ServiceWorkerRegistrationData& aData)
|
RecvRegisterServiceWorker(const ServiceWorkerRegistrationData& aData)
|
||||||
override;
|
override;
|
||||||
|
@ -11,6 +11,7 @@ include protocol PCacheStorage;
|
|||||||
include protocol PCacheStreamControl;
|
include protocol PCacheStreamControl;
|
||||||
include protocol PFileDescriptorSet;
|
include protocol PFileDescriptorSet;
|
||||||
include protocol PVsync;
|
include protocol PVsync;
|
||||||
|
include protocol PMedia;
|
||||||
|
|
||||||
include DOMTypes;
|
include DOMTypes;
|
||||||
include PBackgroundSharedTypes;
|
include PBackgroundSharedTypes;
|
||||||
@ -34,6 +35,7 @@ sync protocol PBackground
|
|||||||
manages PCacheStreamControl;
|
manages PCacheStreamControl;
|
||||||
manages PFileDescriptorSet;
|
manages PFileDescriptorSet;
|
||||||
manages PVsync;
|
manages PVsync;
|
||||||
|
manages PMedia;
|
||||||
|
|
||||||
parent:
|
parent:
|
||||||
// Only called at startup during mochitests to check the basic infrastructure.
|
// Only called at startup during mochitests to check the basic infrastructure.
|
||||||
@ -42,6 +44,7 @@ parent:
|
|||||||
PBackgroundIDBFactory(LoggingInfo loggingInfo);
|
PBackgroundIDBFactory(LoggingInfo loggingInfo);
|
||||||
|
|
||||||
PVsync();
|
PVsync();
|
||||||
|
PMedia();
|
||||||
|
|
||||||
PBroadcastChannel(PrincipalInfo pInfo, nsString origin, nsString channel);
|
PBroadcastChannel(PrincipalInfo pInfo, nsString origin, nsString channel);
|
||||||
|
|
||||||
|
@ -169,7 +169,7 @@ NS_NSS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nssLoadingComponent, nsNSSComponent,
|
|||||||
Init)
|
Init)
|
||||||
|
|
||||||
using namespace mozilla::psm;
|
using namespace mozilla::psm;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
// Use the special factory constructor for everything this module implements,
|
// Use the special factory constructor for everything this module implements,
|
||||||
@ -199,9 +199,9 @@ NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsure, nsPkcs11)
|
|||||||
NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsure, nsCertPicker)
|
NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsure, nsCertPicker)
|
||||||
NS_NSS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nssEnsure, nsNTLMAuthModule, InitTest)
|
NS_NSS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nssEnsure, nsNTLMAuthModule, InitTest)
|
||||||
NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsureChromeOrContent, nsCryptoHash)
|
NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsureChromeOrContent, nsCryptoHash)
|
||||||
NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsure, nsCryptoHMAC)
|
NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsureChromeOrContent, nsCryptoHMAC)
|
||||||
NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsure, nsKeyObject)
|
NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsureChromeOrContent, nsKeyObject)
|
||||||
NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsure, nsKeyObjectFactory)
|
NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsureChromeOrContent, nsKeyObjectFactory)
|
||||||
NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsure, nsDataSignatureVerifier)
|
NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsure, nsDataSignatureVerifier)
|
||||||
NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsure, nsRandomGenerator)
|
NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsure, nsRandomGenerator)
|
||||||
NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsureOnChromeOnly, nsSSLStatus)
|
NS_NSS_GENERIC_FACTORY_CONSTRUCTOR(nssEnsureOnChromeOnly, nsSSLStatus)
|
||||||
|
Loading…
Reference in New Issue
Block a user