Merge mozilla-central to b2g-inbound

This commit is contained in:
Carsten "Tomcat" Book 2014-07-04 14:17:27 +02:00
commit 8ba211d938
88 changed files with 2047 additions and 1294 deletions

View File

@ -9,6 +9,7 @@ support-files =
doc_media-node-creation.html
doc_destroy-nodes.html
doc_connect-toggle.html
doc_connect-param.html
440hz_sine.ogg
head.js
@ -20,6 +21,7 @@ support-files =
[browser_audionode-actor-is-source.js]
[browser_webaudio-actor-simple.js]
[browser_webaudio-actor-destroy-node.js]
[browser_webaudio-actor-connect-param.js]
[browser_wa_destroy-node-01.js]

View File

@ -0,0 +1,26 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test the `connect-param` event on the web audio actor.
*/
function spawnTest () {
let [target, debuggee, front] = yield initBackend(CONNECT_PARAM_URL);
let [_, _, [destNode, carrierNode, modNode, gainNode], _, connectParam] = yield Promise.all([
front.setup({ reload: true }),
once(front, "start-context"),
getN(front, "create-node", 4),
get2(front, "connect-node"),
once(front, "connect-param")
]);
info(connectParam);
is(connectParam.source.actorID, modNode.actorID, "`connect-param` has correct actor for `source`");
is(connectParam.dest.actorID, gainNode.actorID, "`connect-param` has correct actor for `dest`");
is(connectParam.param, "gain", "`connect-param` has correct parameter name for `param`");
yield removeTab(target.tab);
finish();
}

View File

@ -0,0 +1,28 @@
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<!doctype html>
<html>
<head>
<meta charset="utf-8"/>
<title>Web Audio Editor test page</title>
</head>
<body>
<script type="text/javascript;version=1.8">
"use strict";
let ctx = new AudioContext();
let carrier = ctx.createOscillator();
let modulator = ctx.createOscillator();
let gain = ctx.createGain();
carrier.connect(gain);
gain.connect(ctx.destination);
modulator.connect(gain.gain);
modulator.start(0);
carrier.start(0);
</script>
</body>
</html>

View File

@ -28,6 +28,7 @@ const MEDIA_NODES_URL = EXAMPLE_URL + "doc_media-node-creation.html";
const BUFFER_AND_ARRAY_URL = EXAMPLE_URL + "doc_buffer-and-array.html";
const DESTROY_NODES_URL = EXAMPLE_URL + "doc_destroy-nodes.html";
const CONNECT_TOGGLE_URL = EXAMPLE_URL + "doc_connect-toggle.html";
const CONNECT_PARAM_URL = EXAMPLE_URL + "doc_connect-param.html";
// All tests are asynchronous.
waitForExplicitFinish();

View File

@ -86,7 +86,7 @@ class RemoteAutomation(Automation):
topActivity = self._devicemanager.getTopActivity()
if topActivity == proc.procName:
proc.kill()
proc.kill(True)
if status == 1:
if maxTime:
print "TEST-UNEXPECTED-FAIL | %s | application ran for longer than " \
@ -287,5 +287,26 @@ class RemoteAutomation(Automation):
return status
def kill(self):
self.dm.killProcess(self.procName)
def kill(self, stagedShutdown = False):
if stagedShutdown:
# Trigger an ANR report with "kill -3" (SIGQUIT)
self.dm.killProcess(self.procName, 3)
time.sleep(3)
# Trigger a breakpad dump with "kill -6" (SIGABRT)
self.dm.killProcess(self.procName, 6)
# Wait for process to end
retries = 0
while retries < 3:
pid = self.dm.processExist(self.procName)
if pid and pid > 0:
print "%s still alive after SIGABRT: waiting..." % self.procName
time.sleep(5)
else:
return
retries += 1
self.dm.killProcess(self.procName, 9)
pid = self.dm.processExist(self.procName)
if pid and pid > 0:
self.dm.killProcess(self.procName)
else:
self.dm.killProcess(self.procName)

View File

@ -228,7 +228,12 @@ HTMLTrackElement::LoadResource()
return;
}
CreateTextTrack();
// We may already have a TextTrack at this point if GetTrack() has already
// been called. This happens, for instance, if script tries to get the
// TextTrack before its mTrackElement has been bound to the DOM tree.
if (!mTrack) {
CreateTextTrack();
}
// Check for a Content Security Policy to pass down to the channel
// created to load the media content.

View File

@ -321,6 +321,7 @@ skip-if = os == 'win' # bug 894922
[test_bug895305.html]
[test_bug919265.html]
[test_bug957847.html]
[test_bug1018933.html]
[test_can_play_type.html]
[test_can_play_type_mpeg.html]
skip-if = buildapp == 'b2g' # bug 1021675

View File

@ -0,0 +1,50 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1018933
-->
<head>
<meta charset='utf-8'>
<title>Regression test for bug 1018933 - HTMLTrackElement should create only one TextTrack</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<p id="display"></p>
<div id="content">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({"set": [["media.webvtt.enabled", true]]},
function() {
var video = document.createElement("video");
video.src = "seek.webm";
video.preload = "auto";
var trackElement = document.createElement("track");
trackElement.src = "basic.vtt";
trackElement.kind = "subtitles";
document.getElementById("content").appendChild(video);
video.appendChild(trackElement);
// Accessing the track now would have caused the bug as the track element
// shouldn't have had time to bind to the tree yet.
trackElement.track.mode = 'showing';
video.addEventListener("loadedmetadata", function run_tests() {
// Re-que run_tests() at the end of the event loop until the track
// element has loaded its data.
if (trackElement.readyState == 1) {
setTimeout(run_tests, 0);
return;
}
is(video.textTracks.length, 1, "Video should have one TextTrack.");
SimpleTest.finish();
});
}
);
</script>
</pre>
</body>
</html>

View File

@ -12,7 +12,6 @@
#include "StreamNotifyChild.h"
#include "PluginProcessChild.h"
#include "gfxASurface.h"
#include "gfxContext.h"
#include "gfxPlatform.h"
#include "gfx2DGlue.h"
#include "nsNPAPIPluginInstance.h"
@ -2787,12 +2786,6 @@ PluginInstanceChild::DoAsyncSetWindow(const gfxSurfaceType& aSurfaceType,
}
}
static inline gfxRect
GfxFromNsRect(const nsIntRect& aRect)
{
return gfxRect(aRect.x, aRect.y, aRect.width, aRect.height);
}
bool
PluginInstanceChild::CreateOptSurface(void)
{
@ -3454,12 +3447,14 @@ PluginInstanceChild::ShowPluginFrame()
PLUGIN_LOG_DEBUG((" (on background)"));
// Source the background pixels ...
{
nsRefPtr<gfxContext> ctx =
new gfxContext(mHelperSurface ? mHelperSurface : mCurrentSurface);
ctx->SetSource(mBackground);
ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
ctx->Rectangle(gfxRect(rect.x, rect.y, rect.width, rect.height));
ctx->Fill();
nsRefPtr<gfxASurface> surface =
mHelperSurface ? mHelperSurface : mCurrentSurface;
RefPtr<DrawTarget> dt = CreateDrawTargetForSurface(surface);
RefPtr<SourceSurface> backgroundSurface =
gfxPlatform::GetSourceSurfaceForSurface(dt, mBackground);
dt->CopySurface(backgroundSurface,
ToIntRect(rect),
ToIntPoint(rect.TopLeft()));
}
// ... and hand off to the plugin
// BEWARE: mBackground may die during this call
@ -3583,18 +3578,17 @@ PluginInstanceChild::ReadbackDifferenceRect(const nsIntRect& rect)
mSurfaceDifferenceRect.width, mSurfaceDifferenceRect.height));
// Read back previous content
nsRefPtr<gfxContext> ctx = new gfxContext(mCurrentSurface);
ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
ctx->SetSource(mBackSurface);
RefPtr<DrawTarget> dt = CreateDrawTargetForSurface(mCurrentSurface);
RefPtr<SourceSurface> source =
gfxPlatform::GetSourceSurfaceForSurface(dt, mBackSurface);
// Subtract from mSurfaceDifferenceRect area which is overlapping with rect
nsIntRegion result;
result.Sub(mSurfaceDifferenceRect, nsIntRegion(rect));
nsIntRegionRectIterator iter(result);
const nsIntRect* r;
while ((r = iter.Next()) != nullptr) {
ctx->Rectangle(GfxFromNsRect(*r));
dt->CopySurface(source, ToIntRect(*r), ToIntPoint(r->TopLeft()));
}
ctx->Fill();
return true;
}

View File

@ -3309,13 +3309,13 @@ WifiWorker.prototype = {
return;
}
let certDB2 = Cc["@mozilla.org/security/x509certdb;1"]
.getService(Ci.nsIX509CertDB2);
if (!certDB2) {
let certDB = Cc["@mozilla.org/security/x509certdb;1"]
.getService(Ci.nsIX509CertDB);
if (!certDB) {
self._sendMessage(message, false, "Failed to query NSS DB service", msg);
}
let certList = certDB2.getCerts();
let certList = certDB.getCerts();
if (!certList) {
self._sendMessage(message, false, "Failed to get certificate List", msg);
}
@ -3332,7 +3332,7 @@ WifiWorker.prototype = {
};
while (certListEnum.hasMoreElements()) {
let certInfo = certListEnum.getNext().QueryInterface(Ci.nsIX509Cert3);
let certInfo = certListEnum.getNext().QueryInterface(Ci.nsIX509Cert);
let certNicknameInfo = /WIFI\_([A-Z]*)\_(.*)/.exec(certInfo.nickname);
if (!certNicknameInfo) {
continue;

View File

@ -21,7 +21,6 @@
#include "nsPIDOMWindow.h"
#include <algorithm>
#include "BackgroundChild.h"
#include "GeckoProfiler.h"
#include "js/OldDebugAPI.h"
#include "jsfriendapi.h"
@ -41,7 +40,6 @@
#include "nsContentUtils.h"
#include "nsCycleCollector.h"
#include "nsDOMJSUtils.h"
#include "nsIIPCBackgroundChildCreateCallback.h"
#include "nsISupportsImpl.h"
#include "nsLayoutStatics.h"
#include "nsNetUtil.h"
@ -66,12 +64,6 @@
#include "WorkerPrivate.h"
#include "WorkerRunnable.h"
#ifdef ENABLE_TESTS
#include "BackgroundChildImpl.h"
#include "mozilla/ipc/PBackgroundChild.h"
#include "prrng.h"
#endif
using namespace mozilla;
using namespace mozilla::dom;
@ -169,10 +161,6 @@ RuntimeService* gRuntimeService = nullptr;
// Only non-null during the call to Init.
RuntimeService* gRuntimeServiceDuringInit = nullptr;
#ifdef ENABLE_TESTS
bool gTestPBackground = false;
#endif // ENABLE_TESTS
enum {
ID_Worker = 0,
ID_ChromeWorker,
@ -911,37 +899,6 @@ private:
WorkerPrivate* mWorkerPrivate;
};
class WorkerBackgroundChildCallback MOZ_FINAL :
public nsIIPCBackgroundChildCreateCallback
{
bool* mDone;
public:
WorkerBackgroundChildCallback(bool* aDone)
: mDone(aDone)
{
MOZ_ASSERT(mDone);
}
NS_DECL_ISUPPORTS
private:
~WorkerBackgroundChildCallback()
{ }
virtual void
ActorCreated(PBackgroundChild* aActor) MOZ_OVERRIDE
{
*mDone = true;
}
virtual void
ActorFailed() MOZ_OVERRIDE
{
*mDone = true;
}
};
class WorkerThreadPrimaryRunnable MOZ_FINAL : public nsRunnable
{
WorkerPrivate* mWorkerPrivate;
@ -984,9 +941,6 @@ private:
~WorkerThreadPrimaryRunnable()
{ }
nsresult
SynchronouslyCreatePBackground();
NS_DECL_NSIRUNNABLE
};
@ -1086,28 +1040,6 @@ public:
}
#endif
#ifdef ENABLE_TESTS
void
TestPBackground()
{
using namespace mozilla::ipc;
if (gTestPBackground) {
// Randomize value to validate workers are not cross-posting messages.
uint32_t testValue;
PRSize randomSize = PR_GetRandomNoise(&testValue, sizeof(testValue));
MOZ_RELEASE_ASSERT(randomSize == sizeof(testValue));
nsCString testStr;
testStr.AppendInt(testValue);
testStr.AppendInt(reinterpret_cast<int64_t>(PR_GetCurrentThread()));
PBackgroundChild* existingBackgroundChild =
BackgroundChild::GetForCurrentThread();
MOZ_RELEASE_ASSERT(existingBackgroundChild);
bool ok = existingBackgroundChild->SendPBackgroundTestConstructor(testStr);
MOZ_RELEASE_ASSERT(ok);
}
}
#endif // #ENABLE_TESTS
private:
WorkerThread()
: nsThread(nsThread::NOT_MAIN_THREAD, WORKER_STACK_SIZE),
@ -1311,10 +1243,6 @@ RuntimeService::GetOrCreateService()
return nullptr;
}
#ifdef ENABLE_TESTS
gTestPBackground = mozilla::Preferences::GetBool("pbackground.testing", false);
#endif // ENABLE_TESTS
// The observer service now owns us until shutdown.
gRuntimeService = service;
}
@ -1604,6 +1532,10 @@ RuntimeService::ScheduleWorker(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
return false;
}
#ifdef DEBUG
thread->SetAcceptingNonWorkerRunnables(false);
#endif
return true;
}
@ -2592,20 +2524,8 @@ RuntimeService::WorkerThread::Observer::OnProcessNextEvent(
bool aMayWait,
uint32_t aRecursionDepth)
{
using mozilla::ipc::BackgroundChild;
mWorkerPrivate->AssertIsOnWorkerThread();
// If the PBackground child is not created yet, then we must permit
// blocking event processing to support SynchronouslyCreatePBackground().
// If this occurs then we are spinning on the event queue at the start of
// PrimaryWorkerRunnable::Run() and don't want to process the event in
// mWorkerPrivate yet.
if (aMayWait) {
MOZ_ASSERT(aRecursionDepth == 2);
MOZ_ASSERT(!BackgroundChild::GetForCurrentThread());
return NS_OK;
}
MOZ_ASSERT(!aMayWait);
mWorkerPrivate->OnProcessNextEvent(aRecursionDepth);
return NS_OK;
@ -2649,15 +2569,11 @@ LogViolationDetailsRunnable::Run()
return NS_OK;
}
NS_IMPL_ISUPPORTS(WorkerBackgroundChildCallback, nsIIPCBackgroundChildCreateCallback)
NS_IMPL_ISUPPORTS_INHERITED0(WorkerThreadPrimaryRunnable, nsRunnable)
NS_IMETHODIMP
WorkerThreadPrimaryRunnable::Run()
{
using mozilla::ipc::BackgroundChild;
#ifdef MOZ_NUWA_PROCESS
if (IsNuwaProcess()) {
NS_ASSERTION(NuwaMarkCurrentThread != nullptr,
@ -2676,19 +2592,6 @@ WorkerThreadPrimaryRunnable::Run()
profiler_register_thread(threadName.get(), &stackBaseGuess);
// Note: SynchronouslyCreatePBackground() must be called prior to
// mThread->SetWorker() in order to avoid accidentally consuming
// worker messages here.
nsresult rv = SynchronouslyCreatePBackground();
if (NS_WARN_IF(NS_FAILED(rv))) {
// XXX need to fire an error at parent.
return rv;
}
#ifdef ENABLE_TESTS
mThread->TestPBackground();
#endif
mThread->SetWorker(mWorkerPrivate);
mWorkerPrivate->AssertIsOnWorkerThread();
@ -2722,12 +2625,6 @@ WorkerThreadPrimaryRunnable::Run()
JS_ReportPendingException(cx);
}
#ifdef ENABLE_TESTS
mThread->TestPBackground();
#endif
BackgroundChild::CloseForCurrentThread();
#ifdef MOZ_ENABLE_PROFILER_SPS
if (stack) {
stack->sampleRuntime(nullptr);
@ -2766,38 +2663,6 @@ WorkerThreadPrimaryRunnable::Run()
return NS_OK;
}
nsresult
WorkerThreadPrimaryRunnable::SynchronouslyCreatePBackground()
{
using mozilla::ipc::BackgroundChild;
MOZ_ASSERT(!BackgroundChild::GetForCurrentThread());
bool done = false;
nsCOMPtr<nsIIPCBackgroundChildCreateCallback> callback =
new WorkerBackgroundChildCallback(&done);
if (NS_WARN_IF(!BackgroundChild::GetOrCreateForCurrentThread(callback))) {
return NS_ERROR_FAILURE;
}
while (!done) {
if (NS_WARN_IF(!NS_ProcessNextEvent(mThread, true /* aMayWay */))) {
return NS_ERROR_FAILURE;
}
}
if (NS_WARN_IF(!BackgroundChild::GetForCurrentThread())) {
return NS_ERROR_FAILURE;
}
#ifdef DEBUG
mThread->SetAcceptingNonWorkerRunnables(false);
#endif
return NS_OK;
}
NS_IMPL_ISUPPORTS_INHERITED0(WorkerThreadPrimaryRunnable::FinishedRunnable,
nsRunnable)

View File

@ -12,6 +12,8 @@
#include "mozilla/Preferences.h"
#include "mozilla/Endian.h"
#include "TexturePoolOGL.h"
#include "mozilla/layers/CompositorOGL.h"
#include "mozilla/layers/LayerManagerComposite.h"
#include "mozilla/layers/TextureHostOGL.h"
#include "gfxColor.h"
@ -317,6 +319,7 @@ public:
}
void AppendDebugData(DebugGLData *aDebugData);
void CleanDebugData();
void DispatchDebugData();
private:
nsTArray<nsRefPtr<LayerScopeWebSocketHandler> > mHandlers;
@ -325,7 +328,37 @@ private:
nsCOMPtr<nsIServerSocket> mServerSocket;
};
static StaticAutoPtr<LayerScopeWebSocketManager> gLayerScopeWebSocketManager;
// Static class to create and destory LayerScopeWebSocketManager object
class WebSocketHelper
{
public:
static void CreateServerSocket()
{
// Create Web Server Socket (which has to be on the main thread)
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
if (!sWebSocketManager) {
sWebSocketManager = new LayerScopeWebSocketManager();
}
}
static void DestroyServerSocket()
{
// Destroy Web Server Socket
if (sWebSocketManager) {
sWebSocketManager->RemoveAllConnections();
}
}
static LayerScopeWebSocketManager* GetSocketManager()
{
return sWebSocketManager.get();
}
private:
static StaticAutoPtr<LayerScopeWebSocketManager> sWebSocketManager;
};
StaticAutoPtr<LayerScopeWebSocketManager> WebSocketHelper::sWebSocketManager;
class DebugGLData : public LinkedListElement<DebugGLData> {
public:
@ -378,9 +411,9 @@ public:
}
static bool WriteToStream(void *ptr, uint32_t size) {
if (!gLayerScopeWebSocketManager)
if (!WebSocketHelper::GetSocketManager())
return true;
return gLayerScopeWebSocketManager->WriteAll(ptr, size);
return WebSocketHelper::GetSocketManager()->WriteAll(ptr, size);
}
protected:
@ -428,83 +461,97 @@ public:
class DebugGLTextureData : public DebugGLData {
public:
DebugGLTextureData(GLContext* cx, void* layerRef, GLuint target, GLenum name, DataSourceSurface* img)
DebugGLTextureData(GLContext* cx,
void* layerRef,
GLenum target,
GLuint name,
DataSourceSurface* img)
: DebugGLData(DebugGLData::TextureData, cx),
mLayerRef(layerRef),
mTarget(target),
mName(name),
mImage(img)
{ }
mDatasize(0)
{
// pre-packing
// DataSourceSurface may have locked buffer,
// so we should compress now, and then it could
// be unlocked outside.
pack(img);
}
void *GetLayerRef() const { return mLayerRef; }
GLuint GetName() const { return mName; }
DataSourceSurface* GetImage() const { return mImage; }
GLenum GetTextureTarget() const { return mTarget; }
virtual bool Write() {
DebugGLData::TexturePacket packet;
char* dataptr = nullptr;
uint32_t datasize = 0;
std::auto_ptr<char> compresseddata;
packet.type = mDataType;
packet.ptr = static_cast<uint64_t>(mContextAddress);
packet.layerref = reinterpret_cast<uint64_t>(mLayerRef);
packet.name = mName;
packet.format = 0;
packet.target = mTarget;
packet.dataFormat = LOCAL_GL_RGBA;
if (mImage) {
packet.width = mImage->GetSize().width;
packet.height = mImage->GetSize().height;
packet.stride = mImage->Stride();
packet.dataSize = mImage->GetSize().height * mImage->Stride();
dataptr = (char*) mImage->GetData();
datasize = packet.dataSize;
compresseddata = std::auto_ptr<char>((char*) moz_malloc(LZ4::maxCompressedSize(datasize)));
if (compresseddata.get()) {
int ndatasize = LZ4::compress(dataptr, datasize, compresseddata.get());
if (ndatasize > 0) {
datasize = ndatasize;
dataptr = compresseddata.get();
packet.dataFormat = (1 << 16) | packet.dataFormat;
packet.dataSize = datasize;
}
}
} else {
packet.width = 0;
packet.height = 0;
packet.stride = 0;
packet.dataSize = 0;
}
// write the packet header data
if (!WriteToStream(&packet, sizeof(packet)))
if (!WriteToStream(&mPacket, sizeof(mPacket)))
return false;
// then the image data
if (!WriteToStream(dataptr, datasize))
if (mCompresseddata.get() && !WriteToStream(mCompresseddata.get(), mDatasize))
return false;
// then pad out to 4 bytes
if (datasize % 4 != 0) {
if (mDatasize % 4 != 0) {
static char buf[] = { 0, 0, 0, 0 };
if (!WriteToStream(buf, 4 - (datasize % 4)))
if (!WriteToStream(buf, 4 - (mDatasize % 4)))
return false;
}
return true;
}
private:
void pack(DataSourceSurface* aImage) {
mPacket.type = mDataType;
mPacket.ptr = static_cast<uint64_t>(mContextAddress);
mPacket.layerref = reinterpret_cast<uint64_t>(mLayerRef);
mPacket.name = mName;
mPacket.format = 0;
mPacket.target = mTarget;
mPacket.dataFormat = LOCAL_GL_RGBA;
if (aImage) {
mPacket.width = aImage->GetSize().width;
mPacket.height = aImage->GetSize().height;
mPacket.stride = aImage->Stride();
mPacket.dataSize = aImage->GetSize().height * aImage->Stride();
mCompresseddata = std::auto_ptr<char>(
(char*)moz_malloc(LZ4::maxCompressedSize(mPacket.dataSize)));
if (mCompresseddata.get()) {
int ndatasize = LZ4::compress((char*)aImage->GetData(),
mPacket.dataSize,
mCompresseddata.get());
if (ndatasize > 0) {
mDatasize = ndatasize;
mPacket.dataFormat = (1 << 16) | mPacket.dataFormat;
mPacket.dataSize = mDatasize;
} else {
NS_WARNING("Compress data failed");
}
} else {
NS_WARNING("Couldn't moz_malloc for compressed data.");
}
} else {
mPacket.width = 0;
mPacket.height = 0;
mPacket.stride = 0;
mPacket.dataSize = 0;
}
}
protected:
void* mLayerRef;
GLenum mTarget;
GLuint mName;
RefPtr<DataSourceSurface> mImage;
// Packet data
DebugGLData::TexturePacket mPacket;
std::auto_ptr<char> mCompresseddata;
uint32_t mDatasize;
};
class DebugGLColorData : public DebugGLData {
@ -539,18 +586,6 @@ protected:
nsIntSize mSize;
};
static bool
CheckSender()
{
if (!gLayerScopeWebSocketManager)
return false;
if (!gLayerScopeWebSocketManager->IsConnected())
return false;
return true;
}
class DebugListener : public nsIServerSocketListener
{
virtual ~DebugListener() { }
@ -566,11 +601,11 @@ public:
NS_IMETHODIMP OnSocketAccepted(nsIServerSocket *aServ,
nsISocketTransport *aTransport)
{
if (!gLayerScopeWebSocketManager)
if (!WebSocketHelper::GetSocketManager())
return NS_OK;
printf_stderr("*** LayerScope: Accepted connection\n");
gLayerScopeWebSocketManager->AddConnection(aTransport);
WebSocketHelper::GetSocketManager()->AddConnection(aTransport);
return NS_OK;
}
@ -594,24 +629,19 @@ public:
NS_DECL_THREADSAFE_ISUPPORTS
DebugDataSender() {
mList = new LinkedList<DebugGLData>();
}
DebugDataSender() { }
void Append(DebugGLData *d) {
mList->insertBack(d);
mList.insertBack(d);
}
void Cleanup() {
if (!mList)
if (mList.isEmpty())
return;
DebugGLData *d;
while ((d = mList->popFirst()) != nullptr)
while ((d = mList.popFirst()) != nullptr)
delete d;
delete mList;
mList = nullptr;
}
/* nsIRunnable impl; send the data */
@ -620,7 +650,7 @@ public:
DebugGLData *d;
nsresult rv = NS_OK;
while ((d = mList->popFirst()) != nullptr) {
while ((d = mList.popFirst()) != nullptr) {
std::auto_ptr<DebugGLData> cleaner(d);
if (!d->Write()) {
rv = NS_ERROR_FAILURE;
@ -631,84 +661,124 @@ public:
Cleanup();
if (NS_FAILED(rv)) {
LayerScope::DestroyServerSocket();
WebSocketHelper::DestroyServerSocket();
}
return NS_OK;
}
protected:
LinkedList<DebugGLData> *mList;
LinkedList<DebugGLData> mList;
};
NS_IMPL_ISUPPORTS(DebugDataSender, nsIRunnable);
void
LayerScope::CreateServerSocket()
/*
* LayerScope SendXXX Structure
* 1. SendLayer
* 2. SendEffectChain
* 1. SendTexturedEffect
* -> SendTextureSource
* 2. SendYCbCrEffect
* -> SendTextureSource
* 3. SendColor
*/
class SenderHelper
{
if (!gfxPrefs::LayerScopeEnabled()) {
// Sender public APIs
public:
static void SendLayer(LayerComposite* aLayer,
int aWidth,
int aHeight);
static void SendEffectChain(gl::GLContext* aGLContext,
const EffectChain& aEffectChain,
int aWidth = 0,
int aHeight = 0);
// Sender private functions
private:
static void SendColor(void* aLayerRef,
const gfxRGBA& aColor,
int aWidth,
int aHeight);
static void SendTextureSource(GLContext* aGLContext,
void* aLayerRef,
TextureSourceOGL* aSource,
bool aFlipY);
static void SendTexturedEffect(GLContext* aGLContext,
void* aLayerRef,
const TexturedEffect* aEffect);
static void SendYCbCrEffect(GLContext* aGLContext,
void* aLayerRef,
const EffectYCbCr* aEffect);
};
// ----------------------------------------------
// SenderHelper implementation
// ----------------------------------------------
void
SenderHelper::SendLayer(LayerComposite* aLayer,
int aWidth,
int aHeight)
{
MOZ_ASSERT(aLayer && aLayer->GetLayer());
if (!aLayer || !aLayer->GetLayer()) {
return;
}
if (!gLayerScopeWebSocketManager) {
gLayerScopeWebSocketManager = new LayerScopeWebSocketManager();
switch (aLayer->GetLayer()->GetType()) {
case Layer::TYPE_COLOR: {
EffectChain effect;
aLayer->GenEffectChain(effect);
SenderHelper::SendEffectChain(nullptr, effect, aWidth, aHeight);
break;
}
case Layer::TYPE_IMAGE:
case Layer::TYPE_CANVAS:
case Layer::TYPE_THEBES: {
// Get CompositableHost and Compositor
CompositableHost* compHost = aLayer->GetCompositableHost();
Compositor* comp = compHost->GetCompositor();
// Send EffectChain only for CompositorOGL
if (LayersBackend::LAYERS_OPENGL == comp->GetBackendType()) {
CompositorOGL* compOGL = static_cast<CompositorOGL*>(comp);
EffectChain effect;
// Generate primary effect (lock and gen)
AutoLockCompositableHost lock(compHost);
aLayer->GenEffectChain(effect);
SenderHelper::SendEffectChain(compOGL->gl(), effect);
}
break;
}
case Layer::TYPE_CONTAINER:
default:
break;
}
}
void
LayerScope::DestroyServerSocket()
SenderHelper::SendColor(void* aLayerRef,
const gfxRGBA& aColor,
int aWidth,
int aHeight)
{
if (gLayerScopeWebSocketManager) {
gLayerScopeWebSocketManager->RemoveAllConnections();
}
}
void
LayerScope::BeginFrame(GLContext* aGLContext, int64_t aFrameStamp)
{
if (!gLayerScopeWebSocketManager)
return;
if (!gLayerScopeWebSocketManager->IsConnected())
return;
#if 0
// if we're sending data in between frames, flush the list down the socket,
// and start a new one
if (gCurrentSender) {
gDebugSenderThread->Dispatch(gCurrentSender, NS_DISPATCH_NORMAL);
}
#endif
gLayerScopeWebSocketManager->AppendDebugData(new DebugGLData(DebugGLData::FrameStart, aGLContext, aFrameStamp));
}
void
LayerScope::EndFrame(GLContext* aGLContext)
{
if (!CheckSender())
return;
gLayerScopeWebSocketManager->AppendDebugData(new DebugGLData(DebugGLData::FrameEnd, aGLContext));
gLayerScopeWebSocketManager->DispatchDebugData();
}
static void
SendColor(void* aLayerRef, const gfxRGBA& aColor, int aWidth, int aHeight)
{
if (!CheckSender())
return;
gLayerScopeWebSocketManager->AppendDebugData(
WebSocketHelper::GetSocketManager()->AppendDebugData(
new DebugGLColorData(aLayerRef, aColor, aWidth, aHeight));
}
static void
SendTextureSource(GLContext* aGLContext,
void* aLayerRef,
TextureSourceOGL* aSource,
bool aFlipY)
void
SenderHelper::SendTextureSource(GLContext* aGLContext,
void* aLayerRef,
TextureSourceOGL* aSource,
bool aFlipY)
{
MOZ_ASSERT(aGLContext);
if (!aGLContext) {
return;
}
GLenum textureTarget = aSource->GetTextureTarget();
ShaderConfigOGL config = ShaderConfigFromTargetAndFormat(textureTarget,
aSource->GetFormat());
@ -736,15 +806,15 @@ SendTextureSource(GLContext* aGLContext,
size,
shaderConfig, aFlipY);
gLayerScopeWebSocketManager->AppendDebugData(
WebSocketHelper::GetSocketManager()->AppendDebugData(
new DebugGLTextureData(aGLContext, aLayerRef, textureTarget,
textureId, img));
}
static void
SendTexturedEffect(GLContext* aGLContext,
void* aLayerRef,
const TexturedEffect* aEffect)
void
SenderHelper::SendTexturedEffect(GLContext* aGLContext,
void* aLayerRef,
const TexturedEffect* aEffect)
{
TextureSourceOGL* source = aEffect->mTexture->AsSourceOGL();
if (!source)
@ -754,10 +824,10 @@ SendTexturedEffect(GLContext* aGLContext,
SendTextureSource(aGLContext, aLayerRef, source, flipY);
}
static void
SendYCbCrEffect(GLContext* aGLContext,
void* aLayerRef,
const EffectYCbCr* aEffect)
void
SenderHelper::SendYCbCrEffect(GLContext* aGLContext,
void* aLayerRef,
const EffectYCbCr* aEffect)
{
TextureSource* sourceYCbCr = aEffect->mTexture;
if (!sourceYCbCr)
@ -775,49 +845,48 @@ SendYCbCrEffect(GLContext* aGLContext,
}
void
LayerScope::SendEffectChain(GLContext* aGLContext,
const EffectChain& aEffectChain,
int aWidth, int aHeight)
SenderHelper::SendEffectChain(GLContext* aGLContext,
const EffectChain& aEffectChain,
int aWidth,
int aHeight)
{
if (!CheckSender())
return;
const Effect* primaryEffect = aEffectChain.mPrimaryEffect;
switch (primaryEffect->mType) {
case EffectTypes::RGB:
{
const TexturedEffect* texturedEffect =
static_cast<const TexturedEffect*>(primaryEffect);
SendTexturedEffect(aGLContext, aEffectChain.mLayerRef, texturedEffect);
}
break;
case EffectTypes::YCBCR:
{
const EffectYCbCr* yCbCrEffect =
static_cast<const EffectYCbCr*>(primaryEffect);
SendYCbCrEffect(aGLContext, aEffectChain.mLayerRef, yCbCrEffect);
}
case EffectTypes::SOLID_COLOR:
{
const EffectSolidColor* solidColorEffect =
static_cast<const EffectSolidColor*>(primaryEffect);
gfxRGBA color(solidColorEffect->mColor.r,
solidColorEffect->mColor.g,
solidColorEffect->mColor.b,
solidColorEffect->mColor.a);
SendColor(aEffectChain.mLayerRef, color, aWidth, aHeight);
}
break;
case EffectTypes::COMPONENT_ALPHA:
case EffectTypes::RENDER_TARGET:
default:
break;
case EffectTypes::RGB: {
const TexturedEffect* texturedEffect =
static_cast<const TexturedEffect*>(primaryEffect);
SendTexturedEffect(aGLContext, aEffectChain.mLayerRef, texturedEffect);
break;
}
case EffectTypes::YCBCR: {
const EffectYCbCr* yCbCrEffect =
static_cast<const EffectYCbCr*>(primaryEffect);
SendYCbCrEffect(aGLContext, aEffectChain.mLayerRef, yCbCrEffect);
break;
}
case EffectTypes::SOLID_COLOR: {
const EffectSolidColor* solidColorEffect =
static_cast<const EffectSolidColor*>(primaryEffect);
gfxRGBA color(solidColorEffect->mColor.r,
solidColorEffect->mColor.g,
solidColorEffect->mColor.b,
solidColorEffect->mColor.a);
SendColor(aEffectChain.mLayerRef, color, aWidth, aHeight);
break;
}
case EffectTypes::COMPONENT_ALPHA:
case EffectTypes::RENDER_TARGET:
default:
break;
}
//const Effect* secondaryEffect = aEffectChain.mSecondaryEffects[EffectTypes::MASK];
// TODO:
}
// ----------------------------------------------
// LayerScopeWebSocketManager implementation
// ----------------------------------------------
LayerScopeWebSocketManager::LayerScopeWebSocketManager()
{
NS_NewThread(getter_AddRefs(mDebugSenderThread));
@ -832,7 +901,8 @@ LayerScopeWebSocketManager::~LayerScopeWebSocketManager()
{
}
void LayerScopeWebSocketManager::AppendDebugData(DebugGLData *aDebugData)
void
LayerScopeWebSocketManager::AppendDebugData(DebugGLData *aDebugData)
{
if (!mCurrentSender) {
mCurrentSender = new DebugDataSender();
@ -841,11 +911,125 @@ void LayerScopeWebSocketManager::AppendDebugData(DebugGLData *aDebugData)
mCurrentSender->Append(aDebugData);
}
void LayerScopeWebSocketManager::DispatchDebugData()
void
LayerScopeWebSocketManager::CleanDebugData()
{
if (mCurrentSender) {
mCurrentSender->Cleanup();
}
}
void
LayerScopeWebSocketManager::DispatchDebugData()
{
mDebugSenderThread->Dispatch(mCurrentSender, NS_DISPATCH_NORMAL);
mCurrentSender = nullptr;
}
// ----------------------------------------------
// LayerScope implementation
// ----------------------------------------------
void
LayerScope::Init()
{
if (!gfxPrefs::LayerScopeEnabled()) {
return;
}
// Note: The server socket has to be created on the main thread
WebSocketHelper::CreateServerSocket();
}
void
LayerScope::DeInit()
{
// Destroy Web Server Socket
WebSocketHelper::DestroyServerSocket();
}
void
LayerScope::SendEffectChain(gl::GLContext* aGLContext,
const EffectChain& aEffectChain,
int aWidth,
int aHeight)
{
// Protect this public function
if (!CheckSendable()) {
return;
}
SenderHelper::SendEffectChain(aGLContext, aEffectChain, aWidth, aHeight);
}
void
LayerScope::SendLayer(LayerComposite* aLayer,
int aWidth,
int aHeight)
{
// Protect this public function
if (!CheckSendable()) {
return;
}
SenderHelper::SendLayer(aLayer, aWidth, aHeight);
}
bool
LayerScope::CheckSendable()
{
if (!WebSocketHelper::GetSocketManager()) {
return false;
}
if (!WebSocketHelper::GetSocketManager()->IsConnected()) {
return false;
}
return true;
}
void
LayerScope::CleanLayer()
{
if (CheckSendable()) {
WebSocketHelper::GetSocketManager()->CleanDebugData();
}
}
// ----------------------------------------------
// LayerScopeAutoFrame implementation
// ----------------------------------------------
LayerScopeAutoFrame::LayerScopeAutoFrame(int64_t aFrameStamp)
{
// Do Begin Frame
BeginFrame(aFrameStamp);
}
LayerScopeAutoFrame::~LayerScopeAutoFrame()
{
// Do End Frame
EndFrame();
}
void
LayerScopeAutoFrame::BeginFrame(int64_t aFrameStamp)
{
if (!LayerScope::CheckSendable()) {
return;
}
WebSocketHelper::GetSocketManager()->AppendDebugData(
new DebugGLData(DebugGLData::FrameStart, nullptr, aFrameStamp));
}
void
LayerScopeAutoFrame::EndFrame()
{
if (!LayerScope::CheckSendable()) {
return;
}
WebSocketHelper::GetSocketManager()->AppendDebugData(
new DebugGLData(DebugGLData::FrameEnd, nullptr));
WebSocketHelper::GetSocketManager()->DispatchDebugData();
}
} /* layers */
} /* mozilla */

View File

@ -17,16 +17,32 @@ namespace gl { class GLContext; }
namespace layers {
struct EffectChain;
class LayerComposite;
class LayerScope {
public:
static void CreateServerSocket();
static void DestroyServerSocket();
static void BeginFrame(gl::GLContext* aGLContext, int64_t aFrameStamp);
static void EndFrame(gl::GLContext* aGLContext);
static void Init();
static void DeInit();
static void SendEffectChain(gl::GLContext* aGLContext,
const EffectChain& aEffectChain,
int aWidth, int aHeight);
int aWidth,
int aHeight);
static void SendLayer(LayerComposite* aLayer,
int aWidth,
int aHeight);
static bool CheckSendable();
static void CleanLayer();
};
// Perform BeginFrame and EndFrame automatically
class LayerScopeAutoFrame {
public:
LayerScopeAutoFrame(int64_t aFrameStamp);
~LayerScopeAutoFrame();
private:
static void BeginFrame(int64_t aFrameStamp);
static void EndFrame();
};
} /* layers */

View File

@ -87,18 +87,6 @@ CanvasLayerComposite::RenderLayer(const nsIntRect& aClipRect)
}
#endif
GraphicsFilter filter = mFilter;
#ifdef ANDROID
// Bug 691354
// Using the LINEAR filter we get unexplained artifacts.
// Use NEAREST when no scaling is required.
Matrix matrix;
bool is2D = GetEffectiveTransform().Is2D(&matrix);
if (is2D && !ThebesMatrix(matrix).HasNonTranslationOrFlip()) {
filter = GraphicsFilter::FILTER_NEAREST;
}
#endif
EffectChain effectChain(this);
AddBlendModeEffect(effectChain);
@ -108,7 +96,7 @@ CanvasLayerComposite::RenderLayer(const nsIntRect& aClipRect)
mImageHost->Composite(effectChain,
GetEffectiveOpacity(),
GetEffectiveTransform(),
gfx::ToFilter(filter),
GetEffectFilter(),
clipRect);
mImageHost->BumpFlashCounter();
}
@ -132,6 +120,30 @@ CanvasLayerComposite::CleanupResources()
mImageHost = nullptr;
}
gfx::Filter
CanvasLayerComposite::GetEffectFilter()
{
GraphicsFilter filter = mFilter;
#ifdef ANDROID
// Bug 691354
// Using the LINEAR filter we get unexplained artifacts.
// Use NEAREST when no scaling is required.
Matrix matrix;
bool is2D = GetEffectiveTransform().Is2D(&matrix);
if (is2D && !ThebesMatrix(matrix).HasNonTranslationOrFlip()) {
filter = GraphicsFilter::FILTER_NEAREST;
}
#endif
return gfx::ToFilter(filter);
}
void
CanvasLayerComposite::GenEffectChain(EffectChain& aEffect)
{
aEffect.mLayerRef = this;
aEffect.mPrimaryEffect = mImageHost->GenEffect(GetEffectFilter());
}
void
CanvasLayerComposite::PrintInfo(std::stringstream& aStream, const char* aPrefix)
{

View File

@ -52,6 +52,8 @@ public:
virtual void CleanupResources() MOZ_OVERRIDE;
virtual void GenEffectChain(EffectChain& aEffect) MOZ_OVERRIDE;
CompositableHost* GetCompositableHost() MOZ_OVERRIDE;
virtual LayerComposite* AsLayerComposite() MOZ_OVERRIDE { return this; }
@ -63,6 +65,9 @@ public:
protected:
virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix) MOZ_OVERRIDE;
private:
gfx::Filter GetEffectFilter();
private:
RefPtr<CompositableHost> mImageHost;
};

View File

@ -24,11 +24,9 @@ void
ColorLayerComposite::RenderLayer(const nsIntRect& aClipRect)
{
EffectChain effects(this);
gfxRGBA color(GetColor());
effects.mPrimaryEffect = new EffectSolidColor(gfx::Color(color.r,
color.g,
color.b,
color.a));
GenEffectChain(effects);
nsIntRect boundRect = GetBounds();
LayerManagerComposite::AutoAddMaskEffect autoMaskEffect(GetMaskLayer(),
@ -50,5 +48,16 @@ ColorLayerComposite::RenderLayer(const nsIntRect& aClipRect)
transform);
}
void
ColorLayerComposite::GenEffectChain(EffectChain& aEffect)
{
aEffect.mLayerRef = this;
gfxRGBA color(GetColor());
aEffect.mPrimaryEffect = new EffectSolidColor(gfx::Color(color.r,
color.g,
color.b,
color.a));
}
} /* layers */
} /* mozilla */

View File

@ -44,6 +44,8 @@ public:
virtual void RenderLayer(const nsIntRect& aClipRect) MOZ_OVERRIDE;
virtual void CleanupResources() MOZ_OVERRIDE {};
virtual void GenEffectChain(EffectChain& aEffect) MOZ_OVERRIDE;
CompositableHost* GetCompositableHost() MOZ_OVERRIDE { return nullptr; }
virtual LayerComposite* AsLayerComposite() MOZ_OVERRIDE { return this; }

View File

@ -17,6 +17,7 @@
#include "mozilla/gfx/Types.h" // for Filter
#include "mozilla/ipc/ProtocolUtils.h"
#include "mozilla/layers/CompositorTypes.h" // for TextureInfo, etc
#include "mozilla/layers/Effects.h" // for Texture Effect
#include "mozilla/layers/LayersTypes.h" // for LayerRenderState, etc
#include "mozilla/layers/TextureHost.h" // for TextureHost
#include "mozilla/mozalloc.h" // for operator delete
@ -289,6 +290,14 @@ public:
void SetAsyncID(uint64_t aID) { mAsyncID = aID; }
virtual bool Lock() { return false; }
virtual void Unlock() { }
virtual TemporaryRef<TexturedEffect> GenEffect(const gfx::Filter& aFilter) {
return nullptr;
}
protected:
TextureInfo mTextureInfo;
uint64_t mAsyncID;
@ -301,6 +310,29 @@ protected:
bool mKeepAttached;
};
class AutoLockCompositableHost MOZ_FINAL
{
public:
AutoLockCompositableHost(CompositableHost* aHost)
: mHost(aHost)
{
mSucceeded = mHost->Lock();
}
~AutoLockCompositableHost()
{
if (mSucceeded) {
mHost->Unlock();
}
}
bool Failed() const { return !mSucceeded; }
private:
RefPtr<CompositableHost> mHost;
bool mSucceeded;
};
/**
* Global CompositableMap, to use in the compositor thread only.
*

View File

@ -35,27 +35,6 @@ ContentHostBase::~ContentHostBase()
{
}
struct AutoLockContentHost
{
AutoLockContentHost(ContentHostBase* aHost)
: mHost(aHost)
{
mSucceeded = mHost->Lock();
}
~AutoLockContentHost()
{
if (mSucceeded) {
mHost->Unlock();
}
}
bool Failed() { return !mSucceeded; }
ContentHostBase* mHost;
bool mSucceeded;
};
void
ContentHostBase::Composite(EffectChain& aEffectChain,
float aOpacity,
@ -67,7 +46,7 @@ ContentHostBase::Composite(EffectChain& aEffectChain,
{
NS_ASSERTION(aVisibleRegion, "Requires a visible region");
AutoLockContentHost lock(this);
AutoLockCompositableHost lock(this);
if (lock.Failed()) {
return;
}
@ -78,9 +57,8 @@ ContentHostBase::Composite(EffectChain& aEffectChain,
if (!source) {
return;
}
RefPtr<TexturedEffect> effect =
CreateTexturedEffect(source, sourceOnWhite, aFilter, true);
RefPtr<TexturedEffect> effect = GenEffect(aFilter);
if (!effect) {
return;
}
@ -229,6 +207,16 @@ ContentHostBase::Composite(EffectChain& aEffectChain,
aTransform, mFlashCounter);
}
TemporaryRef<TexturedEffect>
ContentHostBase::GenEffect(const gfx::Filter& aFilter)
{
RefPtr<NewTextureSource> source = GetTextureSource();
RefPtr<NewTextureSource> sourceOnWhite = GetTextureSourceOnWhite();
if (!source) {
return nullptr;
}
return CreateTexturedEffect(source, sourceOnWhite, aFilter, true);
}
void
ContentHostTexture::UseTextureHost(TextureHost* aTexture)

View File

@ -102,12 +102,11 @@ public:
virtual void SetPaintWillResample(bool aResample) { mPaintWillResample = aResample; }
virtual bool Lock() = 0;
virtual void Unlock() = 0;
virtual NewTextureSource* GetTextureSource() = 0;
virtual NewTextureSource* GetTextureSourceOnWhite() = 0;
virtual TemporaryRef<TexturedEffect> GenEffect(const gfx::Filter& aFilter) MOZ_OVERRIDE;
protected:
virtual nsIntPoint GetOriginOffset()
{
@ -150,7 +149,7 @@ public:
virtual void UseComponentAlphaTextures(TextureHost* aTextureOnBlack,
TextureHost* aTextureOnWhite) MOZ_OVERRIDE;
virtual bool Lock() {
virtual bool Lock() MOZ_OVERRIDE {
MOZ_ASSERT(!mLocked);
if (!mTextureHost) {
return false;
@ -166,7 +165,7 @@ public:
mLocked = true;
return true;
}
virtual void Unlock() {
virtual void Unlock() MOZ_OVERRIDE {
MOZ_ASSERT(mLocked);
mTextureHost->Unlock();
if (mTextureHostOnWhite) {
@ -175,11 +174,11 @@ public:
mLocked = false;
}
virtual NewTextureSource* GetTextureSource() {
virtual NewTextureSource* GetTextureSource() MOZ_OVERRIDE {
MOZ_ASSERT(mLocked);
return mTextureHost->GetTextureSources();
}
virtual NewTextureSource* GetTextureSourceOnWhite() {
virtual NewTextureSource* GetTextureSourceOnWhite() MOZ_OVERRIDE {
MOZ_ASSERT(mLocked);
if (mTextureHostOnWhite) {
return mTextureHostOnWhite->GetTextureSources();
@ -281,20 +280,20 @@ public:
virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix) MOZ_OVERRIDE;
virtual bool Lock() {
virtual bool Lock() MOZ_OVERRIDE {
MOZ_ASSERT(!mLocked);
ProcessTextureUpdates();
mLocked = true;
return true;
}
virtual void Unlock() {
virtual void Unlock() MOZ_OVERRIDE {
MOZ_ASSERT(mLocked);
mLocked = false;
}
virtual NewTextureSource* GetTextureSource();
virtual NewTextureSource* GetTextureSourceOnWhite();
virtual NewTextureSource* GetTextureSource() MOZ_OVERRIDE;
virtual NewTextureSource* GetTextureSourceOnWhite() MOZ_OVERRIDE;
private:

View File

@ -31,6 +31,7 @@ ImageHost::ImageHost(const TextureInfo& aTextureInfo)
: CompositableHost(aTextureInfo)
, mFrontBuffer(nullptr)
, mHasPictureRect(false)
, mLocked(false)
{}
ImageHost::~ImageHost() {}
@ -81,24 +82,17 @@ ImageHost::Composite(EffectChain& aEffectChain,
mFrontBuffer->SetCompositor(GetCompositor());
mFrontBuffer->SetCompositableBackendSpecificData(GetCompositableBackendSpecificData());
AutoLockTextureHost autoLock(mFrontBuffer);
AutoLockCompositableHost autoLock(this);
if (autoLock.Failed()) {
NS_WARNING("failed to lock front buffer");
return;
}
RefPtr<NewTextureSource> source = mFrontBuffer->GetTextureSources();
RefPtr<NewTextureSource> source = GetTextureSource();
if (!source) {
return;
}
bool isAlphaPremultiplied = true;
if (mFrontBuffer->GetFlags() & TextureFlags::NON_PREMULTIPLIED)
isAlphaPremultiplied = false;
RefPtr<TexturedEffect> effect = CreateTexturedEffect(mFrontBuffer->GetFormat(),
source,
aFilter,
isAlphaPremultiplied);
RefPtr<TexturedEffect> effect = GenEffect(aFilter);
if (!effect) {
return;
}
@ -243,5 +237,48 @@ ImageHost::GetAsSurface()
}
#endif
bool
ImageHost::Lock()
{
MOZ_ASSERT(!mLocked);
if (!mFrontBuffer->Lock()) {
return false;
}
mLocked = true;
return true;
}
void
ImageHost::Unlock()
{
MOZ_ASSERT(mLocked);
mFrontBuffer->Unlock();
mLocked = false;
}
TemporaryRef<NewTextureSource>
ImageHost::GetTextureSource()
{
MOZ_ASSERT(mLocked);
return mFrontBuffer->GetTextureSources();
}
TemporaryRef<TexturedEffect>
ImageHost::GenEffect(const gfx::Filter& aFilter)
{
RefPtr<NewTextureSource> source = GetTextureSource();
if (!source) {
return nullptr;
}
bool isAlphaPremultiplied = true;
if (mFrontBuffer->GetFlags() & TextureFlags::NON_PREMULTIPLIED)
isAlphaPremultiplied = false;
return CreateTexturedEffect(mFrontBuffer->GetFormat(),
source,
aFilter,
isAlphaPremultiplied);
}
}
}

View File

@ -79,11 +79,20 @@ public:
virtual TemporaryRef<gfx::DataSourceSurface> GetAsSurface() MOZ_OVERRIDE;
#endif
virtual bool Lock() MOZ_OVERRIDE;
virtual void Unlock() MOZ_OVERRIDE;
virtual TemporaryRef<NewTextureSource> GetTextureSource();
virtual TemporaryRef<TexturedEffect> GenEffect(const gfx::Filter& aFilter) MOZ_OVERRIDE;
protected:
RefPtr<TextureHost> mFrontBuffer;
nsIntRect mPictureRect;
bool mHasPictureRect;
bool mLocked;
};
}

View File

@ -107,7 +107,7 @@ ImageLayerComposite::RenderLayer(const nsIntRect& aClipRect)
mImageHost->Composite(effectChain,
GetEffectiveOpacity(),
GetEffectiveTransform(),
gfx::ToFilter(mFilter),
GetEffectFilter(),
clipRect);
mImageHost->BumpFlashCounter();
}
@ -161,6 +161,19 @@ ImageLayerComposite::CleanupResources()
mImageHost = nullptr;
}
gfx::Filter
ImageLayerComposite::GetEffectFilter()
{
return gfx::ToFilter(mFilter);
}
void
ImageLayerComposite::GenEffectChain(EffectChain& aEffect)
{
aEffect.mLayerRef = this;
aEffect.mPrimaryEffect = mImageHost->GenEffect(GetEffectFilter());
}
void
ImageLayerComposite::PrintInfo(std::stringstream& aStream, const char* aPrefix)
{

View File

@ -51,6 +51,8 @@ public:
CompositableHost* GetCompositableHost() MOZ_OVERRIDE;
virtual void GenEffectChain(EffectChain& aEffect) MOZ_OVERRIDE;
virtual LayerComposite* AsLayerComposite() MOZ_OVERRIDE { return this; }
virtual const char* Name() const { return "ImageLayerComposite"; }
@ -58,6 +60,9 @@ public:
protected:
virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix) MOZ_OVERRIDE;
private:
gfx::Filter GetEffectFilter();
private:
RefPtr<CompositableHost> mImageHost;
};

View File

@ -16,6 +16,7 @@
#include "GeckoProfiler.h" // for profiler_set_frame_number, etc
#include "ImageLayerComposite.h" // for ImageLayerComposite
#include "Layers.h" // for Layer, ContainerLayer, etc
#include "LayerScope.h" // for LayerScope Tool
#include "ThebesLayerComposite.h" // for ThebesLayerComposite
#include "TiledLayerBuffer.h" // for TiledLayerComposer
#include "Units.h" // for ScreenIntRect
@ -417,6 +418,9 @@ LayerManagerComposite::Render()
/** Our more efficient but less powerful alter ego, if one is available. */
nsRefPtr<Composer2D> composer2D = mCompositor->GetWidget()->GetComposer2D();
// Set LayerScope begin/end frame
LayerScopeAutoFrame frame(PR_Now());
if (!mTarget && composer2D && composer2D->TryRender(mRoot, mWorldMatrix, mGeometryChanged)) {
if (mFPS) {
double fps = mFPS->mCompositionFps.AddFrameAndGetFps(TimeStamp::Now());

View File

@ -74,7 +74,7 @@ class LayerManagerComposite : public LayerManager
public:
LayerManagerComposite(Compositor* aCompositor);
~LayerManagerComposite();
virtual void Destroy() MOZ_OVERRIDE;
/**
@ -267,7 +267,7 @@ private:
RefPtr<Compositor> mCompositor;
nsAutoPtr<LayerProperties> mClonedLayerTreeProperties;
/**
/**
* Context target, nullptr when drawing directly to our swap chain.
*/
RefPtr<gfx::DrawTarget> mTarget;
@ -336,11 +336,12 @@ public:
virtual TiledLayerComposer* GetTiledLayerComposer() { return nullptr; }
virtual void DestroyFrontBuffer() { }
void AddBlendModeEffect(EffectChain& aEffectChain);
virtual void GenEffectChain(EffectChain& aEffect) { }
/**
* The following methods are
*

View File

@ -147,7 +147,7 @@ ThebesLayerComposite::RenderLayer(const nsIntRect& aClipRect)
mBuffer->Composite(effectChain,
GetEffectiveOpacity(),
GetEffectiveTransform(),
gfx::Filter::LINEAR,
GetEffectFilter(),
clipRect,
&visibleRegion,
mRequiresTiledProperties ? &tiledLayerProps
@ -180,6 +180,13 @@ ThebesLayerComposite::CleanupResources()
mBuffer = nullptr;
}
void
ThebesLayerComposite::GenEffectChain(EffectChain& aEffect)
{
aEffect.mLayerRef = this;
aEffect.mPrimaryEffect = mBuffer->GenEffect(GetEffectFilter());
}
CSSToScreenScale
ThebesLayerComposite::GetEffectiveResolution()
{

View File

@ -56,6 +56,8 @@ public:
virtual void CleanupResources() MOZ_OVERRIDE;
virtual void GenEffectChain(EffectChain& aEffect) MOZ_OVERRIDE;
virtual bool SetCompositableHost(CompositableHost* aHost) MOZ_OVERRIDE;
virtual LayerComposite* AsLayerComposite() MOZ_OVERRIDE { return this; }
@ -81,8 +83,11 @@ protected:
virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix) MOZ_OVERRIDE;
private:
gfx::Filter GetEffectFilter() { return gfx::Filter::LINEAR; }
CSSToScreenScale GetEffectiveResolution();
private:
RefPtr<ContentHost> mBuffer;
bool mRequiresTiledProperties;
};

View File

@ -706,8 +706,6 @@ CompositorOGL::BeginFrame(const nsIntRegion& aInvalidRegion,
MOZ_ASSERT(!mFrameInProgress, "frame still in progress (should have called EndFrame or AbortFrame");
LayerScope::BeginFrame(mGLContext, PR_Now());
mFrameInProgress = true;
gfx::Rect rect;
if (mUseExternalSurfaceSize) {
@ -1313,8 +1311,6 @@ CompositorOGL::EndFrame()
mFrameInProgress = false;
LayerScope::EndFrame(mGLContext);
if (mTarget) {
CopyToTarget(mTarget, mTargetBounds.TopLeft(), mCurrentRenderTarget->GetTransform());
mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);

View File

@ -37,11 +37,6 @@ class PBackgroundChild;
// (assuming success) GetForCurrentThread() will return the same actor every
// time.
//
// CloseForCurrentThread() will close the current PBackground actor. Subsequent
// calls to GetForCurrentThread will return null. CloseForCurrentThread() may
// only be called exactly once per thread. Currently it is illegal to call this
// before the PBackground actor has been created.
//
// The PBackgroundChild actor and all its sub-protocol actors will be
// automatically destroyed when its designated thread completes.
class BackgroundChild MOZ_FINAL
@ -61,10 +56,6 @@ public:
static bool
GetOrCreateForCurrentThread(nsIIPCBackgroundChildCreateCallback* aCallback);
// See above.
static void
CloseForCurrentThread();
private:
// Only called by ContentChild or ContentParent.
static void

View File

@ -350,8 +350,6 @@ class ChildImpl MOZ_FINAL : public BackgroundChildImpl
nsIThread* mBoundThread;
#endif
DebugOnly<bool> mActorDestroyed;
public:
static bool
OpenProtocolOnMainThread(nsIEventTarget* aEventTarget);
@ -374,15 +372,8 @@ public:
THREADSAFETY_ASSERT(current);
}
void
AssertActorDestroyed()
{
MOZ_ASSERT(mActorDestroyed, "ChildImpl::ActorDestroy not called in time");
}
ChildImpl()
: mBoundThread(nullptr)
, mActorDestroyed(false)
{
AssertIsOnMainThread();
}
@ -406,10 +397,6 @@ private:
static bool
GetOrCreateForCurrentThread(nsIIPCBackgroundChildCreateCallback* aCallback);
// Forwarded from BackgroundChild.
static void
CloseForCurrentThread();
// Forwarded from BackgroundChildImpl.
static BackgroundChildImpl::ThreadLocal*
GetThreadLocalForCurrentThread();
@ -422,17 +409,6 @@ private:
if (threadLocalInfo) {
if (threadLocalInfo->mActor) {
threadLocalInfo->mActor->Close();
threadLocalInfo->mActor->AssertActorDestroyed();
// Since the actor is created on the main thread it must only
// be released on the main thread as well.
if (!NS_IsMainThread()) {
ChildImpl* actor;
threadLocalInfo->mActor.forget(&actor);
nsCOMPtr<nsIRunnable> releaser =
NS_NewNonOwningRunnableMethod(actor, &ChildImpl::Release);
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(releaser)));
}
}
delete threadLocalInfo;
}
@ -443,9 +419,7 @@ private:
// This class is reference counted.
~ChildImpl()
{
AssertActorDestroyed();
}
{ }
void
SetBoundThread()
@ -861,13 +835,6 @@ BackgroundChild::GetOrCreateForCurrentThread(
return ChildImpl::GetOrCreateForCurrentThread(aCallback);
}
// static
void
BackgroundChild::CloseForCurrentThread()
{
ChildImpl::CloseForCurrentThread();
}
// -----------------------------------------------------------------------------
// BackgroundChildImpl Public Methods
// -----------------------------------------------------------------------------
@ -1611,11 +1578,7 @@ ChildImpl::GetForCurrentThread()
auto threadLocalInfo =
static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(sThreadLocalIndex));
if (!threadLocalInfo) {
return nullptr;
}
return threadLocalInfo->mActor;
return threadLocalInfo ? threadLocalInfo->mActor : nullptr;
}
// static
@ -1679,31 +1642,6 @@ ChildImpl::GetOrCreateForCurrentThread(
return true;
}
// static
void
ChildImpl::CloseForCurrentThread()
{
MOZ_ASSERT(sThreadLocalIndex != kBadThreadLocalIndex,
"BackgroundChild::Startup() was never called!");
auto threadLocalInfo =
static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(sThreadLocalIndex));
// If we don't have a thread local we are in one of these conditions:
// 1) Startup has not completed and we are racing
// 2) We were called again after a previous close or shutdown
// For now, these should not happen, so crash. We can add extra complexity
// in the future if it turns out we need to support these cases.
if (!threadLocalInfo) {
MOZ_CRASH("Attempting to close a non-existent PBackground actor!");
}
if (threadLocalInfo->mActor) {
threadLocalInfo->mActor->FlushPendingInterruptQueue();
}
DebugOnly<PRStatus> status = PR_SetThreadPrivate(sThreadLocalIndex, nullptr);
MOZ_ASSERT(status == PR_SUCCESS);
}
// static
BackgroundChildImpl::ThreadLocal*
ChildImpl::GetThreadLocalForCurrentThread()
@ -2008,7 +1946,6 @@ ChildImpl::ActorDestroy(ActorDestroyReason aWhy)
{
AssertIsOnBoundThread();
mActorDestroyed = true;
BackgroundChildImpl::ActorDestroy(aWhy);
}

View File

@ -7,13 +7,11 @@
#include "nsIRunnable.h"
#include "nsIThread.h"
#include "nsITimer.h"
#include "nsICancelableRunnable.h"
#include "base/basictypes.h"
#include "base/logging.h"
#include "base/scoped_nsautorelease_pool.h"
#include "mozilla/Assertions.h"
#include "mozilla/AutoRestore.h"
#include "mozilla/DebugOnly.h"
#include "nsComponentManagerUtils.h"
#include "nsDebug.h"
@ -42,14 +40,12 @@ static mozilla::DebugOnly<MessagePump::Delegate*> gFirstDelegate;
namespace mozilla {
namespace ipc {
class DoWorkRunnable MOZ_FINAL : public nsICancelableRunnable,
class DoWorkRunnable MOZ_FINAL : public nsIRunnable,
public nsITimerCallback
{
public:
DoWorkRunnable(MessagePump* aPump)
: mPump(aPump)
, mCanceled(false)
, mCallingRunWhileCanceled(false)
{
MOZ_ASSERT(aPump);
}
@ -57,15 +53,12 @@ public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIRUNNABLE
NS_DECL_NSITIMERCALLBACK
NS_DECL_NSICANCELABLERUNNABLE
private:
~DoWorkRunnable()
{ }
MessagePump* mPump;
bool mCanceled;
bool mCallingRunWhileCanceled;
};
} /* namespace ipc */
@ -218,17 +211,11 @@ MessagePump::DoDelayedWork(base::MessagePump::Delegate* aDelegate)
}
}
NS_IMPL_ISUPPORTS(DoWorkRunnable, nsIRunnable, nsITimerCallback,
nsICancelableRunnable)
NS_IMPL_ISUPPORTS(DoWorkRunnable, nsIRunnable, nsITimerCallback)
NS_IMETHODIMP
DoWorkRunnable::Run()
{
MOZ_ASSERT(!mCanceled || mCallingRunWhileCanceled);
if (mCanceled && !mCallingRunWhileCanceled) {
return NS_OK;
}
MessageLoop* loop = MessageLoop::current();
MOZ_ASSERT(loop);
@ -255,23 +242,6 @@ DoWorkRunnable::Notify(nsITimer* aTimer)
return NS_OK;
}
NS_IMETHODIMP
DoWorkRunnable::Cancel()
{
MOZ_ASSERT(!mCanceled);
MOZ_ASSERT(!mCallingRunWhileCanceled);
// Workers require cancelable runnables, but we can't really cancel cleanly
// here. If we don't process all of these then we will leave something
// unprocessed in the chromium queue. Therefore, eagerly complete our work
// instead by immediately calling Run().
mCanceled = true;
mozilla::AutoRestore<bool> guard(mCallingRunWhileCanceled);
mCallingRunWhileCanceled = true;
Run();
return NS_OK;
}
void
MessagePumpForChildProcess::Run(base::MessagePump::Delegate* aDelegate)
{

View File

@ -31,7 +31,6 @@
#include "nsStyleUtil.h"
#include "mozilla/css/Declaration.h"
#include "nsCSSParser.h"
#include "nsPrintfCString.h"
#include "nsDOMClassInfoID.h"
#include "mozilla/dom/CSSStyleDeclarationBinding.h"
#include "StyleRule.h"
@ -1408,52 +1407,6 @@ AppendSerializedFontSrc(const nsCSSValue& src, nsAString & aResult)
aResult.Truncate(aResult.Length() - 2); // remove the last comma-space
}
// print all characters with at least four hex digits
static void
AppendSerializedUnicodePoint(uint32_t aCode, nsACString &aBuf)
{
aBuf.Append(nsPrintfCString("%04X", aCode));
}
// A unicode-range: descriptor is represented as an array of integers,
// to be interpreted as a sequence of pairs: min max min max ...
// It is in source order. (Possibly it should be sorted and overlaps
// consolidated, but right now we don't do that.)
static void
AppendSerializedUnicodeRange(nsCSSValue const & aValue,
nsAString & aResult)
{
NS_PRECONDITION(aValue.GetUnit() == eCSSUnit_Null ||
aValue.GetUnit() == eCSSUnit_Array,
"improper value unit for unicode-range:");
aResult.Truncate();
if (aValue.GetUnit() != eCSSUnit_Array)
return;
nsCSSValue::Array const & sources = *aValue.GetArrayValue();
nsAutoCString buf;
NS_ABORT_IF_FALSE(sources.Count() % 2 == 0,
"odd number of entries in a unicode-range: array");
for (uint32_t i = 0; i < sources.Count(); i += 2) {
uint32_t min = sources[i].GetIntValue();
uint32_t max = sources[i+1].GetIntValue();
// We don't try to replicate the U+XX?? notation.
buf.AppendLiteral("U+");
AppendSerializedUnicodePoint(min, buf);
if (min != max) {
buf.Append('-');
AppendSerializedUnicodePoint(max, buf);
}
buf.AppendLiteral(", ");
}
buf.Truncate(buf.Length() - 2); // remove the last comma-space
CopyASCIItoUTF16(buf, aResult);
}
// Mapping from nsCSSFontDesc codes to nsCSSFontFaceStyleDecl fields.
nsCSSValue nsCSSFontFaceStyleDecl::* const
nsCSSFontFaceStyleDecl::Fields[] = {
@ -1539,7 +1492,7 @@ nsCSSFontFaceStyleDecl::GetPropertyValue(nsCSSFontDesc aFontDescID,
return NS_OK;
case eCSSFontDesc_UnicodeRange:
AppendSerializedUnicodeRange(val, aResult);
nsStyleUtil::AppendUnicodeRange(val, aResult);
return NS_OK;
case eCSSFontDesc_UNKNOWN:

View File

@ -13,6 +13,7 @@
#include "nsIContentPolicy.h"
#include "nsIContentSecurityPolicy.h"
#include "nsIURI.h"
#include "nsPrintfCString.h"
using namespace mozilla;
@ -461,6 +462,51 @@ nsStyleUtil::ComputeFunctionalAlternates(const nsCSSValueList* aList,
}
}
// print all characters with at least four hex digits
static void
AppendSerializedUnicodePoint(uint32_t aCode, nsACString& aBuf)
{
aBuf.Append(nsPrintfCString("%04X", aCode));
}
// A unicode-range: descriptor is represented as an array of integers,
// to be interpreted as a sequence of pairs: min max min max ...
// It is in source order. (Possibly it should be sorted and overlaps
// consolidated, but right now we don't do that.)
/* static */ void
nsStyleUtil::AppendUnicodeRange(const nsCSSValue& aValue, nsAString& aResult)
{
NS_PRECONDITION(aValue.GetUnit() == eCSSUnit_Null ||
aValue.GetUnit() == eCSSUnit_Array,
"improper value unit for unicode-range:");
aResult.Truncate();
if (aValue.GetUnit() != eCSSUnit_Array)
return;
nsCSSValue::Array const & sources = *aValue.GetArrayValue();
nsAutoCString buf;
NS_ABORT_IF_FALSE(sources.Count() % 2 == 0,
"odd number of entries in a unicode-range: array");
for (uint32_t i = 0; i < sources.Count(); i += 2) {
uint32_t min = sources[i].GetIntValue();
uint32_t max = sources[i+1].GetIntValue();
// We don't try to replicate the U+XX?? notation.
buf.AppendLiteral("U+");
AppendSerializedUnicodePoint(min, buf);
if (min != max) {
buf.Append('-');
AppendSerializedUnicodePoint(max, buf);
}
buf.AppendLiteral(", ");
}
buf.Truncate(buf.Length() - 2); // remove the last comma-space
CopyASCIItoUTF16(buf, aResult);
}
/* static */ float
nsStyleUtil::ColorComponentToFloat(uint8_t aAlpha)
{

View File

@ -64,6 +64,8 @@ public:
static void AppendFontFeatureSettings(const nsCSSValue& src,
nsAString& aResult);
static void AppendUnicodeRange(const nsCSSValue& aValue, nsAString& aResult);
static void AppendCSSNumber(float aNumber, nsAString& aResult)
{
aResult.AppendFloat(aNumber);

View File

@ -290,7 +290,9 @@
</intent-filter>
</receiver>
<receiver android:name="org.mozilla.gecko.ReferrerReceiver" android:exported="true">
<!-- Catch install referrer so we can do post-install work. -->
<receiver android:name="org.mozilla.gecko.distribution.ReferrerReceiver"
android:exported="true">
<intent-filter>
<action android:name="com.android.vending.INSTALL_REFERRER" />
</intent-filter>

View File

@ -200,6 +200,13 @@ public final class GeckoProfile {
getGuestDir(context).mkdir();
GeckoProfile profile = getGuestProfile(context);
profile.lock();
/*
* Now do the things that createProfileDirectory normally does --
* right now that's kicking off DB init.
*/
profile.enqueueInitialization();
return profile;
} catch (Exception ex) {
Log.e(LOGTAG, "Error creating guest profile", ex);

View File

@ -1,62 +0,0 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* 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/. */
package org.mozilla.gecko;
import org.json.JSONException;
import org.json.JSONObject;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import java.net.URLDecoder;
import java.util.HashMap;
public class ReferrerReceiver
extends BroadcastReceiver
{
private static final String LOGTAG = "GeckoReferrerReceiver";
public static final String ACTION_INSTALL_REFERRER = "com.android.vending.INSTALL_REFERRER";
public static final String UTM_SOURCE = "mozilla";
@Override
public void onReceive(Context context, Intent intent) {
if (ACTION_INSTALL_REFERRER.equals(intent.getAction())) {
String referrer = intent.getStringExtra("referrer");
if (referrer == null)
return;
HashMap<String, String> values = new HashMap<String, String>();
try {
String referrers[] = referrer.split("&");
for (String referrerValue : referrers) {
String keyValue[] = referrerValue.split("=");
values.put(URLDecoder.decode(keyValue[0]), URLDecoder.decode(keyValue[1]));
}
} catch (Exception e) {
}
String source = values.get("utm_source");
String campaign = values.get("utm_campaign");
if (source != null && UTM_SOURCE.equals(source) && campaign != null) {
try {
JSONObject data = new JSONObject();
data.put("id", "playstore");
data.put("version", campaign);
// Try to make sure the prefs are written as a group
GeckoEvent event = GeckoEvent.createBroadcastEvent("Campaign:Set", data.toString());
GeckoAppShell.sendEventToGecko(event);
} catch (JSONException e) {
Log.e(LOGTAG, "Error setting distribution", e);
}
}
}
}
}

View File

@ -5,12 +5,19 @@
package org.mozilla.gecko.distribution;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.ProtocolException;
import java.net.SocketException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.UnknownHostException;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
@ -19,34 +26,95 @@ import java.util.Map;
import java.util.Queue;
import java.util.Scanner;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import javax.net.ssl.SSLException;
import org.apache.http.protocol.HTTP;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.GeckoEvent;
import org.mozilla.gecko.GeckoSharedPrefs;
import org.mozilla.gecko.Telemetry;
import org.mozilla.gecko.mozglue.RobocopTarget;
import org.mozilla.gecko.util.ThreadUtils;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.SystemClock;
import android.util.Log;
/**
* Handles distribution file loading and fetching,
* and the corresponding hand-offs to Gecko.
*/
public final class Distribution {
@RobocopTarget
public class Distribution {
private static final String LOGTAG = "GeckoDistribution";
private static final int STATE_UNKNOWN = 0;
private static final int STATE_NONE = 1;
private static final int STATE_SET = 2;
private static final String FETCH_PROTOCOL = "https";
private static final String FETCH_HOSTNAME = "distro-download.cdn.mozilla.net";
private static final String FETCH_PATH = "/android/1/";
private static final String FETCH_EXTENSION = ".jar";
private static final String EXPECTED_CONTENT_TYPE = "application/java-archive";
private static final String DISTRIBUTION_PATH = "distribution/";
/**
* Telemetry constants.
*/
private static final String HISTOGRAM_REFERRER_INVALID = "FENNEC_DISTRIBUTION_REFERRER_INVALID";
private static final String HISTOGRAM_DOWNLOAD_TIME_MS = "FENNEC_DISTRIBUTION_DOWNLOAD_TIME_MS";
private static final String HISTOGRAM_CODE_CATEGORY = "FENNEC_DISTRIBUTION_CODE_CATEGORY";
/**
* Success/failure codes. Don't exceed the maximum listed in Histograms.json.
*/
private static final int CODE_CATEGORY_STATUS_OUT_OF_RANGE = 0;
// HTTP status 'codes' run from 1 to 5.
private static final int CODE_CATEGORY_OFFLINE = 6;
private static final int CODE_CATEGORY_FETCH_EXCEPTION = 7;
// It's a post-fetch exception if we were able to download, but not
// able to extract.
private static final int CODE_CATEGORY_POST_FETCH_EXCEPTION = 8;
private static final int CODE_CATEGORY_POST_FETCH_SECURITY_EXCEPTION = 9;
// It's a malformed distribution if we could extract, but couldn't
// process the contents.
private static final int CODE_CATEGORY_MALFORMED_DISTRIBUTION = 10;
// Specific fetch errors.
private static final int CODE_CATEGORY_FETCH_SOCKET_ERROR = 11;
private static final int CODE_CATEGORY_FETCH_SSL_ERROR = 12;
private static final int CODE_CATEGORY_FETCH_NON_SUCCESS_RESPONSE = 13;
private static final int CODE_CATEGORY_FETCH_INVALID_CONTENT_TYPE = 14;
// Corresponds to the high value in Histograms.json.
private static final long MAX_DOWNLOAD_TIME_MSEC = 40000; // 40 seconds.
/**
* Used as a drop-off point for ReferrerReceiver. Checked when we process
* first-run distribution.
*
* This is `protected` so that test code can clear it between runs.
*/
@RobocopTarget
protected static volatile ReferrerDescriptor referrer;
private static Distribution instance;
private final Context context;
@ -70,6 +138,7 @@ public final class Distribution {
return instance;
}
@RobocopTarget
public static class DistributionDescriptor {
public final boolean valid;
public final String id;
@ -140,6 +209,7 @@ public final class Distribution {
* Use <code>Context.getPackageResourcePath</code> to find an implicit
* package path. Reuses the existing Distribution if one exists.
*/
@RobocopTarget
public static void init(final Context context) {
Distribution.init(Distribution.getInstance(context));
}
@ -166,6 +236,17 @@ public final class Distribution {
this(context, context.getPackageResourcePath(), null);
}
/**
* This method is called by ReferrerReceiver when we receive a post-install
* notification from Google Play.
*
* @param ref a parsed referrer value from the store-supplied intent.
*/
public static void onReceivedReferrer(ReferrerDescriptor ref) {
// Track the referrer object for distribution handling.
referrer = ref;
}
/**
* Helper to grab a file in the distribution directory.
*
@ -214,9 +295,11 @@ public final class Distribution {
} catch (IOException e) {
Log.e(LOGTAG, "Error getting distribution descriptor file.", e);
Telemetry.HistogramAdd(HISTOGRAM_CODE_CATEGORY, CODE_CATEGORY_MALFORMED_DISTRIBUTION);
return null;
} catch (JSONException e) {
Log.e(LOGTAG, "Error parsing preferences.json", e);
Telemetry.HistogramAdd(HISTOGRAM_CODE_CATEGORY, CODE_CATEGORY_MALFORMED_DISTRIBUTION);
return null;
}
}
@ -232,11 +315,13 @@ public final class Distribution {
return new JSONArray(getFileContents(bookmarks));
} catch (IOException e) {
Log.e(LOGTAG, "Error getting bookmarks", e);
Telemetry.HistogramAdd(HISTOGRAM_CODE_CATEGORY, CODE_CATEGORY_MALFORMED_DISTRIBUTION);
return null;
} catch (JSONException e) {
Log.e(LOGTAG, "Error parsing bookmarks.json", e);
Telemetry.HistogramAdd(HISTOGRAM_CODE_CATEGORY, CODE_CATEGORY_MALFORMED_DISTRIBUTION);
return null;
}
return null;
}
/**
@ -245,9 +330,12 @@ public final class Distribution {
* Postcondition: if this returns true, distributionDir will have been
* set and populated.
*
* This method is *only* protected for use from testDistribution.
*
* @return true if we've set a distribution.
*/
private boolean doInit() {
@RobocopTarget
protected boolean doInit() {
ThreadUtils.assertNotOnUiThread();
// Bail if we've already tried to initialize the distribution, and
@ -274,8 +362,9 @@ public final class Distribution {
return true;
}
// We try the APK, then the system directory.
// We try the install intent, then the APK, then the system directory.
final boolean distributionSet =
checkIntentDistribution() ||
checkAPKDistribution() ||
checkSystemDistribution();
@ -286,6 +375,153 @@ public final class Distribution {
return distributionSet;
}
/**
* If applicable, download and select the distribution specified in
* the referrer intent.
*
* @return true if a referrer-supplied distribution was selected.
*/
private boolean checkIntentDistribution() {
if (referrer == null) {
return false;
}
URI uri = getReferredDistribution(referrer);
if (uri == null) {
return false;
}
long start = SystemClock.uptimeMillis();
Log.v(LOGTAG, "Downloading referred distribution: " + uri);
try {
HttpURLConnection connection = (HttpURLConnection) uri.toURL().openConnection();
connection.setRequestProperty(HTTP.USER_AGENT, GeckoAppShell.getGeckoInterface().getDefaultUAString());
connection.setRequestProperty("Accept", EXPECTED_CONTENT_TYPE);
try {
final JarInputStream distro;
try {
distro = fetchDistribution(uri, connection);
} catch (Exception e) {
Log.e(LOGTAG, "Error fetching distribution from network.", e);
recordFetchTelemetry(e);
return false;
}
long end = SystemClock.uptimeMillis();
final long duration = end - start;
Log.d(LOGTAG, "Distro fetch took " + duration + "ms; result? " + (distro != null));
Telemetry.HistogramAdd(HISTOGRAM_DOWNLOAD_TIME_MS, clamp(MAX_DOWNLOAD_TIME_MSEC, duration));
if (distro == null) {
// Nothing to do.
return false;
}
// Try to copy distribution files from the fetched stream.
try {
Log.d(LOGTAG, "Copying files from fetched zip.");
if (copyFilesFromStream(distro)) {
// We always copy to the data dir, and we only copy files from
// a 'distribution' subdirectory. Track our dist dir now that
// we know it.
this.distributionDir = new File(getDataDir(), DISTRIBUTION_PATH);
return true;
}
} catch (SecurityException e) {
Log.e(LOGTAG, "Security exception copying files. Corrupt or malicious?", e);
Telemetry.HistogramAdd(HISTOGRAM_CODE_CATEGORY, CODE_CATEGORY_POST_FETCH_SECURITY_EXCEPTION);
} catch (Exception e) {
Log.e(LOGTAG, "Error copying files from distribution.", e);
Telemetry.HistogramAdd(HISTOGRAM_CODE_CATEGORY, CODE_CATEGORY_POST_FETCH_EXCEPTION);
} finally {
distro.close();
}
} finally {
connection.disconnect();
}
} catch (IOException e) {
Log.e(LOGTAG, "Error copying distribution files from network.", e);
recordFetchTelemetry(e);
}
return false;
}
private static final int clamp(long v, long c) {
return (int) Math.min(c, v);
}
/**
* Fetch the provided URI, returning a {@link JarInputStream} if the response body
* is appropriate.
*
* Protected to allow for mocking.
*
* @return the entity body as a stream, or null on failure.
*/
@SuppressWarnings("static-method")
@RobocopTarget
protected JarInputStream fetchDistribution(URI uri, HttpURLConnection connection) throws IOException {
final int status = connection.getResponseCode();
Log.d(LOGTAG, "Distribution fetch: " + status);
// We record HTTP statuses as 2xx, 3xx, 4xx, 5xx => 2, 3, 4, 5.
final int value;
if (status > 599 || status < 100) {
Log.wtf(LOGTAG, "Unexpected HTTP status code: " + status);
value = CODE_CATEGORY_STATUS_OUT_OF_RANGE;
} else {
value = status / 100;
}
Telemetry.HistogramAdd(HISTOGRAM_CODE_CATEGORY, value);
if (status != 200) {
Log.w(LOGTAG, "Got status " + status + " fetching distribution.");
Telemetry.HistogramAdd(HISTOGRAM_CODE_CATEGORY, CODE_CATEGORY_FETCH_NON_SUCCESS_RESPONSE);
return null;
}
final String contentType = connection.getContentType();
if (contentType == null || !contentType.startsWith(EXPECTED_CONTENT_TYPE)) {
Log.w(LOGTAG, "Malformed response: invalid Content-Type.");
Telemetry.HistogramAdd(HISTOGRAM_CODE_CATEGORY, CODE_CATEGORY_FETCH_INVALID_CONTENT_TYPE);
return null;
}
return new JarInputStream(new BufferedInputStream(connection.getInputStream()), true);
}
private static void recordFetchTelemetry(final Exception exception) {
if (exception == null) {
// Should never happen.
Telemetry.HistogramAdd(HISTOGRAM_CODE_CATEGORY, CODE_CATEGORY_FETCH_EXCEPTION);
return;
}
if (exception instanceof UnknownHostException) {
// Unknown host => we're offline.
Telemetry.HistogramAdd(HISTOGRAM_CODE_CATEGORY, CODE_CATEGORY_OFFLINE);
return;
}
if (exception instanceof SSLException) {
Telemetry.HistogramAdd(HISTOGRAM_CODE_CATEGORY, CODE_CATEGORY_FETCH_SSL_ERROR);
return;
}
if (exception instanceof ProtocolException ||
exception instanceof SocketException) {
Telemetry.HistogramAdd(HISTOGRAM_CODE_CATEGORY, CODE_CATEGORY_FETCH_SOCKET_ERROR);
return;
}
Telemetry.HistogramAdd(HISTOGRAM_CODE_CATEGORY, CODE_CATEGORY_FETCH_EXCEPTION);
}
/**
* Execute tasks that wanted to run when we were done loading
* the distribution. These tasks are expected to call {@link #exists()}
@ -308,7 +544,7 @@ public final class Distribution {
// We always copy to the data dir, and we only copy files from
// a 'distribution' subdirectory. Track our dist dir now that
// we know it.
this.distributionDir = new File(getDataDir(), "distribution/");
this.distributionDir = new File(getDataDir(), DISTRIBUTION_PATH);
return true;
}
} catch (IOException e) {
@ -330,6 +566,41 @@ public final class Distribution {
return false;
}
/**
* Unpack distribution files from a downloaded jar stream.
*
* The caller is responsible for closing the provided stream.
*/
private boolean copyFilesFromStream(JarInputStream jar) throws FileNotFoundException, IOException {
final byte[] buffer = new byte[1024];
boolean distributionSet = false;
JarEntry entry;
while ((entry = jar.getNextJarEntry()) != null) {
final String name = entry.getName();
if (entry.isDirectory()) {
// We'll let getDataFile deal with creating the directory hierarchy.
// Yes, we can do better, but it can wait.
continue;
}
if (!name.startsWith(DISTRIBUTION_PATH)) {
continue;
}
File outFile = getDataFile(name);
if (outFile == null) {
continue;
}
distributionSet = true;
writeStream(jar, outFile, entry.getTime(), buffer);
}
return distributionSet;
}
/**
* Copies the /distribution folder out of the APK and into the app's data directory.
* Returns true if distribution files were found and copied.
@ -352,7 +623,7 @@ public final class Distribution {
continue;
}
if (!name.startsWith("distribution/")) {
if (!name.startsWith(DISTRIBUTION_PATH)) {
continue;
}
@ -413,6 +684,29 @@ public final class Distribution {
return outFile;
}
private URI getReferredDistribution(ReferrerDescriptor descriptor) {
final String content = descriptor.content;
if (content == null) {
return null;
}
// We restrict here to avoid injection attacks. After all,
// we're downloading a distribution payload based on intent input.
if (!content.matches("^[a-zA-Z0-9]+$")) {
Log.e(LOGTAG, "Invalid referrer content: " + content);
Telemetry.HistogramAdd(HISTOGRAM_REFERRER_INVALID, 1);
return null;
}
try {
return new URI(FETCH_PROTOCOL, FETCH_HOSTNAME, FETCH_PATH + content + FETCH_EXTENSION, null);
} catch (URISyntaxException e) {
// This should never occur.
Log.wtf(LOGTAG, "Invalid URI with content " + content + "!");
return null;
}
}
/**
* After calling this method, either <code>distributionDir</code>
* will be set, or there is no distribution in use.
@ -432,7 +726,7 @@ public final class Distribution {
// the APK, or it exists in /system/.
// Look in each location in turn.
// (This could be optimized by caching the path in shared prefs.)
File copied = new File(getDataDir(), "distribution/");
File copied = new File(getDataDir(), DISTRIBUTION_PATH);
if (copied.exists()) {
return this.distributionDir = copied;
}

View File

@ -0,0 +1,55 @@
/* 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/. */
package org.mozilla.gecko.distribution;
import org.mozilla.gecko.mozglue.RobocopTarget;
import android.net.Uri;
/**
* Encapsulates access to values encoded in the "referrer" extra of an install intent.
*
* This object is immutable.
*
* Example input:
*
* "utm_source=campsource&utm_medium=campmed&utm_term=term%2Bhere&utm_content=content&utm_campaign=name"
*/
@RobocopTarget
public class ReferrerDescriptor {
public final String source;
public final String medium;
public final String term;
public final String content;
public final String campaign;
public ReferrerDescriptor(final String referrer) {
if (referrer == null) {
source = null;
medium = null;
term = null;
content = null;
campaign = null;
return;
}
final Uri u = new Uri.Builder()
.scheme("http")
.authority("local")
.path("/")
.encodedQuery(referrer).build();
source = u.getQueryParameter("utm_source");
medium = u.getQueryParameter("utm_medium");
term = u.getQueryParameter("utm_term");
content = u.getQueryParameter("utm_content");
campaign = u.getQueryParameter("utm_campaign");
}
@Override
public String toString() {
return "{s: " + source + ", m: " + medium + ", t: " + term + ", c: " + content + ", c: " + campaign + "}";
}
}

View File

@ -0,0 +1,76 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* 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/. */
package org.mozilla.gecko.distribution;
import org.json.JSONException;
import org.json.JSONObject;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.GeckoEvent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.text.TextUtils;
import android.util.Log;
public class ReferrerReceiver extends BroadcastReceiver {
private static final String LOGTAG = "GeckoReferrerReceiver";
private static final String ACTION_INSTALL_REFERRER = "com.android.vending.INSTALL_REFERRER";
/**
* If the install intent has this source, we'll track the campaign ID.
*/
private static final String MOZILLA_UTM_SOURCE = "mozilla";
/**
* If the install intent has this campaign, we'll load the specified distribution.
*/
private static final String DISTRIBUTION_UTM_CAMPAIGN = "distribution";
@Override
public void onReceive(Context context, Intent intent) {
Log.v(LOGTAG, "Received intent " + intent);
if (!ACTION_INSTALL_REFERRER.equals(intent.getAction())) {
// This should never happen.
return;
}
ReferrerDescriptor referrer = new ReferrerDescriptor(intent.getStringExtra("referrer"));
// Track the referrer object for distribution handling.
if (TextUtils.equals(referrer.campaign, DISTRIBUTION_UTM_CAMPAIGN)) {
Distribution.onReceivedReferrer(referrer);
} else {
Log.d(LOGTAG, "Not downloading distribution: non-matching campaign.");
}
// If this is a Mozilla campaign, pass the campaign along to Gecko.
if (TextUtils.equals(referrer.source, MOZILLA_UTM_SOURCE)) {
propagateMozillaCampaign(referrer);
}
}
private void propagateMozillaCampaign(ReferrerDescriptor referrer) {
if (referrer.campaign == null) {
return;
}
try {
final JSONObject data = new JSONObject();
data.put("id", "playstore");
data.put("version", referrer.campaign);
String payload = data.toString();
// Try to make sure the prefs are written as a group.
final GeckoEvent event = GeckoEvent.createBroadcastEvent("Campaign:Set", payload);
GeckoAppShell.sendEventToGecko(event);
} catch (JSONException e) {
Log.e(LOGTAG, "Error propagating campaign identifier.", e);
}
}
}

View File

@ -156,6 +156,8 @@ gbjar.sources += [
'db/TabsProvider.java',
'db/TopSitesCursorWrapper.java',
'distribution/Distribution.java',
'distribution/ReferrerDescriptor.java',
'distribution/ReferrerReceiver.java',
'DoorHangerPopup.java',
'DynamicToolbar.java',
'EditBookmarkDialog.java',
@ -354,7 +356,6 @@ gbjar.sources += [
'prompts/PromptService.java',
'prompts/TabInput.java',
'ReaderModeUtils.java',
'ReferrerReceiver.java',
'Restarter.java',
'ScrollAnimator.java',
'ServiceNotificationClient.java',

View File

@ -2,19 +2,29 @@ package org.mozilla.gecko.tests;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URI;
import java.util.jar.JarInputStream;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.mozilla.gecko.Actions;
import org.mozilla.gecko.AppConstants;
import org.mozilla.gecko.db.BrowserContract;
import org.mozilla.gecko.distribution.Distribution;
import org.mozilla.gecko.distribution.ReferrerDescriptor;
import org.mozilla.gecko.mozglue.RobocopTarget;
import org.mozilla.gecko.util.ThreadUtils;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.util.Log;
/**
* Tests distribution customization.
@ -28,6 +38,38 @@ import android.content.SharedPreferences;
* engine.xml
*/
public class testDistribution extends ContentProviderTest {
private static final String CLASS_REFERRER_RECEIVER = "org.mozilla.gecko.distribution.ReferrerReceiver";
private static final String ACTION_INSTALL_REFERRER = "com.android.vending.INSTALL_REFERRER";
private static final int WAIT_TIMEOUT_MSEC = 10000;
public static final String LOGTAG = "GeckoTestDistribution";
public static class TestableDistribution extends Distribution {
@Override
protected JarInputStream fetchDistribution(URI uri,
HttpURLConnection connection) throws IOException {
Log.i(LOGTAG, "Not downloading: this is a test.");
return null;
}
public TestableDistribution(Context context) {
super(context);
}
public void go() {
doInit();
}
@RobocopTarget
public static void clearReferrerDescriptorForTesting() {
referrer = null;
}
@RobocopTarget
public static ReferrerDescriptor getReferrerDescriptorForTesting() {
return referrer;
}
}
private static final String MOCK_PACKAGE = "mock-package.zip";
private static final int PREF_REQUEST_ID = 0x7357;
@ -65,7 +107,7 @@ public class testDistribution extends ContentProviderTest {
mAsserter.dumpLog("Background task completed. Proceeding.");
}
public void testDistribution() {
public void testDistribution() throws Exception {
mActivity = getActivity();
String mockPackagePath = getMockPackagePath();
@ -87,6 +129,90 @@ public class testDistribution extends ContentProviderTest {
setTestLocale("es-MX");
initDistribution(mockPackagePath);
checkLocalizedPreferences("es-MX");
// Test the (stubbed) download interaction.
setTestLocale("en-US");
clearDistributionPref();
doTestValidReferrerIntent();
clearDistributionPref();
doTestInvalidReferrerIntent();
}
public void doTestValidReferrerIntent() throws Exception {
// Send the faux-download intent.
// Equivalent to
// am broadcast -a com.android.vending.INSTALL_REFERRER \
// -n org.mozilla.fennec/org.mozilla.gecko.distribution.ReferrerReceiver \
// --es "referrer" "utm_source=mozilla&utm_medium=testmedium&utm_term=testterm&utm_content=testcontent&utm_campaign=distribution"
final String ref = "utm_source=mozilla&utm_medium=testmedium&utm_term=testterm&utm_content=testcontent&utm_campaign=distribution";
final Intent intent = new Intent(ACTION_INSTALL_REFERRER);
intent.setClassName(AppConstants.ANDROID_PACKAGE_NAME, CLASS_REFERRER_RECEIVER);
intent.putExtra("referrer", ref);
mActivity.sendBroadcast(intent);
// Wait for the intent to be processed.
final TestableDistribution distribution = new TestableDistribution(mActivity);
final Object wait = new Object();
distribution.addOnDistributionReadyCallback(new Runnable() {
@Override
public void run() {
mAsserter.ok(!distribution.exists(), "Not processed.", "No download because we're offline.");
ReferrerDescriptor referrerValue = TestableDistribution.getReferrerDescriptorForTesting();
mAsserter.dumpLog("Referrer was " + referrerValue);
mAsserter.is(referrerValue.content, "testcontent", "Referrer content");
mAsserter.is(referrerValue.medium, "testmedium", "Referrer medium");
mAsserter.is(referrerValue.campaign, "distribution", "Referrer campaign");
synchronized (wait) {
wait.notifyAll();
}
}
});
distribution.go();
synchronized (wait) {
wait.wait(WAIT_TIMEOUT_MSEC);
}
}
/**
* Test processing if the campaign isn't "distribution". The intent shouldn't
* result in a download, and won't be saved as the temporary referrer,
* even if we *do* include it in a Campaign:Set message.
*/
public void doTestInvalidReferrerIntent() throws Exception {
// Send the faux-download intent.
// Equivalent to
// am broadcast -a com.android.vending.INSTALL_REFERRER \
// -n org.mozilla.fennec/org.mozilla.gecko.distribution.ReferrerReceiver \
// --es "referrer" "utm_source=mozilla&utm_medium=testmedium&utm_term=testterm&utm_content=testcontent&utm_campaign=testname"
final String ref = "utm_source=mozilla&utm_medium=testmedium&utm_term=testterm&utm_content=testcontent&utm_campaign=testname";
final Intent intent = new Intent(ACTION_INSTALL_REFERRER);
intent.setClassName(AppConstants.ANDROID_PACKAGE_NAME, CLASS_REFERRER_RECEIVER);
intent.putExtra("referrer", ref);
mActivity.sendBroadcast(intent);
// Wait for the intent to be processed.
final TestableDistribution distribution = new TestableDistribution(mActivity);
final Object wait = new Object();
distribution.addOnDistributionReadyCallback(new Runnable() {
@Override
public void run() {
mAsserter.ok(!distribution.exists(), "Not processed.", "No download because campaign was wrong.");
ReferrerDescriptor referrerValue = TestableDistribution.getReferrerDescriptorForTesting();
mAsserter.is(referrerValue, null, "No referrer.");
synchronized (wait) {
wait.notifyAll();
}
}
});
distribution.go();
synchronized (wait) {
wait.wait(WAIT_TIMEOUT_MSEC);
}
}
// Initialize the distribution from the mock package.
@ -288,12 +414,16 @@ public class testDistribution extends ContentProviderTest {
return mockPackagePath;
}
// Clears the distribution pref to return distribution state to STATE_UNKNOWN
/**
* Clears the distribution pref to return distribution state to STATE_UNKNOWN,
* and wipes the in-memory referrer pigeonhole.
*/
private void clearDistributionPref() {
mAsserter.dumpLog("Clearing distribution pref.");
SharedPreferences settings = mActivity.getSharedPreferences("GeckoApp", Activity.MODE_PRIVATE);
String keyName = mActivity.getPackageName() + ".distribution_state";
settings.edit().remove(keyName).commit();
TestableDistribution.clearReferrerDescriptorForTesting();
}
@Override

View File

@ -11,6 +11,7 @@ jar.sources += [
'src/harness/BrowserInstrumentationTestRunner.java',
'src/harness/BrowserTestListener.java',
'src/tests/BrowserTestCase.java',
'src/tests/TestDistribution.java',
'src/tests/TestGeckoSharedPrefs.java',
'src/tests/TestJarReader.java',
'src/tests/TestRawResource.java',

View File

@ -0,0 +1,36 @@
/* 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/. */
package org.mozilla.gecko.browser.tests;
import org.mozilla.gecko.distribution.ReferrerDescriptor;
public class TestDistribution extends BrowserTestCase {
private static final String TEST_REFERRER_STRING = "utm_source=campsource&utm_medium=campmed&utm_term=term%2Bhere&utm_content=content&utm_campaign=name";
private static final String TEST_MALFORMED_REFERRER_STRING = "utm_source=campsource&utm_medium=campmed&utm_term=term%2";
public void testReferrerParsing() {
ReferrerDescriptor good = new ReferrerDescriptor(TEST_REFERRER_STRING);
assertEquals("campsource", good.source);
assertEquals("campmed", good.medium);
assertEquals("term+here", good.term);
assertEquals("content", good.content);
assertEquals("name", good.campaign);
// Uri.Builder is permissive.
ReferrerDescriptor bad = new ReferrerDescriptor(TEST_MALFORMED_REFERRER_STRING);
assertEquals("campsource", bad.source);
assertEquals("campmed", bad.medium);
assertFalse("term+here".equals(bad.term));
assertNull(bad.content);
assertNull(bad.campaign);
ReferrerDescriptor ugly = new ReferrerDescriptor(null);
assertNull(ugly.source);
assertNull(ugly.medium);
assertNull(ugly.term);
assertNull(ugly.content);
assertNull(ugly.campaign);
}
}

View File

@ -569,7 +569,7 @@ VerifySignature(AppTrustedRoot trustedRoot, const SECItem& buffer,
NS_IMETHODIMP
OpenSignedAppFile(AppTrustedRoot aTrustedRoot, nsIFile* aJarFile,
/*out, optional */ nsIZipReader** aZipReader,
/*out, optional */ nsIX509Cert3** aSignerCert)
/*out, optional */ nsIX509Cert** aSignerCert)
{
NS_ENSURE_ARG_POINTER(aJarFile);
@ -728,7 +728,7 @@ OpenSignedAppFile(AppTrustedRoot aTrustedRoot, nsIFile* aJarFile,
// but we can't do that until we switch to libpkix.
if (aSignerCert) {
MOZ_ASSERT(CERT_LIST_HEAD(builtChain));
nsCOMPtr<nsIX509Cert3> signerCert =
nsCOMPtr<nsIX509Cert> signerCert =
nsNSSCertificate::Create(CERT_LIST_HEAD(builtChain)->cert);
NS_ENSURE_TRUE(signerCert, NS_ERROR_OUT_OF_MEMORY);
signerCert.forget(aSignerCert);
@ -769,7 +769,7 @@ private:
const nsCOMPtr<nsIFile> mJarFile;
nsMainThreadPtrHandle<nsIOpenSignedAppFileCallback> mCallback;
nsCOMPtr<nsIZipReader> mZipReader; // out
nsCOMPtr<nsIX509Cert3> mSignerCert; // out
nsCOMPtr<nsIX509Cert> mSignerCert; // out
};
} // unnamed namespace

View File

@ -43,7 +43,6 @@ function getDERString(cert)
function getPKCS7String(cert, chainMode)
{
var length = {};
cert.QueryInterface(Components.interfaces.nsIX509Cert3);
var pkcs7Array = cert.exportAsCMS(chainMode, length);
var pkcs7String = '';
for (var i = 0; i < pkcs7Array.length; i++) {
@ -110,10 +109,10 @@ function exportToFile(parent, cert)
content = getDERString(cert);
break;
case 3:
content = getPKCS7String(cert, Components.interfaces.nsIX509Cert3.CMS_CHAIN_MODE_CertOnly);
content = getPKCS7String(cert, Components.interfaces.nsIX509Cert.CMS_CHAIN_MODE_CertOnly);
break;
case 4:
content = getPKCS7String(cert, Components.interfaces.nsIX509Cert3.CMS_CHAIN_MODE_CertChainWithRoot);
content = getPKCS7String(cert, Components.interfaces.nsIX509Cert.CMS_CHAIN_MODE_CertChainWithRoot);
break;
case 0:
default:

View File

@ -3,7 +3,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const nsIX509Cert = Components.interfaces.nsIX509Cert;
const nsIX509Cert3 = Components.interfaces.nsIX509Cert3;
const nsX509CertDB = "@mozilla.org/security/x509certdb;1";
const nsIX509CertDB = Components.interfaces.nsIX509CertDB;
const nsPK11TokenDB = "@mozilla.org/security/pk11tokendb;1";
@ -94,14 +93,9 @@ function setWindowName()
AddCertChain("treesetDump", chain, "dump_");
DisplayGeneralDataFromCert(cert);
BuildPrettyPrint(cert);
if (cert instanceof nsIX509Cert3)
{
cert.requestUsagesArrayAsync(new listener());
}
cert.requestUsagesArrayAsync(new listener());
}
function addChildrenToTree(parentTree,label,value,addTwistie)
{
var treeChild1 = document.createElement("treechildren");
@ -249,7 +243,7 @@ function DisplayGeneralDataFromCert(cert)
addAttributeFromCert('validitystart', cert.validity.notBeforeLocalDay);
// Validity end
addAttributeFromCert('validityend', cert.validity.notAfterLocalDay);
//Now to populate the fields that correspond to the issuer.
var issuerCommonname, issuerOrg, issuerOrgUnit;
issuerCommonname = cert.issuerCommonName;
@ -287,7 +281,7 @@ function getCurrentCert()
&& document.getElementById('prettyprint_tab').selected) {
/* if the user manually selected a cert on the Details tab,
then take that one */
realIndex = tree.currentIndex;
realIndex = tree.currentIndex;
} else {
/* otherwise, take the one at the bottom of the chain
(i.e. the one of the end-entity, unless we're displaying

View File

@ -39,10 +39,7 @@ XPIDL_SOURCES += [
'nsITokenPasswordDialogs.idl',
'nsIUserCertPicker.idl',
'nsIX509Cert.idl',
'nsIX509Cert2.idl',
'nsIX509Cert3.idl',
'nsIX509CertDB.idl',
'nsIX509CertDB2.idl',
'nsIX509CertList.idl',
'nsIX509CertValidity.idl',
]

View File

@ -23,7 +23,7 @@ interface nsISSLStatus : nsISupports {
* "unstrusted because missing or untrusted issuer"
* and
* "untrusted because self signed"
* query nsIX509Cert3::isSelfSigned
* query nsIX509Cert::isSelfSigned
*/
readonly attribute boolean isUntrusted;

View File

@ -9,11 +9,18 @@
interface nsIArray;
interface nsIX509CertValidity;
interface nsIASN1Object;
interface nsICertVerificationListener;
%{ C++
/* forward declaration */
typedef struct CERTCertificateStr CERTCertificate;
%}
[ptr] native CERTCertificatePtr(CERTCertificate);
/**
* This represents a X.509 certificate.
*/
[scriptable, uuid(891d2009-b9ba-4a0d-bebe-6b3a30e33191)]
[scriptable, uuid(f8ed8364-ced9-4c6e-86ba-48af53c393e6)]
interface nsIX509Cert : nsISupports {
/**
@ -33,7 +40,7 @@ interface nsIX509Cert : nsISupports {
* @param length The number of strings in the returned array.
* @return An array of email addresses.
*/
void getEmailAddresses(out unsigned long length,
void getEmailAddresses(out unsigned long length,
[retval, array, size_is(length)] out wstring addresses);
/**
@ -42,7 +49,7 @@ interface nsIX509Cert : nsISupports {
* The behaviour for non ASCII characters is undefined.
*
* @param aEmailAddress The address to search for.
*
*
* @return True if the address is contained in the certificate.
*/
boolean containsEmailAddress(in AString aEmailAddress);
@ -138,6 +145,18 @@ interface nsIX509Cert : nsISupports {
const unsigned long USER_CERT = 1 << 1;
const unsigned long EMAIL_CERT = 1 << 2;
const unsigned long SERVER_CERT = 1 << 3;
const unsigned long ANY_CERT = 0xffff;
/**
* Type of this certificate
*/
readonly attribute unsigned long certType;
/**
* True if the certificate is self-signed. CA issued
* certificates are always self-signed.
*/
readonly attribute boolean isSelfSigned;
/**
* Constants for certificate verification results.
@ -152,7 +171,7 @@ interface nsIX509Cert : nsISupports {
const unsigned long INVALID_CA = 1 << 6;
const unsigned long USAGE_NOT_ALLOWED = 1 << 7;
const unsigned long SIGNATURE_ALGORITHM_DISABLED = 1 << 8;
/**
* Constants that describe the certified usages of a certificate.
*
@ -172,7 +191,14 @@ interface nsIX509Cert : nsISupports {
const unsigned long CERT_USAGE_AnyCA = 11;
/**
* Obtain a list of certificates that contains this certificate
* Constants for specifying the chain mode when exporting a certificate
*/
const unsigned long CMS_CHAIN_MODE_CertOnly = 1;
const unsigned long CMS_CHAIN_MODE_CertChain = 2;
const unsigned long CMS_CHAIN_MODE_CertChainWithRoot = 3;
/**
* Obtain a list of certificates that contains this certificate
* and the issuing certificates of all involved issuers,
* up to the root issuer.
*
@ -192,9 +218,17 @@ interface nsIX509Cert : nsISupports {
*/
void getUsagesArray(in boolean localOnly,
out uint32_t verified,
out uint32_t count,
out uint32_t count,
[array, size_is(count)] out wstring usages);
/**
* Async version of nsIX509Cert::getUsagesArray()
*
* Will not block, will request results asynchronously,
* availability of results will be notified on the main thread.
*/
void requestUsagesArrayAsync(in nsICertVerificationListener cvl);
/**
* Obtain a single comma separated human readable string describing
* the certificate's certified usages.
@ -224,7 +258,7 @@ interface nsIX509Cert : nsISupports {
[retval, array, size_is(length)] out octet data);
/**
* Test whether two certificate instances represent the
* Test whether two certificate instances represent the
* same certificate.
*
* @return Whether the certificates are equal
@ -236,4 +270,81 @@ interface nsIX509Cert : nsISupports {
* digest.
*/
readonly attribute ACString sha256SubjectPublicKeyInfoDigest;
/**
* Obtain the certificate wrapped in a PKCS#7 SignedData structure,
* with or without the certificate chain
*
* @param chainMode Whether to include the chain (with or without the root),
see CMS_CHAIN_MODE constants.
* @param length The number of bytes of the PKCS#7 data.
* @param data The bytes representing the PKCS#7 wrapped certificate.
*/
void exportAsCMS(in unsigned long chainMode,
out unsigned long length,
[retval, array, size_is(length)] out octet data);
/**
* Retrieves the NSS certificate object wrapped by this interface
*/
[notxpcom, noscript] CERTCertificatePtr getCert();
/**
* Human readable names identifying all hardware or
* software tokens the certificate is stored on.
*
* @param length On success, the number of entries in the returned array.
* @return On success, an array containing the names of all tokens
* the certificate is stored on (may be empty).
* On failure the function throws/returns an error.
*/
void getAllTokenNames(out unsigned long length,
[retval, array, size_is(length)] out wstring
tokenNames);
/**
* Either delete the certificate from all cert databases,
* or mark it as untrusted.
*/
void markForPermDeletion();
};
[scriptable, uuid(2fd0a785-9f2d-4327-8871-8c3e0783891d)]
interface nsICertVerificationResult : nsISupports {
/**
* This interface reflects a container of
* verification results. Call will not block.
*
* Obtain an array of human readable strings describing
* the certificate's certified usages.
*
* Mirrors the results produced by
* nsIX509Cert::getUsagesArray()
*
* As of today, this function is a one-shot object,
* only the first call will succeed.
* This allows an optimization in the implementation,
* ownership of result data will be transfered to caller.
*
* @param cert The certificate that was verified.
* @param verified The certificate verification result,
* see constants in nsIX509Cert.
* @param count The number of human readable usages returned.
* @param usages The array of human readable usages.
*/
void getUsagesArrayResult(out uint32_t verified,
out uint32_t count,
[array, size_is(count)] out wstring usages);
};
[scriptable, uuid(6684bce9-50db-48e1-81b7-98102bf81357)]
interface nsICertVerificationListener : nsISupports {
/**
* Notify that results are ready, that have been requested
* using nsIX509Cert::requestUsagesArrayAsync()
*/
void notify(in nsIX509Cert verifiedCert,
in nsICertVerificationResult result);
};

View File

@ -1,30 +0,0 @@
/* -*- 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 "nsIX509Cert.idl"
interface nsIArray;
interface nsIASN1Object;
%{ C++
/* forward declaration */
typedef struct CERTCertificateStr CERTCertificate;
%}
[ptr] native CERTCertificatePtr(CERTCertificate);
/**
* This represents additional interfaces to X.509 certificates
*/
[scriptable, uuid(5b62c61c-f898-4dab-8ace-51109bb459b4)]
interface nsIX509Cert2 : nsIX509Cert {
/**
* Additional constants to classify the type of a certificate.
*/
const unsigned long ANY_CERT = 0xffff;
readonly attribute unsigned long certType;
void markForPermDeletion();
[notxpcom, noscript] CERTCertificatePtr getCert();
};

View File

@ -1,98 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsIX509Cert2.idl"
interface nsICertVerificationListener;
/**
* Extending nsIX509Cert
*/
[scriptable, uuid(399004d8-b8c7-4eb9-8362-d99f4c0161fd)]
interface nsIX509Cert3 : nsIX509Cert2 {
/**
* Constants for specifying the chain mode when exporting a certificate
*/
const unsigned long CMS_CHAIN_MODE_CertOnly = 1;
const unsigned long CMS_CHAIN_MODE_CertChain = 2;
const unsigned long CMS_CHAIN_MODE_CertChainWithRoot = 3;
/**
* Async version of nsIX509Cert::getUsagesArray()
*
* Will not block, will request results asynchronously,
* availability of results will be notified on the main thread.
*/
void requestUsagesArrayAsync(in nsICertVerificationListener cvl);
/**
* Obtain the certificate wrapped in a PKCS#7 SignedData structure,
* with or without the certificate chain
*
* @param chainMode Whether to include the chain (with or without the root),
see CMS_CHAIN_MODE constants.
* @param length The number of bytes of the PKCS#7 data.
* @param data The bytes representing the PKCS#7 wrapped certificate.
*/
void exportAsCMS(in unsigned long chainMode,
out unsigned long length,
[retval, array, size_is(length)] out octet data);
readonly attribute boolean isSelfSigned;
/**
* Human readable names identifying all hardware or
* software tokens the certificate is stored on.
*
* @param length On success, the number of entries in the returned array.
* @return On success, an array containing the names of all tokens
* the certificate is stored on (may be empty).
* On failure the function throws/returns an error.
*/
void getAllTokenNames(out unsigned long length,
[retval, array, size_is(length)] out wstring
tokenNames);
};
[scriptable, uuid(2fd0a785-9f2d-4327-8871-8c3e0783891d)]
interface nsICertVerificationResult : nsISupports {
/**
* This interface reflects a container of
* verification results. Call will not block.
*
* Obtain an array of human readable strings describing
* the certificate's certified usages.
*
* Mirrors the results produced by
* nsIX509Cert::getUsagesArray()
*
* As of today, this function is a one-shot object,
* only the first call will succeed.
* This allows an optimization in the implementation,
* ownership of result data will be transfered to caller.
*
* @param cert The certificate that was verified.
* @param verified The certificate verification result,
* see constants in nsIX509Cert.
* @param count The number of human readable usages returned.
* @param usages The array of human readable usages.
*/
void getUsagesArrayResult(out uint32_t verified,
out uint32_t count,
[array, size_is(count)] out wstring usages);
};
[scriptable, uuid(6684bce9-50db-48e1-81b7-98102bf81357)]
interface nsICertVerificationListener : nsISupports {
/**
* Notify that results are ready, that have been requested
* using nsIX509Cert3::requestUsagesArrayAsync()
*/
void notify(in nsIX509Cert3 verifiedCert,
in nsICertVerificationResult result);
};

View File

@ -8,7 +8,6 @@
interface nsIArray;
interface nsIX509Cert;
interface nsIX509Cert3;
interface nsIFile;
interface nsIInterfaceRequestor;
interface nsIZipReader;
@ -21,16 +20,16 @@ interface nsIX509CertList;
typedef uint32_t AppTrustedRoot;
[scriptable, function, uuid(0927baea-622d-4e41-a76d-255af426e7fb)]
[scriptable, function, uuid(5984db62-d0e5-4671-a082-799cf7271e24)]
interface nsIOpenSignedAppFileCallback : nsISupports
{
void openSignedAppFileFinished(in nsresult rv,
in nsIZipReader aZipReader,
in nsIX509Cert3 aSignerCert);
in nsIX509Cert aSignerCert);
};
/**
* This represents a service to access and manipulate
* This represents a service to access and manipulate
* X.509 certificates stored in a database.
*/
[scriptable, uuid(7446a5b1-84ca-491f-a2fe-0bc60a71ffa5)]
@ -49,12 +48,12 @@ interface nsIX509CertDB : nsISupports {
* Given a nickname and optionally a token,
* locate the matching certificate.
*
* @param aToken Optionally limits the scope of
* @param aToken Optionally limits the scope of
* this function to a token device.
* Can be null to mean any token.
* @param aNickname The nickname to be used as the key
* to find a certificate.
*
*
* @return The matching certificate if found.
*/
nsIX509Cert findCertByNickname(in nsISupports aToken,
@ -67,7 +66,7 @@ interface nsIX509CertDB : nsISupports {
*
* @param aDBkey Database internal key, as obtained using
* attribute dbkey in nsIX509Cert.
* @param aToken Optionally limits the scope of
* @param aToken Optionally limits the scope of
* this function to a token device.
* Can be null to mean any token.
*/
@ -79,7 +78,7 @@ interface nsIX509CertDB : nsISupports {
* user, ca, or server cert - the nickname
* email cert - the email address
*
* @param aToken Optionally limits the scope of
* @param aToken Optionally limits the scope of
* this function to a token device.
* Can be null to mean any token.
* @param aType Type of certificate to obtain
@ -87,7 +86,7 @@ interface nsIX509CertDB : nsISupports {
* @param count The number of nicknames in the returned array
* @param certNameList The returned array of certificate nicknames.
*/
void findCertNicknames(in nsISupports aToken,
void findCertNicknames(in nsISupports aToken,
in unsigned long aType,
out unsigned long count,
[array, size_is(count)] out wstring certNameList);
@ -97,7 +96,7 @@ interface nsIX509CertDB : nsISupports {
*
* @param aNickname The nickname to be used as the key
* to find the certificate.
*
*
* @return The matching certificate if found.
*/
nsIX509Cert findEmailEncryptionCert(in AString aNickname);
@ -107,7 +106,7 @@ interface nsIX509CertDB : nsISupports {
*
* @param aNickname The nickname to be used as the key
* to find the certificate.
*
*
* @return The matching certificate if found.
*/
nsIX509Cert findEmailSigningCert(in AString aNickname);
@ -115,12 +114,12 @@ interface nsIX509CertDB : nsISupports {
/**
* Find a certificate by email address.
*
* @param aToken Optionally limits the scope of
* @param aToken Optionally limits the scope of
* this function to a token device.
* Can be null to mean any token.
* @param aEmailAddress The email address to be used as the key
* to find the certificate.
*
*
* @return The matching certificate if found.
*/
nsIX509Cert findCertByEmailAddress(in nsISupports aToken,
@ -164,7 +163,7 @@ interface nsIX509CertDB : nsISupports {
in nsIInterfaceRequestor ctx);
/**
* Import a personal certificate into the database, assuming
* Import a personal certificate into the database, assuming
* the database already contains the private key for this certificate.
*
* @param data The raw data to be imported
@ -184,7 +183,7 @@ interface nsIX509CertDB : nsISupports {
/**
* Modify the trust that is stored and associated to a certificate within
* a database. Separate trust is stored for
* a database. Separate trust is stored for
* One call manipulates the trust for one trust type only.
* See the trust type constants defined within this interface.
*
@ -203,14 +202,14 @@ interface nsIX509CertDB : nsISupports {
* characters, indicating SSL, Email, and Obj signing
* trust.
*/
void setCertTrustFromString(in nsIX509Cert3 cert, in string trustString);
void setCertTrustFromString(in nsIX509Cert cert, in string trustString);
/**
* Query whether a certificate is trusted for a particular use.
*
* @param cert Obtain the stored trust of this certificate.
* @param certType The type of the certificate. See nsIX509Cert.
* @param trustType A single bit from the usages constants defined
* @param trustType A single bit from the usages constants defined
* within this interface.
*
* @return Returns true if the certificate is trusted for the given use.
@ -222,7 +221,7 @@ interface nsIX509CertDB : nsISupports {
/**
* Import certificate(s) from file
*
* @param aToken Optionally limits the scope of
* @param aToken Optionally limits the scope of
* this function to a token device.
* Can be null to mean any token.
* @param aFile Identifies a file that contains the certificate
@ -237,7 +236,7 @@ interface nsIX509CertDB : nsISupports {
/**
* Import a PKCS#12 file containing cert(s) and key(s) into the database.
*
* @param aToken Optionally limits the scope of
* @param aToken Optionally limits the scope of
* this function to a token device.
* Can be null to mean any token.
* @param aFile Identifies a file that contains the data
@ -249,7 +248,7 @@ interface nsIX509CertDB : nsISupports {
/**
* Export a set of certs and keys from the database to a PKCS#12 file.
*
* @param aToken Optionally limits the scope of
* @param aToken Optionally limits the scope of
* this function to a token device.
* Can be null to mean any token.
* @param aFile Identifies a file that will be filled with the data
@ -316,7 +315,7 @@ interface nsIX509CertDB : nsISupports {
in nsIFile aJarFile,
in nsIOpenSignedAppFileCallback callback);
/*
/*
* Add a cert to a cert DB from a binary string.
*
* @param certDER The raw DER encoding of a certificate.
@ -361,4 +360,20 @@ interface nsIX509CertDB : nsISupports {
// Clears the OCSP cache for the current certificate verification
// implementation.
void clearOCSPCache();
/*
* Add a cert to a cert DB from a base64 encoded string.
*
* @param base64 The raw representation of a certificate,
* encoded as Base 64.
* @param aTrust decoded by CERT_DecodeTrustString. 3 comma separated characters,
* indicating SSL, Email, and Obj signing trust
* @param aName name of the cert for display purposes.
*/
void addCertFromBase64(in string base64, in string aTrust, in string aName);
/*
* Get all the known certs in the database
*/
nsIX509CertList getCerts();
};

View File

@ -1,36 +0,0 @@
/* -*- 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 "nsISupports.idl"
interface nsIX509CertList;
/**
* This represents a service to access and manipulate
* X.509 certificates stored in a database through methods
* not in nsIX509CertDB, which is frozen
*
*/
[scriptable, uuid(e0df4784-6560-45bf-b1b7-86076a0e8381)]
interface nsIX509CertDB2 : nsISupports {
/*
* Add a cert to a cert DB from a base64 encoded string.
*
* @param base64 The raw representation of a certificate,
* encoded as Base 64.
* @param aTrust decoded by CERT_DecodeTrustString. 3 comma separated characters,
* indicating SSL, Email, and Obj signing trust
* @param aName name of the cert for display purposes.
*/
void addCertFromBase64(in string base64, in string aTrust, in string aName);
/*
* Get all the known certs in the database
*/
nsIX509CertList getCerts();
};

View File

@ -689,7 +689,6 @@ BlockServerCertChangeForSpdy(nsNSSSocketInfo* infoObject,
// Get the existing cert. If there isn't one, then there is
// no cert change to worry about.
nsCOMPtr<nsIX509Cert> cert;
nsCOMPtr<nsIX509Cert2> cert2;
RefPtr<nsSSLStatus> status(infoObject->SSLStatus());
if (!status) {
@ -700,10 +699,9 @@ BlockServerCertChangeForSpdy(nsNSSSocketInfo* infoObject,
}
status->GetServerCert(getter_AddRefs(cert));
cert2 = do_QueryInterface(cert);
if (!cert2) {
if (!cert) {
NS_NOTREACHED("every nsSSLStatus must have a cert"
"that implements nsIX509Cert2");
"that implements nsIX509Cert");
PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
return SECFailure;
}
@ -715,9 +713,9 @@ BlockServerCertChangeForSpdy(nsNSSSocketInfo* infoObject,
"GetNegotiatedNPN() failed during renegotiation");
if (NS_SUCCEEDED(rv) && !StringBeginsWith(negotiatedNPN,
NS_LITERAL_CSTRING("spdy/")))
NS_LITERAL_CSTRING("spdy/"))) {
return SECSuccess;
}
// If GetNegotiatedNPN() failed we will assume spdy for safety's safe
if (NS_FAILED(rv)) {
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
@ -726,11 +724,12 @@ BlockServerCertChangeForSpdy(nsNSSSocketInfo* infoObject,
}
// Check to see if the cert has actually changed
ScopedCERTCertificate c(cert2->GetCert());
ScopedCERTCertificate c(cert->GetCert());
NS_ASSERTION(c, "very bad and hopefully impossible state");
bool sameCert = CERT_CompareCerts(c, serverCert);
if (sameCert)
if (sameCert) {
return SECSuccess;
}
// Report an error - changed cert is confirmed
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,

View File

@ -535,13 +535,9 @@ AppendErrorTextUntrusted(PRErrorCode errTrust,
nsString &returnedMessage)
{
const char *errorID = nullptr;
nsCOMPtr<nsIX509Cert3> cert3 = do_QueryInterface(ix509);
if (cert3) {
bool isSelfSigned;
if (NS_SUCCEEDED(cert3->GetIsSelfSigned(&isSelfSigned))
&& isSelfSigned) {
errorID = "certErrorTrust_SelfSigned";
}
bool isSelfSigned;
if (NS_SUCCEEDED(ix509->GetIsSelfSigned(&isSelfSigned)) && isSelfSigned) {
errorID = "certErrorTrust_SelfSigned";
}
if (!errorID) {
@ -690,11 +686,7 @@ AppendErrorTextMismatch(const nsString &host,
const char16_t *params[1];
nsresult rv;
mozilla::pkix::ScopedCERTCertificate nssCert;
nsCOMPtr<nsIX509Cert2> cert2 = do_QueryInterface(ix509, &rv);
if (cert2)
nssCert = cert2->GetCert();
mozilla::pkix::ScopedCERTCertificate nssCert(ix509->GetCert());
if (!nssCert) {
// We are unable to extract the valid names, say "not valid for name".

View File

@ -390,14 +390,11 @@ GetCertFingerprintByOidTag(nsIX509Cert *aCert,
SECOidTag aOidTag,
nsCString &fp)
{
nsCOMPtr<nsIX509Cert2> cert2 = do_QueryInterface(aCert);
if (!cert2)
return NS_ERROR_FAILURE;
mozilla::pkix::ScopedCERTCertificate nsscert(cert2->GetCert());
if (!nsscert)
mozilla::pkix::ScopedCERTCertificate nsscert(aCert->GetCert());
if (!nsscert) {
return NS_ERROR_FAILURE;
}
return GetCertFingerprintByOidTag(nsscert.get(), aOidTag, fp);
}
@ -425,24 +422,23 @@ GetCertFingerprintByDottedOidString(CERTCertificate* nsscert,
static nsresult
GetCertFingerprintByDottedOidString(nsIX509Cert *aCert,
const nsCString &dottedOid,
const nsCString &dottedOid,
nsCString &fp)
{
nsCOMPtr<nsIX509Cert2> cert2 = do_QueryInterface(aCert);
if (!cert2)
return NS_ERROR_FAILURE;
mozilla::pkix::ScopedCERTCertificate nsscert(cert2->GetCert());
if (!nsscert)
mozilla::pkix::ScopedCERTCertificate nsscert(aCert->GetCert());
if (!nsscert) {
return NS_ERROR_FAILURE;
}
return GetCertFingerprintByDottedOidString(nsscert.get(), dottedOid, fp);
}
NS_IMETHODIMP
nsCertOverrideService::RememberValidityOverride(const nsACString & aHostName, int32_t aPort,
nsIX509Cert *aCert,
uint32_t aOverrideBits,
nsCertOverrideService::RememberValidityOverride(const nsACString& aHostName,
int32_t aPort,
nsIX509Cert* aCert,
uint32_t aOverrideBits,
bool aTemporary)
{
NS_ENSURE_ARG_POINTER(aCert);
@ -451,13 +447,10 @@ nsCertOverrideService::RememberValidityOverride(const nsACString & aHostName, in
if (aPort < -1)
return NS_ERROR_INVALID_ARG;
nsCOMPtr<nsIX509Cert2> cert2 = do_QueryInterface(aCert);
if (!cert2)
return NS_ERROR_FAILURE;
mozilla::pkix::ScopedCERTCertificate nsscert(cert2->GetCert());
if (!nsscert)
mozilla::pkix::ScopedCERTCertificate nsscert(aCert->GetCert());
if (!nsscert) {
return NS_ERROR_FAILURE;
}
char* nickname = DefaultServerNicknameForCert(nsscert.get());
if (!aTemporary && nickname && *nickname)

View File

@ -330,7 +330,7 @@ nsCertTree::nsCertCompareFunc
nsCertTree::GetCompareFuncFromCertType(uint32_t aType)
{
switch (aType) {
case nsIX509Cert2::ANY_CERT:
case nsIX509Cert::ANY_CERT:
case nsIX509Cert::USER_CERT:
return CmpUserCert;
case nsIX509Cert::CA_CERT:
@ -477,7 +477,7 @@ nsCertTree::GetCertsByTypeFromCertList(CERTCertList *aCertList,
!CERT_LIST_END(node, aCertList);
node = CERT_LIST_NEXT(node)) {
bool wantThisCert = (aWantedType == nsIX509Cert2::ANY_CERT);
bool wantThisCert = (aWantedType == nsIX509Cert::ANY_CERT);
bool wantThisCertIfNoOverrides = false;
bool wantThisCertIfHaveOverrides = false;
bool addOverrides = false;
@ -809,12 +809,7 @@ nsCertTree::DeleteEntryObject(uint32_t index)
// although there are still overrides stored,
// so, we keep the cert, but remove the trust
mozilla::pkix::ScopedCERTCertificate nsscert;
nsCOMPtr<nsIX509Cert2> cert2 = do_QueryInterface(cert);
if (cert2) {
nsscert = cert2->GetCert();
}
mozilla::pkix::ScopedCERTCertificate nsscert(cert->GetCert());
if (nsscert) {
CERTCertTrust trust;
@ -1235,12 +1230,8 @@ nsCertTree::GetCellText(int32_t row, nsITreeColumn* col,
(certdi->mIsTemporary) ? "CertExceptionTemporary" : "CertExceptionPermanent";
rv = mNSSComponent->GetPIPNSSBundleString(stringID, _retval);
} else if (NS_LITERAL_STRING("typecol").Equals(colID) && cert) {
nsCOMPtr<nsIX509Cert2> pipCert = do_QueryInterface(cert);
uint32_t type = nsIX509Cert::UNKNOWN_CERT;
if (pipCert) {
rv = pipCert->GetCertType(&type);
}
rv = cert->GetCertType(&type);
switch (type) {
case nsIX509Cert::USER_CERT:

View File

@ -17,7 +17,7 @@ class DispatchCertVerificationResult : public nsRunnable
{
public:
DispatchCertVerificationResult(const nsMainThreadPtrHandle<nsICertVerificationListener>& aListener,
nsIX509Cert3* aCert,
nsIX509Cert* aCert,
nsICertVerificationResult* aResult)
: mListener(aListener)
, mCert(aCert)
@ -31,7 +31,7 @@ public:
private:
nsMainThreadPtrHandle<nsICertVerificationListener> mListener;
nsCOMPtr<nsIX509Cert3> mCert;
nsCOMPtr<nsIX509Cert> mCert;
nsCOMPtr<nsICertVerificationResult> mResult;
};
} // anonymous namespace
@ -63,9 +63,8 @@ void nsCertVerificationJob::Run()
ires = vres;
}
nsCOMPtr<nsIX509Cert3> c3 = do_QueryInterface(mCert);
nsCOMPtr<nsIRunnable> r = new DispatchCertVerificationResult(mListener, c3, ires);
nsCOMPtr<nsIRunnable> r = new DispatchCertVerificationResult(mListener, mCert, ires);
NS_DispatchToMainThread(r);
}

View File

@ -19,7 +19,6 @@
#include "nsPKCS12Blob.h"
#include "nsPK11TokenDB.h"
#include "nsIX509Cert.h"
#include "nsIX509Cert3.h"
#include "nsNSSASN1Object.h"
#include "nsString.h"
#include "nsXPIDLString.h"
@ -68,8 +67,6 @@ NSSCleanupAutoPtrClass_WithParam(PLArenaPool, PORT_FreeArena, FalseParam, false)
NS_IMPL_ISUPPORTS(nsNSSCertificate,
nsIX509Cert,
nsIX509Cert2,
nsIX509Cert3,
nsIIdentityInfo,
nsISerializable,
nsIClassInfo)
@ -1141,9 +1138,9 @@ nsNSSCertificate::ExportAsCMS(uint32_t chainMode,
return NS_ERROR_FAILURE;
switch (chainMode) {
case nsIX509Cert3::CMS_CHAIN_MODE_CertOnly:
case nsIX509Cert3::CMS_CHAIN_MODE_CertChain:
case nsIX509Cert3::CMS_CHAIN_MODE_CertChainWithRoot:
case nsIX509Cert::CMS_CHAIN_MODE_CertOnly:
case nsIX509Cert::CMS_CHAIN_MODE_CertChain:
case nsIX509Cert::CMS_CHAIN_MODE_CertChainWithRoot:
break;
default:
return NS_ERROR_INVALID_ARG;
@ -1178,15 +1175,15 @@ nsNSSCertificate::ExportAsCMS(uint32_t chainMode,
// Since CERT_CertChainFromCert() also includes the certificate itself,
// we have to start at the issuing cert (to avoid duplicate certs
// in the SignedData).
if (chainMode == nsIX509Cert3::CMS_CHAIN_MODE_CertChain ||
chainMode == nsIX509Cert3::CMS_CHAIN_MODE_CertChainWithRoot) {
if (chainMode == nsIX509Cert::CMS_CHAIN_MODE_CertChain ||
chainMode == nsIX509Cert::CMS_CHAIN_MODE_CertChainWithRoot) {
ScopedCERTCertificate issuerCert(
CERT_FindCertIssuer(mCert.get(), PR_Now(), certUsageAnyCA));
// the issuerCert of a self signed root is the cert itself,
// so make sure we're not adding duplicates, again
if (issuerCert && issuerCert != mCert.get()) {
bool includeRoot =
(chainMode == nsIX509Cert3::CMS_CHAIN_MODE_CertChainWithRoot);
(chainMode == nsIX509Cert::CMS_CHAIN_MODE_CertChainWithRoot);
ScopedCERTCertificateList certChain(
CERT_CertChainFromCert(issuerCert, certUsageAnyCA, includeRoot));
if (certChain) {
@ -1377,11 +1374,7 @@ nsNSSCertificate::Equals(nsIX509Cert* other, bool* result)
NS_ENSURE_ARG(other);
NS_ENSURE_ARG(result);
nsCOMPtr<nsIX509Cert2> other2 = do_QueryInterface(other);
if (!other2)
return NS_ERROR_FAILURE;
ScopedCERTCertificate cert(other2->GetCert());
ScopedCERTCertificate cert(other->GetCert());
*result = (mCert.get() == cert.get());
return NS_OK;
}
@ -1552,10 +1545,7 @@ nsNSSCertList::AddCert(nsIX509Cert* aCert)
if (isAlreadyShutDown()) {
return NS_ERROR_NOT_AVAILABLE;
}
nsCOMPtr<nsIX509Cert2> nssCert = do_QueryInterface(aCert);
CERTCertificate* cert;
cert = nssCert->GetCert();
CERTCertificate* cert = aCert->GetCert();
if (!cert) {
NS_ERROR("Somehow got nullptr for mCertificate in nsNSSCertificate.");
return NS_ERROR_FAILURE;
@ -1577,8 +1567,7 @@ nsNSSCertList::DeleteCert(nsIX509Cert* aCert)
if (isAlreadyShutDown()) {
return NS_ERROR_NOT_AVAILABLE;
}
nsCOMPtr<nsIX509Cert2> nssCert = do_QueryInterface(aCert);
CERTCertificate* cert = nssCert->GetCert();
CERTCertificate* cert = aCert->GetCert();
CERTCertListNode* node;
if (!cert) {
@ -1605,8 +1594,9 @@ CERTCertList*
nsNSSCertList::DupCertList(CERTCertList* aCertList,
const nsNSSShutDownPreventionLock& /*proofOfLock*/)
{
if (!aCertList)
if (!aCertList) {
return nullptr;
}
CERTCertList* newList = CERT_NewCertList();

View File

@ -7,8 +7,6 @@
#define _NS_NSSCERTIFICATE_H_
#include "nsIX509Cert.h"
#include "nsIX509Cert2.h"
#include "nsIX509Cert3.h"
#include "nsIX509CertDB.h"
#include "nsIX509CertList.h"
#include "nsIASN1Object.h"
@ -25,7 +23,7 @@ class nsAutoString;
class nsINSSComponent;
class nsIASN1Sequence;
class nsNSSCertificate : public nsIX509Cert3,
class nsNSSCertificate : public nsIX509Cert,
public nsIIdentityInfo,
public nsISerializable,
public nsIClassInfo,
@ -34,8 +32,6 @@ class nsNSSCertificate : public nsIX509Cert3,
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIX509CERT
NS_DECL_NSIX509CERT2
NS_DECL_NSIX509CERT3
NS_DECL_NSIIDENTITYINFO
NS_DECL_NSISERIALIZABLE
NS_DECL_NSICLASSINFO

View File

@ -82,7 +82,7 @@ attemptToLogInWithDefaultPassword()
return NS_OK;
}
NS_IMPL_ISUPPORTS(nsNSSCertificateDB, nsIX509CertDB, nsIX509CertDB2)
NS_IMPL_ISUPPORTS(nsNSSCertificateDB, nsIX509CertDB)
nsNSSCertificateDB::nsNSSCertificateDB()
: mBadCertsLock("nsNSSCertificateDB::mBadCertsLock")
@ -954,14 +954,15 @@ nsNSSCertificateDB::DeleteCertificate(nsIX509Cert *aCert)
if (isAlreadyShutDown()) {
return NS_ERROR_NOT_AVAILABLE;
}
nsCOMPtr<nsIX509Cert2> nssCert = do_QueryInterface(aCert);
mozilla::pkix::ScopedCERTCertificate cert(nssCert->GetCert());
if (!cert) return NS_ERROR_FAILURE;
mozilla::pkix::ScopedCERTCertificate cert(aCert->GetCert());
if (!cert) {
return NS_ERROR_FAILURE;
}
SECStatus srv = SECSuccess;
uint32_t certType;
nssCert->GetCertType(&certType);
if (NS_FAILED(nssCert->MarkForPermDeletion()))
aCert->GetCertType(&certType);
if (NS_FAILED(aCert->MarkForPermDeletion()))
{
return NS_ERROR_FAILURE;
}
@ -998,11 +999,7 @@ nsNSSCertificateDB::SetCertTrust(nsIX509Cert *cert,
}
nsNSSCertTrust trust;
nsresult rv;
nsCOMPtr<nsIX509Cert2> pipCert = do_QueryInterface(cert, &rv);
if (!pipCert) {
return rv;
}
mozilla::pkix::ScopedCERTCertificate nsscert(pipCert->GetCert());
mozilla::pkix::ScopedCERTCertificate nsscert(cert->GetCert());
rv = attemptToLogInWithDefaultPassword();
if (NS_WARN_IF(rv != NS_OK)) {
@ -1054,8 +1051,7 @@ nsNSSCertificateDB::IsCertTrusted(nsIX509Cert *cert,
return NS_ERROR_NOT_AVAILABLE;
}
SECStatus srv;
nsCOMPtr<nsIX509Cert2> pipCert = do_QueryInterface(cert);
mozilla::pkix::ScopedCERTCertificate nsscert(pipCert->GetCert());
mozilla::pkix::ScopedCERTCertificate nsscert(cert->GetCert());
CERTCertTrust nsstrust;
srv = CERT_GetCertTrust(nsscert.get(), &nsstrust);
if (srv != SECSuccess)
@ -1284,7 +1280,8 @@ finish:
/* nsIX509Cert getDefaultEmailEncryptionCert (); */
NS_IMETHODIMP
nsNSSCertificateDB::FindEmailEncryptionCert(const nsAString &aNickname, nsIX509Cert **_retval)
nsNSSCertificateDB::FindEmailEncryptionCert(const nsAString& aNickname,
nsIX509Cert** _retval)
{
NS_ENSURE_ARG_POINTER(_retval);
*_retval = nullptr;
@ -1320,7 +1317,8 @@ nsNSSCertificateDB::FindEmailEncryptionCert(const nsAString &aNickname, nsIX509C
/* nsIX509Cert getDefaultEmailSigningCert (); */
NS_IMETHODIMP
nsNSSCertificateDB::FindEmailSigningCert(const nsAString &aNickname, nsIX509Cert **_retval)
nsNSSCertificateDB::FindEmailSigningCert(const nsAString& aNickname,
nsIX509Cert** _retval)
{
NS_ENSURE_ARG_POINTER(_retval);
*_retval = nullptr;
@ -1590,14 +1588,16 @@ nsNSSCertificateDB::get_default_nickname(CERTCertificate *cert,
}
}
}
if (!dummycert)
if (!dummycert) {
break;
}
count++;
}
}
NS_IMETHODIMP nsNSSCertificateDB::AddCertFromBase64(const char *aBase64, const char *aTrust, const char *aName)
NS_IMETHODIMP nsNSSCertificateDB::AddCertFromBase64(const char* aBase64,
const char* aTrust,
const char* aName)
{
NS_ENSURE_ARG_POINTER(aBase64);
nsCOMPtr <nsIX509Cert> newCert;
@ -1668,7 +1668,7 @@ nsNSSCertificateDB::AddCert(const nsACString & aCertDER, const char *aTrust,
}
NS_IMETHODIMP
nsNSSCertificateDB::SetCertTrustFromString(nsIX509Cert3* cert,
nsNSSCertificateDB::SetCertTrustFromString(nsIX509Cert* cert,
const char* trustString)
{
CERTCertTrust trust;
@ -1761,11 +1761,10 @@ nsNSSCertificateDB::VerifyCertNow(nsIX509Cert* aCert,
EnsureIdentityInfoLoaded();
#endif
nsCOMPtr<nsIX509Cert2> x509Cert = do_QueryInterface(aCert);
if (!x509Cert) {
ScopedCERTCertificate nssCert(aCert->GetCert());
if (!nssCert) {
return NS_ERROR_INVALID_ARG;
}
ScopedCERTCertificate nssCert(x509Cert->GetCert());
RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
NS_ENSURE_TRUE(certVerifier, NS_ERROR_FAILURE);

View File

@ -6,7 +6,6 @@
#define __NSNSSCERTIFICATEDB_H__
#include "nsIX509CertDB.h"
#include "nsIX509CertDB2.h"
#include "nsNSSShutDown.h"
#include "mozilla/RefPtr.h"
#include "mozilla/Mutex.h"
@ -17,14 +16,12 @@ class nsIArray;
class nsRecentBadCerts;
class nsNSSCertificateDB : public nsIX509CertDB
, public nsIX509CertDB2
, public nsNSSShutDownObject
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIX509CERTDB
NS_DECL_NSIX509CERTDB2
nsNSSCertificateDB();

View File

@ -12,7 +12,6 @@
#include "nsISupportsPrimitives.h"
#include "nsIX509Cert.h"
#include "nsNSSCertificate.h"
#include "nsNSSCertificate.h"
#include "nsString.h"
#include "nsXPIDLString.h"
@ -357,3 +356,55 @@ nsNSSCertificateFakeTransport::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc)
*aClassIDNoAlloc = kNSSCertificateCID;
return NS_OK;
}
NS_IMETHODIMP
nsNSSCertificateFakeTransport::GetCertType(unsigned int*)
{
NS_NOTREACHED("Unimplemented on content process");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsNSSCertificateFakeTransport::GetIsSelfSigned(bool*)
{
NS_NOTREACHED("Unimplemented on content process");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsNSSCertificateFakeTransport::RequestUsagesArrayAsync(nsICertVerificationListener*)
{
NS_NOTREACHED("Unimplemented on content process");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsNSSCertificateFakeTransport::GetAllTokenNames(unsigned int*,
char16_t***)
{
NS_NOTREACHED("Unimplemented on content process");
return NS_ERROR_NOT_IMPLEMENTED;
}
CERTCertificate*
nsNSSCertificateFakeTransport::GetCert()
{
NS_NOTREACHED("Unimplemented on content process");
return nullptr;
}
NS_IMETHODIMP
nsNSSCertificateFakeTransport::ExportAsCMS(unsigned int,
unsigned int*,
unsigned char**)
{
NS_NOTREACHED("Unimplemented on content process");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsNSSCertificateFakeTransport::MarkForPermDeletion()
{
NS_NOTREACHED("Unimplemented on content process");
return NS_ERROR_NOT_IMPLEMENTED;
}

View File

@ -387,16 +387,19 @@ nsNSSSocketInfo::JoinConnection(const nsACString& npnProtocol,
ScopedCERTCertificate nssCert;
nsCOMPtr<nsIX509Cert2> cert2 = do_QueryInterface(SSLStatus()->mServerCert);
if (cert2)
nssCert = cert2->GetCert();
nsCOMPtr<nsIX509Cert> cert(SSLStatus()->mServerCert);
if (cert) {
nssCert = cert->GetCert();
}
if (!nssCert)
if (!nssCert) {
return NS_OK;
}
if (CERT_VerifyCertName(nssCert, PromiseFlatCString(hostname).get()) !=
SECSuccess)
return NS_OK;
SECSuccess) {
return NS_OK;
}
// All tests pass - this is joinable
mJoined = true;

View File

@ -10,7 +10,6 @@
#include "nspr.h"
#include "nsIX509Cert.h"
#include "nsIX509Cert3.h"
#include "nsProxyRelease.h"
class nsBaseVerificationJob

View File

@ -8,9 +8,6 @@
do_get_profile(); // must be called before getting nsIX509CertDB
const certdb = Cc["@mozilla.org/security/x509certdb;1"]
.getService(Ci.nsIX509CertDB);
const certdb2 = Cc["@mozilla.org/security/x509certdb;1"]
.getService(Ci.nsIX509CertDB2);
// This is the list of certificates needed for the test
// The certificates prefixed by 'int-' are intermediates
let certList = [
@ -29,7 +26,7 @@ function load_cert(cert_name, trust_string) {
// the ones that I am interested in.
function get_ca_array() {
let ret_array = new Array();
let allCerts = certdb2.getCerts();
let allCerts = certdb.getCerts();
let enumerator = allCerts.getEnumerator();
while (enumerator.hasMoreElements()) {
let cert = enumerator.getNext().QueryInterface(Ci.nsIX509Cert);

View File

@ -25,7 +25,7 @@ let { FileUtils } = Cu.import("resource://gre/modules/FileUtils.jsm", {});
let { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
let gCertDB = Cc["@mozilla.org/security/x509certdb;1"]
.getService(Ci.nsIX509CertDB2);
.getService(Ci.nsIX509CertDB);
gCertDB.QueryInterface(Ci.nsIX509CertDB);
const BUILT_IN_NICK_PREFIX = "Builtin Object Token:";
@ -108,8 +108,7 @@ function isBuiltinToken(tokenName) {
}
function isCertBuiltIn(cert) {
let cert3 = cert.QueryInterface(Ci.nsIX509Cert3);
let tokenNames = cert3.getAllTokenNames({});
let tokenNames = cert.getAllTokenNames({});
if (!tokenNames) {
return false;
}

View File

@ -12,6 +12,7 @@ SOURCES += [
'pkix_cert_extension_tests.cpp',
'pkix_ocsp_request_tests.cpp',
'pkixcheck_CheckKeyUsage_tests.cpp',
'pkixcheck_CheckTimes_tests.cpp',
'pkixder_input_tests.cpp',
'pkixder_pki_types_tests.cpp',
'pkixder_universal_types_tests.cpp',

View File

@ -0,0 +1,174 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This code is made available to you under your choice of the following sets
* of licensing terms:
*/
/* 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/.
*/
/* Copyright 2014 Mozilla Contributors
*
* 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 "pkixgtest.h"
#include "pkixtestutil.h"
using namespace mozilla::pkix;
using namespace mozilla::pkix::test;
namespace mozilla { namespace pkix {
extern Result CheckTimes(const CERTValidity& validity, PRTime time);
} } // namespace mozilla::pkix
static const SECItem empty_null = { siBuffer, nullptr, 0 };
static const PRTime PAST_TIME(YMDHMS(1998, 12, 31, 12, 23, 56));
static const uint8_t OLDER_GENERALIZEDTIME_DATA[] = {
'1', '9', '9', '9', '0', '1', '0', '1', // 1999-01-01
'0', '0', '0', '0', '0', '0', 'Z' // 00:00:00Z
};
static const SECItem OLDER_GENERALIZEDTIME = {
siGeneralizedTime,
const_cast<uint8_t*>(OLDER_GENERALIZEDTIME_DATA),
sizeof(OLDER_GENERALIZEDTIME_DATA)
};
static const uint8_t OLDER_UTCTIME_DATA[] = {
'9', '9', '0', '1', '0', '1', // (19)99-01-01
'0', '0', '0', '0', '0', '0', 'Z' // 00:00:00Z
};
static const SECItem OLDER_UTCTIME = {
siUTCTime,
const_cast<uint8_t*>(OLDER_UTCTIME_DATA),
sizeof(OLDER_UTCTIME_DATA)
};
static const PRTime NOW(YMDHMS(2016, 12, 31, 12, 23, 56));
static const uint8_t NEWER_GENERALIZEDTIME_DATA[] = {
'2', '0', '2', '1', '0', '1', '0', '1', // 2021-01-01
'0', '0', '0', '0', '0', '0', 'Z' // 00:00:00Z
};
static const SECItem NEWER_GENERALIZEDTIME = {
siGeneralizedTime,
const_cast<uint8_t*>(NEWER_GENERALIZEDTIME_DATA),
sizeof(NEWER_GENERALIZEDTIME_DATA)
};
static const uint8_t NEWER_UTCTIME_DATA[] = {
'2', '1', '0', '1', '0', '1', // 2021-01-01
'0', '0', '0', '0', '0', '0', 'Z' // 00:00:00Z
};
static const SECItem NEWER_UTCTIME = {
siUTCTime,
const_cast<uint8_t*>(NEWER_UTCTIME_DATA),
sizeof(NEWER_UTCTIME_DATA)
};
static const PRTime FUTURE_TIME(YMDHMS(2025, 12, 31, 12, 23, 56));
class pkixcheck_CheckTimes : public ::testing::Test
{
public:
virtual void SetUp()
{
PR_SetError(0, 0);
}
};
TEST_F(pkixcheck_CheckTimes, BothEmptyNull)
{
static const CERTValidity validity = { nullptr, empty_null, empty_null };
ASSERT_RecoverableError(SEC_ERROR_EXPIRED_CERTIFICATE,
CheckTimes(validity, NOW));
}
TEST_F(pkixcheck_CheckTimes, NotBeforeEmptyNull)
{
static const CERTValidity validity = { nullptr, empty_null, NEWER_UTCTIME };
ASSERT_RecoverableError(SEC_ERROR_EXPIRED_CERTIFICATE,
CheckTimes(validity, NOW));
}
TEST_F(pkixcheck_CheckTimes, NotAfterEmptyNull)
{
static const CERTValidity validity = { nullptr, OLDER_UTCTIME, empty_null };
ASSERT_RecoverableError(SEC_ERROR_EXPIRED_CERTIFICATE,
CheckTimes(validity, NOW));
}
TEST_F(pkixcheck_CheckTimes, Valid_UTCTIME_UTCTIME)
{
static const CERTValidity validity = {
nullptr, OLDER_UTCTIME, NEWER_UTCTIME
};
ASSERT_Success(CheckTimes(validity, NOW));
}
TEST_F(pkixcheck_CheckTimes, Valid_GENERALIZEDTIME_GENERALIZEDTIME)
{
static const CERTValidity validity = {
nullptr, OLDER_GENERALIZEDTIME, NEWER_GENERALIZEDTIME
};
ASSERT_Success(CheckTimes(validity, NOW));
}
TEST_F(pkixcheck_CheckTimes, Valid_GENERALIZEDTIME_UTCTIME)
{
static const CERTValidity validity = {
nullptr, OLDER_GENERALIZEDTIME, NEWER_UTCTIME
};
ASSERT_Success(CheckTimes(validity, NOW));
}
TEST_F(pkixcheck_CheckTimes, Valid_UTCTIME_GENERALIZEDTIME)
{
static const CERTValidity validity = {
nullptr, OLDER_UTCTIME, NEWER_GENERALIZEDTIME
};
ASSERT_Success(CheckTimes(validity, NOW));
}
TEST_F(pkixcheck_CheckTimes, InvalidBeforeNotBefore)
{
static const CERTValidity validity = {
nullptr, OLDER_UTCTIME, NEWER_UTCTIME
};
ASSERT_RecoverableError(SEC_ERROR_EXPIRED_CERTIFICATE,
CheckTimes(validity, PAST_TIME));
}
TEST_F(pkixcheck_CheckTimes, InvalidAfterNotAfter)
{
static const CERTValidity validity = {
nullptr, OLDER_UTCTIME, NEWER_UTCTIME
};
ASSERT_RecoverableError(SEC_ERROR_EXPIRED_CERTIFICATE,
CheckTimes(validity, FUTURE_TIME));
}
TEST_F(pkixcheck_CheckTimes, InvalidNotAfterBeforeNotBefore)
{
static const CERTValidity validity = {
nullptr, NEWER_UTCTIME, OLDER_UTCTIME
};
ASSERT_RecoverableError(SEC_ERROR_EXPIRED_CERTIFICATE,
CheckTimes(validity, NOW));
}

View File

@ -28,9 +28,11 @@
#include "pkix/bind.h"
#include "pkixder.h"
#include "pkixtestutil.h"
#include "stdint.h"
using namespace mozilla::pkix::der;
using namespace mozilla::pkix::test;
using namespace std;
namespace {
@ -305,23 +307,6 @@ TEST_F(pkixder_universal_types_tests, EnumeratedInvalidZeroLength)
ASSERT_EQ(SEC_ERROR_BAD_DER, PR_GetError());
}
static PRTime
YMDHMS(int16_t year, int16_t month, int16_t day,
int16_t hour, int16_t minutes, int16_t seconds)
{
PRExplodedTime tm;
tm.tm_usec = 0;
tm.tm_sec = seconds;
tm.tm_min = minutes;
tm.tm_hour = hour;
tm.tm_mday = day;
tm.tm_month = month - 1; // tm_month is zero-based
tm.tm_year = year;
tm.tm_params.tp_gmt_offset = 0;
tm.tm_params.tp_dst_offset = 0;
return PR_ImplodeTime(&tm);
}
////////////////////////////////////////
// GeneralizedTime and TimeChoice
//

View File

@ -428,6 +428,23 @@ PRTimeToTimeChoice(PLArenaPool* arena, PRTime time)
: GeneralizedTime);
}
PRTime
YMDHMS(int16_t year, int16_t month, int16_t day,
int16_t hour, int16_t minutes, int16_t seconds)
{
PRExplodedTime tm;
tm.tm_usec = 0;
tm.tm_sec = seconds;
tm.tm_min = minutes;
tm.tm_hour = hour;
tm.tm_mday = day;
tm.tm_month = month - 1; // tm_month is zero-based
tm.tm_year = year;
tm.tm_params.tp_gmt_offset = 0;
tm.tm_params.tp_dst_offset = 0;
return PR_ImplodeTime(&tm);
}
static SECItem*
SignedData(PLArenaPool* arena, const SECItem* tbsData,
SECKEYPrivateKey* privKey, SECOidTag hashAlg,

View File

@ -62,6 +62,10 @@ FILE* OpenFile(const char* dir, const char* filename, const char* mode);
extern const PRTime ONE_DAY;
// e.g. YMDHMS(2016, 12, 31, 1, 23, 45) => 2016-12-31:01:23:45 (GMT)
PRTime YMDHMS(int16_t year, int16_t month, int16_t day,
int16_t hour, int16_t minutes, int16_t seconds);
SECStatus GenerateKeyPair(/*out*/ ScopedSECKEYPublicKey& publicKey,
/*out*/ ScopedSECKEYPrivateKey& privateKey);

View File

@ -4,7 +4,6 @@
"robocop": "TIMED_OUT",
"content/canvas/test/webgl-conformance": "bug 865443 - separate suite -- mochitest-gl",
"content/canvas/test/webgl-mochitest/test_no_arr_points.html": "Android 2.3 aws only; bug 1030942",
"content/html/content/test/test_bug659743.xml": "Android 2.3 aws only; bug 1031103",
"docshell/test/navigation/test_reserved.html": "too slow on Android 2.3 aws only; bug 1030403",
"dom/media/tests/mochitest": "Android 2.3 only; bug 981881",
"layout/style/test/test_media_queries.html": "Android 2.3 aws only; bug 1030419",

View File

@ -537,20 +537,33 @@ class DeviceManagerSUT(DeviceManager):
def killProcess(self, appname, sig=None):
if sig:
self._logger.warn("killProcess(): sig parameter unsupported on SUT")
retries = 0
while retries < self.retryLimit:
try:
if self.processExist(appname):
self._runCmds([{ 'cmd': 'kill ' + appname }])
return
except DMError, err:
retries +=1
self._logger.warn("try %d of %d failed to kill %s" %
(retries, self.retryLimit, appname))
self._logger.debug(err)
if retries >= self.retryLimit:
pid = self.processExist(appname)
if pid and pid > 0:
try:
self.shellCheckOutput(['kill', '-%d' % sig, str(pid)],
root=True)
except DMError, err:
self._logger.warn("unable to kill -%d %s (pid %s)" %
(sig, appname, str(pid)))
self._logger.debug(err)
raise err
else:
self._logger.warn("unable to kill -%d %s -- not running?" %
(sig, appname))
else:
retries = 0
while retries < self.retryLimit:
try:
if self.processExist(appname):
self._runCmds([{ 'cmd': 'kill ' + appname }])
return
except DMError, err:
retries += 1
self._logger.warn("try %d of %d failed to kill %s" %
(retries, self.retryLimit, appname))
self._logger.debug(err)
if retries >= self.retryLimit:
raise err
def getTempDir(self):
return self._runCmds([{ 'cmd': 'tmpd' }]).strip()

View File

@ -2959,6 +2959,28 @@
"extended_statistics_ok": true,
"description": "PLACES: Time to calculate the md5 hash for a backup"
},
"FENNEC_DISTRIBUTION_REFERRER_INVALID": {
"expires_in_version": "never",
"kind": "flag",
"description": "Whether the referrer intent specified an invalid distribution name",
"cpp_guard": "ANDROID"
},
"FENNEC_DISTRIBUTION_CODE_CATEGORY": {
"expires_in_version": "never",
"kind": "enumerated",
"n_values": 20,
"description": "First digit of HTTP result code, or error category, during distribution download",
"cpp_guard": "ANDROID"
},
"FENNEC_DISTRIBUTION_DOWNLOAD_TIME_MS": {
"expires_in_version": "never",
"kind": "exponential",
"low": 100,
"high": "40000",
"n_buckets": 30,
"description": "Time taken to download a specified distribution file (msec)",
"cpp_guard": "ANDROID"
},
"FENNEC_FAVICONS_COUNT": {
"expires_in_version": "never",
"kind": "exponential",

View File

@ -39,10 +39,9 @@ const UDPSocket = CC("@mozilla.org/network/udp-socket;1",
"nsIUDPSocket",
"init");
// TODO Bug 1027456: May need to reserve these with IANA
const SCAN_PORT = 50624;
const UPDATE_PORT = 50625;
const ADDRESS = "224.0.0.200";
const ADDRESS = "224.0.0.115";
const REPLY_TIMEOUT = 5000;
const { XPCOMUtils } = Cu.import("resource://gre/modules/XPCOMUtils.jsm", {});
@ -158,6 +157,8 @@ function Discovery() {
this._onRemoteUpdate = this._onRemoteUpdate.bind(this);
this._purgeMissingDevices = this._purgeMissingDevices.bind(this);
Services.obs.addObserver(this, "network-active-changed", false);
this._getSystemInfo();
}
@ -295,6 +296,35 @@ Discovery.prototype = {
this._transports.update = null;
},
observe: function(subject, topic, data) {
if (topic !== "network-active-changed") {
return;
}
let activeNetwork = subject;
if (!activeNetwork) {
log("No active network");
return;
}
activeNetwork = activeNetwork.QueryInterface(Ci.nsINetworkInterface);
log("Active network changed to: " + activeNetwork.type);
// UDP sockets go down when the device goes offline, so we'll restart them
// when the active network goes back to WiFi.
if (activeNetwork.type === Ci.nsINetworkInterface.NETWORK_TYPE_WIFI) {
this._restartListening();
}
},
_restartListening: function() {
if (this._transports.scan) {
this._stopListeningForScan();
this._startListeningForScan();
}
if (this._transports.update) {
this._stopListeningForUpdate();
this._startListeningForUpdate();
}
},
/**
* When sending message, we can use either transport, so just pick the first
* one currently alive.

View File

@ -363,7 +363,7 @@ let WebAudioActor = exports.WebAudioActor = protocol.ActorClass({
let { caller, args, window, name } = functionCall.details;
let source = caller;
let dest = args[0];
let isAudioParam = dest instanceof window.AudioParam;
let isAudioParam = dest ? getConstructorName(dest) === "AudioParam" : false;
// audionode.connect(param)
if (name === "connect" && isAudioParam) {
@ -433,8 +433,9 @@ let WebAudioActor = exports.WebAudioActor = protocol.ActorClass({
},
"connect-param": {
type: "connectParam",
source: Arg(0, "audionode"),
param: Arg(1, "string")
source: Option(0, "audionode"),
dest: Option(0, "audionode"),
param: Option(0, "string")
},
"change-param": {
type: "changeParam",
@ -461,12 +462,30 @@ let WebAudioActor = exports.WebAudioActor = protocol.ActorClass({
// Ensure AudioNode is wrapped.
node = new XPCNativeWrapper(node);
this._instrumentParams(node);
let actor = new AudioNodeActor(this.conn, node);
this.manage(actor);
this._nativeToActorID.set(node.id, actor.actorID);
return actor;
},
/**
* Takes an XrayWrapper node, and attaches the node's `nativeID`
* to the AudioParams as `_parentID`, as well as the the type of param
* as a string on `_paramName`.
*/
_instrumentParams: function (node) {
let type = getConstructorName(node);
Object.keys(NODE_PROPERTIES[type])
.filter(isAudioParam.bind(null, node))
.forEach(paramName => {
let param = node[paramName];
param._parentID = node.id;
param._paramName = paramName;
});
},
/**
* Takes an AudioNode and returns the stored actor for it.
* In some cases, we won't have an actor stored (for example,
@ -505,10 +524,15 @@ let WebAudioActor = exports.WebAudioActor = protocol.ActorClass({
/**
* Called when an audio node is connected to an audio param.
* Implement in bug 986705
*/
_onConnectParam: function (source, dest) {
// TODO bug 986705
_onConnectParam: function (source, param) {
let sourceActor = this._getActorByNativeID(source.id);
let destActor = this._getActorByNativeID(param._parentID);
emit(this, "connect-param", {
source: sourceActor,
dest: destActor,
param: param._paramName
});
},
/**

View File

@ -167,7 +167,6 @@ this.checkCert =
if (!issuerCert)
throw new Ce(certNotBuiltInErr, Cr.NS_ERROR_ABORT);
issuerCert = issuerCert.QueryInterface(Ci.nsIX509Cert3);
var tokenNames = issuerCert.getAllTokenNames({});
if (!tokenNames || !tokenNames.some(isBuiltinToken))

View File

@ -83,6 +83,7 @@ const PREFS_WHITELIST = [
const PREFS_BLACKLIST = [
/^network[.]proxy[.]/,
/[.]print_to_filename$/,
/^print[.]macosx[.]pagesetup/,
];
this.Troubleshoot = {

View File

@ -15,120 +15,27 @@
* limitations under the License.
*/
#include <fcntl.h>
#include <linux/fb.h>
#include <linux/kd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
#include <vector>
#include "Framebuffer.h"
#include "android/log.h"
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/ioctl.h>
#include "Framebuffer.h"
#include "gfxContext.h"
#include "gfxImageSurface.h"
#include "gfxUtils.h"
#include "nsSize.h"
#include "mozilla/FileUtils.h"
#include "nsTArray.h"
#include "nsRegion.h"
#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args)
#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args)
using namespace std;
namespace mozilla {
namespace Framebuffer {
static int sFd = -1;
static size_t sMappedSize;
static struct fb_var_screeninfo sVi;
static size_t sActiveBuffer;
typedef vector<nsRefPtr<gfxImageSurface> > BufferVector;
BufferVector* sBuffers;
static gfxIntSize *sScreenSize = nullptr;
BufferVector& Buffers() { return *sBuffers; }
bool
SetGraphicsMode()
{
ScopedClose fd(open("/dev/tty0", O_RDWR | O_SYNC));
if (0 > fd.get()) {
// This is non-fatal; post-Cupcake kernels don't have tty0.
LOG("No /dev/tty0?");
} else if (ioctl(fd.get(), KDSETMODE, (void*) KD_GRAPHICS)) {
LOG("Error setting graphics mode on /dev/tty0");
return false;
}
return true;
}
bool
Open()
{
if (0 <= sFd)
return true;
if (!SetGraphicsMode())
return false;
ScopedClose fd(open("/dev/graphics/fb0", O_RDWR));
if (0 > fd.get()) {
LOG("Error opening framebuffer device");
return false;
}
struct fb_fix_screeninfo fi;
if (0 > ioctl(fd.get(), FBIOGET_FSCREENINFO, &fi)) {
LOG("Error getting fixed screeninfo");
return false;
}
if (0 > ioctl(fd.get(), FBIOGET_VSCREENINFO, &sVi)) {
LOG("Error getting variable screeninfo");
return false;
}
sMappedSize = fi.smem_len;
void* mem = mmap(0, sMappedSize, PROT_READ | PROT_WRITE, MAP_SHARED,
fd.rwget(), 0);
if (MAP_FAILED == mem) {
LOG("Error mmap'ing framebuffer");
return false;
}
sFd = fd.get();
fd.forget();
// The android porting doc requires a /dev/graphics/fb0 device
// that's double buffered with r5g6b5 format. Hence the
// hard-coded numbers here.
gfxImageFormat format = gfxImageFormat::RGB16_565;
if (!sScreenSize) {
sScreenSize = new gfxIntSize(sVi.xres, sVi.yres);
}
long stride = fi.line_length;
size_t numFrameBytes = stride * sScreenSize->height;
sBuffers = new BufferVector(2);
unsigned char* data = static_cast<unsigned char*>(mem);
for (size_t i = 0; i < 2; ++i, data += numFrameBytes) {
memset(data, 0, numFrameBytes);
Buffers()[i] = new gfxImageSurface(data, *sScreenSize, stride, format);
}
// Clear the framebuffer to a known state.
Present(nsIntRect());
return true;
}
bool
GetSize(nsIntSize *aScreenSize) {
// If the framebuffer has been opened, we should always have the size.
@ -153,54 +60,5 @@ GetSize(nsIntSize *aScreenSize) {
return true;
}
void
Close()
{
if (0 > sFd)
return;
munmap(Buffers()[0]->Data(), sMappedSize);
delete sBuffers;
sBuffers = nullptr;
delete sScreenSize;
sScreenSize = nullptr;
close(sFd);
sFd = -1;
}
gfxASurface*
BackBuffer()
{
return Buffers()[!sActiveBuffer];
}
static gfxASurface*
FrontBuffer()
{
return Buffers()[sActiveBuffer];
}
void
Present(const nsIntRegion& aUpdated)
{
sActiveBuffer = !sActiveBuffer;
sVi.yres_virtual = sVi.yres * 2;
sVi.yoffset = sActiveBuffer * sVi.yres;
sVi.bits_per_pixel = 16;
if (ioctl(sFd, FBIOPUT_VSCREENINFO, &sVi) < 0) {
LOG("Error presenting front buffer");
}
nsRefPtr<gfxContext> ctx = new gfxContext(BackBuffer());
gfxUtils::PathFromRegion(ctx, aUpdated);
ctx->Clip();
ctx->SetSource(FrontBuffer());
ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
ctx->Paint(1.0);
}
} // namespace Framebuffer
} // namespace mozilla

View File

@ -15,48 +15,14 @@
* limitations under the License.
*/
class gfxASurface;
class nsIntRegion;
class nsIntSize;
namespace mozilla {
namespace Framebuffer {
//
// The general usage of Framebuffer is
//
// -- in initialization code --
// Open();
//
// -- ready to paint next frame --
// nsRefPtr<gfxASurface> backBuffer = BackBuffer();
// // ...
// Paint(backBuffer);
// // ...
// Present();
//
// Return true if the fbdev was successfully opened. If this fails,
// the result of all further calls is undefined. Open() is idempotent.
bool Open();
// After Close(), the result of all further calls is undefined.
// Close() is idempotent, and Open() can be called again after
// Close().
void Close();
// Return true if the fbdev was successfully opened or the size was
// already cached.
bool GetSize(nsIntSize *aScreenSize);
// Return the buffer to be drawn into, that will be the next frame.
gfxASurface* BackBuffer();
// Swap the front buffer for the back buffer. |aUpdated| is the
// region of the back buffer that was repainted.
void Present(const nsIntRegion& aUpdated);
} // namespace Framebuffer
} // namespace mozilla

View File

@ -19,9 +19,9 @@
#include "libdisplay/GonkDisplay.h"
#include "Framebuffer.h"
#include "GLContext.h" // for GLContext
#include "HwcUtils.h"
#include "HwcComposer2D.h"
#include "LayerScope.h"
#include "mozilla/layers/LayerManagerComposite.h"
#include "mozilla/layers/PLayerTransaction.h"
#include "mozilla/layers/ShadowLayerUtilsGralloc.h"
@ -807,8 +807,12 @@ HwcComposer2D::TryRender(Layer* aRoot,
return false;
}
// Send data to LayerScope for debugging
SendtoLayerScope();
if (!TryHwComposition()) {
LOGD("H/W Composition failed");
LayerScope::CleanLayer();
return false;
}
@ -816,4 +820,19 @@ HwcComposer2D::TryRender(Layer* aRoot,
return true;
}
void
HwcComposer2D::SendtoLayerScope()
{
if (!LayerScope::CheckSendable()) {
return;
}
const int len = mList->numHwLayers;
for (int i = 0; i < len; ++i) {
LayerComposite* layer = mHwcLayerMap[i];
const hwc_rect_t r = mList->hwLayers[i].displayFrame;
LayerScope::SendLayer(layer, r.right - r.left, r.bottom - r.top);
}
}
} // namespace mozilla

View File

@ -97,6 +97,7 @@ private:
const gfxMatrix& aParentTransform, const gfxMatrix& aGLWorldTransform);
void setCrop(HwcLayer* layer, hwc_rect_t srcCrop);
void setHwcGeometry(bool aGeometryChanged);
void SendtoLayerScope();
HwcDevice* mHwc;
HwcList* mList;

View File

@ -68,14 +68,10 @@ static uint32_t sScreenRotation;
static uint32_t sPhysicalScreenRotation;
static nsIntRect sVirtualBounds;
static nsRefPtr<GLContext> sGLContext;
static nsTArray<nsWindow *> sTopWindows;
static nsWindow *gFocusedWindow = nullptr;
static bool sFramebufferOpen;
static bool sUsingOMTC;
static bool sUsingHwc;
static bool sScreenInitialized;
static nsRefPtr<gfxASurface> sOMTCSurface;
namespace {
@ -160,15 +156,11 @@ nsWindow::nsWindow()
// to know the color depth, which asks our native window.
// This has to happen after other init has finished.
gfxPlatform::GetPlatform();
sUsingOMTC = ShouldUseOffMainThreadCompositing();
if (!ShouldUseOffMainThreadCompositing()) {
MOZ_CRASH("How can we render apps, then?");
}
//Update sUsingHwc whenever layers.composer2d.enabled changes
Preferences::AddBoolVarCache(&sUsingHwc, "layers.composer2d.enabled");
if (sUsingOMTC) {
sOMTCSurface = new gfxImageSurface(gfxIntSize(1, 1),
gfxImageFormat::RGB24);
}
}
}
@ -201,35 +193,6 @@ nsWindow::DoDraw(void)
LayerManager* lm = targetWindow->GetLayerManager();
if (mozilla::layers::LayersBackend::LAYERS_CLIENT == lm->GetBackendType()) {
// No need to do anything, the compositor will handle drawing
} else if (mozilla::layers::LayersBackend::LAYERS_BASIC == lm->GetBackendType()) {
MOZ_ASSERT(sFramebufferOpen || sUsingOMTC);
nsRefPtr<gfxASurface> targetSurface;
if(sUsingOMTC)
targetSurface = sOMTCSurface;
else
targetSurface = Framebuffer::BackBuffer();
{
nsRefPtr<gfxContext> ctx = new gfxContext(targetSurface);
gfxUtils::PathFromRegion(ctx, sVirtualBounds);
ctx->Clip();
// No double-buffering needed.
AutoLayerManagerSetup setupLayerManager(
targetWindow, ctx, mozilla::layers::BufferMode::BUFFER_NONE,
ScreenRotation(EffectiveScreenRotation()));
listener = targetWindow->GetWidgetListener();
if (listener) {
listener->PaintWindow(targetWindow, sVirtualBounds);
}
}
if (!sUsingOMTC) {
targetSurface->Flush();
Framebuffer::Present(sVirtualBounds);
}
} else {
NS_RUNTIMEABORT("Unexpected layer manager type");
}
@ -537,12 +500,7 @@ nsWindow::GetLayerManager(PLayerTransactionChild* aShadowManager,
if (mLayerManager) {
// This layer manager might be used for painting outside of DoDraw(), so we need
// to set the correct rotation on it.
if (mLayerManager->GetBackendType() == LayersBackend::LAYERS_BASIC) {
BasicLayerManager* manager =
static_cast<BasicLayerManager*>(mLayerManager.get());
manager->SetDefaultTargetConfiguration(mozilla::layers::BufferMode::BUFFER_NONE,
ScreenRotation(EffectiveScreenRotation()));
} else if (mLayerManager->GetBackendType() == LayersBackend::LAYERS_CLIENT) {
if (mLayerManager->GetBackendType() == LayersBackend::LAYERS_CLIENT) {
ClientLayerManager* manager =
static_cast<ClientLayerManager*>(mLayerManager.get());
manager->SetDefaultTargetConfiguration(mozilla::layers::BufferMode::BUFFER_NONE,
@ -561,38 +519,13 @@ nsWindow::GetLayerManager(PLayerTransactionChild* aShadowManager,
return nullptr;
}
if (sUsingOMTC) {
CreateCompositor();
if (mCompositorParent) {
uint64_t rootLayerTreeId = mCompositorParent->RootLayerTreeId();
CompositorParent::SetControllerForLayerTree(rootLayerTreeId, new ParentProcessController());
CompositorParent::GetAPZCTreeManager(rootLayerTreeId)->SetDPI(GetDPI());
}
if (mLayerManager)
return mLayerManager;
CreateCompositor();
if (mCompositorParent) {
uint64_t rootLayerTreeId = mCompositorParent->RootLayerTreeId();
CompositorParent::SetControllerForLayerTree(rootLayerTreeId, new ParentProcessController());
CompositorParent::GetAPZCTreeManager(rootLayerTreeId)->SetDPI(GetDPI());
}
if (mUseLayersAcceleration) {
DebugOnly<nsIntRect> fbBounds = gScreenBounds;
if (!sGLContext) {
sGLContext = GLContextProvider::CreateForWindow(this);
}
MOZ_ASSERT(fbBounds.value == gScreenBounds);
}
// Fall back to software rendering.
sFramebufferOpen = Framebuffer::Open();
if (sFramebufferOpen) {
LOG("Falling back to framebuffer software rendering");
} else {
LOGE("Failed to mmap fb(?!?), aborting ...");
NS_RUNTIMEABORT("Can't open GL context and can't fall back on /dev/graphics/fb0 ...");
}
mLayerManager = new ClientLayerManager(this);
mUseLayersAcceleration = false;
MOZ_ASSERT(mLayerManager);
return mLayerManager;
}

View File

@ -172,7 +172,7 @@ static void DeferredDestroyCompositor(CompositorParent* aCompositorParent,
void nsBaseWidget::DestroyCompositor()
{
LayerScope::DestroyServerSocket();
LayerScope::DeInit();
if (mCompositorChild) {
mCompositorChild->SendWillStop();
@ -900,8 +900,8 @@ void nsBaseWidget::CreateCompositor(int aWidth, int aHeight)
return;
}
// The server socket has to be created on the main thread.
LayerScope::CreateServerSocket();
// Initialize LayerScope on the main thread.
LayerScope::Init();
mCompositorParent = NewCompositorParent(aWidth, aHeight);
MessageChannel *parentChannel = mCompositorParent->GetIPCChannel();

View File

@ -33,8 +33,7 @@ else:
'xptcinvoke.cpp',
'xptcstubs.cpp',
]
if CONFIG['TARGET_CPU'] == 'x86_64' or CONFIG['GNU_CXX']:
SOURCES['xptcinvoke.cpp'].no_pgo = True
SOURCES['xptcinvoke.cpp'].no_pgo = True
FINAL_LIBRARY = 'xpcom_core'
@ -42,8 +41,3 @@ LOCAL_INCLUDES += [
'../..',
'/xpcom/reflect/xptinfo',
]
if CONFIG['TARGET_CPU'] != 'x86_64':
if not CONFIG['GNU_CXX']:
# FIXME: bug 413019
NO_PGO = True