Bug 1337062 - Transfer initial gfxVars over command line - r=blassey

When a subprocess is launched, gfxVars updates (for non-default values) are
serialized and passed on the command line, up to a limit of 1023 characters,
and ensuring it should not overflow the command line size.

When the child starts, the command line parameter is given to gfxVars, so the
updates can be used during gfxVars::Initialize(), instead of doing a sync
request to the parent.

In case the updates are not sent, or in the unlikely case the child cannot
parse them, we fallback to the sync request -- The former case should be rare
enough that a slow sync request is acceptable: It should only happen if D3D
block-list is *modified* (most people would either use the default, or just
overwrite these prefs with short strings.)

MozReview-Commit-ID: 6MoJC0fe59Q

--HG--
extra : rebase_source : cdc2e451783160c579b8fc84050e8457c600523e
This commit is contained in:
Gerald Squelart 2017-03-28 12:16:41 +11:00
parent 04137c02ea
commit 9c16b0ccdc
4 changed files with 236 additions and 7 deletions

View File

@ -2039,6 +2039,35 @@ ContentParent::LaunchSubprocess(ProcessPriority aInitialPriority /* = PROCESS_PR
extraArgs.push_back("-stringPrefs");
extraArgs.push_back(stringPrefs.get());
char gfxBuf[1024];
nsFixedCString gfxVarsUpdates(gfxBuf, 1024, 0);
if (gfxVars::SerializeNonDefaultVarUpdates(gfxVarsUpdates, 1023)) {
// Don't add gfxVarsUpdates if they risk taking too much command line space.
const size_t maxArg =
#ifdef XP_WIN
8191;
#else
size_t(sysconf(_SC_ARG_MAX));
#endif
size_t extraArgsLength = 0;
for (const std::string& arg : extraArgs) {
extraArgsLength += arg.size() + 1;
}
if (extraArgsLength + size_t(gfxVarsUpdates.Length()) + 1024 < maxArg) {
extraArgs.push_back("-gfxVars");
if (gfxVarsUpdates.IsEmpty()) {
// Don't pass an empty string.
extraArgs.push_back("0");
} else {
extraArgs.push_back(gfxVarsUpdates.get());
}
// Since we have sent all gfxVarsUpdates known so far, we can start
// listening for updates.
gfxVars::AddReceiver(this);
}
}
if (gSafeMode) {
extraArgs.push_back("-safeMode");
}

View File

@ -20,6 +20,8 @@
#include "nsDirectoryServiceDefs.h"
#endif
#include "mozilla/gfx/gfxVars.h"
using mozilla::ipc::IOThreadChild;
namespace mozilla {
@ -203,8 +205,14 @@ ContentProcess::Init(int aArgc, char* aArgv[])
}
SET_PREF_PHASE(END_INIT_PREFS);
foundStringPrefs = true;
}
else if (!strcmp(aArgv[idx], "-safeMode")) {
} else if (!strcmp(aArgv[idx], "-gfxVars")) {
SET_PREF_PHASE(BEGIN_INIT_PREFS);
char* str = aArgv[idx + 1];
if (str[0] != '0' || str[1] != '\0') {
gfxVars::GotSerializedInitialVarUpdates(aArgv[idx + 1]);
}
SET_PREF_PHASE(END_INIT_PREFS);
} else if (!strcmp(aArgv[idx], "-safeMode")) {
gSafeMode = true;
}

View File

@ -7,14 +7,17 @@
#include "gfxVars.h"
#include "gfxVarReceiver.h"
#include "mozilla/dom/ContentChild.h"
#include "nsPrintfCString.h"
namespace mozilla {
namespace gfx {
StaticAutoPtr<gfxVars> gfxVars::sInstance;
StaticAutoPtr<nsTArray<gfxVars::VarBase*>> gfxVars::sVarList;
const char* gfxVars::sSerializedInitialVarUpdates = nullptr;
void
/* static */ void
gfxVars::Initialize()
{
if (sInstance) {
@ -30,10 +33,13 @@ gfxVars::Initialize()
// init. Note the GPU process is not handled here - it cannot send sync
// messages, so instead the initial data is pushed down.
if (XRE_IsContentProcess()) {
InfallibleTArray<GfxVarUpdate> vars;
dom::ContentChild::GetSingleton()->SendGetGfxVars(&vars);
for (const auto& var : vars) {
ApplyUpdate(var);
if (!ApplySerializedVarUpdates(sSerializedInitialVarUpdates)) {
// No initial updates, or could not apply them -> Try sync retrieval.
InfallibleTArray<GfxVarUpdate> vars;
dom::ContentChild::GetSingleton()->SendGetGfxVars(&vars);
for (const auto& var : vars) {
ApplyUpdate(var);
}
}
}
}
@ -101,6 +107,183 @@ gfxVars::FetchNonDefaultVars()
return updates;
}
/* static */ bool
gfxVars::SerializeNonDefaultVarUpdates(nsACString& aUpdates, size_t aMax)
{
MOZ_ASSERT(NS_IsMainThread());
if (!sVarList) {
return false;
}
for (size_t i = 0; i < sVarList->Length(); i++) {
VarBase* var = sVarList->ElementAt(i);
if (var->HasDefaultValue()) {
continue;
}
GfxVarValue value;
var->GetValue(&value);
switch (value.type()) {
case mozilla::gfx::GfxVarValue::TBackendType: {
nsPrintfCString t("T%zu:%d|", i, int(value.get_BackendType()));
if (aUpdates.Length() + t.Length() > aMax) {
return false;
}
aUpdates.Append(t);
}
break;
case mozilla::gfx::GfxVarValue::Tbool: {
nsPrintfCString b("B%zu:%d|",
i, int(value.get_bool()));
if (aUpdates.Length() + b.Length() > aMax) {
return false;
}
aUpdates.Append(b);
}
break;
case mozilla::gfx::GfxVarValue::TgfxImageFormat: {
nsPrintfCString f("F%zu:%d|", i, int(value.get_gfxImageFormat()));
if (aUpdates.Length() + f.Length() > aMax) {
return false;
}
aUpdates.Append(f);
}
break;
case mozilla::gfx::GfxVarValue::TIntSize: {
nsPrintfCString z("Z%zu:%dx%d|",
i,
int(value.get_IntSize().width),
int(value.get_IntSize().height));
if (aUpdates.Length() + z.Length() > aMax) {
return false;
}
aUpdates.Append(z);
}
break;
case mozilla::gfx::GfxVarValue::TnsCString: {
nsPrintfCString s("S%zu:%u;%s|",
i,
value.get_nsCString().Length(),
value.get_nsCString().get());
if (aUpdates.Length() + s.Length() > aMax) {
return false;
}
aUpdates.Append(s);
}
break;
default:
MOZ_ASSERT(false);
return false;
}
}
return true;
}
/* static */ void
gfxVars::GotSerializedInitialVarUpdates(const char* aUpdates)
{
sSerializedInitialVarUpdates = aUpdates;
}
/* static */ bool
gfxVars::ApplySerializedVarUpdates(const char* aUpdates)
{
if (!aUpdates) {
return false;
}
for (const char* p = aUpdates; *p;) {
switch (*p++) {
case 'T': {
int32_t index = strtol(p, const_cast<char**>(&p), 10);
if (*p != ':') {
return false;
}
p++;
int32_t type = strtol(p, const_cast<char**>(&p), 10);
if (*p != '|') {
return false;
}
p++;
ApplyUpdate(GfxVarUpdate(index, GfxVarValue(BackendType(type))));
}
break;
case 'B': {
int32_t index = strtol(p, const_cast<char**>(&p), 10);
if (*p != ':') {
return false;
}
p++;
int32_t b = strtol(p, const_cast<char**>(&p), 10);
if (*p != '|') {
return false;
}
p++;
ApplyUpdate(GfxVarUpdate(index, GfxVarValue(bool(b))));
}
break;
case 'F': {
int32_t index = strtol(p, const_cast<char**>(&p), 10);
if (*p != ':') {
return false;
}
p++;
int32_t format = strtol(p, const_cast<char**>(&p), 10);
if (*p != '|') {
return false;
}
p++;
ApplyUpdate(GfxVarUpdate(index, GfxVarValue(gfxImageFormat(format))));
}
break;
case 'Z': {
int32_t index = strtol(p, const_cast<char**>(&p), 10);
if (*p != ':') {
return false;
}
p++;
int32_t width = strtol(p, const_cast<char**>(&p), 10);
if (*p != 'x') {
return false;
}
p++;
int32_t height = strtol(p, const_cast<char**>(&p), 10);
if (*p != '|') {
return false;
}
p++;
ApplyUpdate(GfxVarUpdate(index, GfxVarValue(IntSize(width, height))));
}
break;
case 'S': {
int32_t index = strtol(p, const_cast<char**>(&p), 10);
if (*p != ':') {
return false;
}
p++;
int32_t length = strtol(p, const_cast<char**>(&p), 10);
if (*p != ';') {
return false;
}
p++;
ApplyUpdate(GfxVarUpdate(index, GfxVarValue(nsCString(p, length))));
p += length;
if (*p++ != '|') {
return false;
}
}
break;
default:
return false;
}
}
return true;
}
gfxVars::VarBase::VarBase()
{
mIndex = gfxVars::sVarList->Length();

View File

@ -66,6 +66,12 @@ public:
// Return a list of updates for all variables with non-default values.
static nsTArray<GfxVarUpdate> FetchNonDefaultVars();
// Fill aUpdates with serialized updates for all variables with non-default
// values. Return true if ok, false if length>aMax or other issue.
static bool SerializeNonDefaultVarUpdates(nsACString& aUpdates, size_t aMax);
// Inform gfxVars that some initial updates are available, to be used from
// a child's Initialize(), instead of doing a sync request to the parent.
static void GotSerializedInitialVarUpdates(const char* aUpdates);
public:
// Each variable must expose Set and Get methods for IPDL.
@ -86,6 +92,7 @@ public:
private:
static StaticAutoPtr<gfxVars> sInstance;
static StaticAutoPtr<nsTArray<VarBase*>> sVarList;
static const char* sSerializedInitialVarUpdates;
template <typename T, T Default()>
class VarImpl final : public VarBase
@ -141,6 +148,8 @@ public: \
private:
gfxVars();
static bool ApplySerializedVarUpdates(const char* aUpdates);
void NotifyReceivers(VarBase* aVar);
private: