diff --git a/b2g/app/b2g.js b/b2g/app/b2g.js
index e574d20eda54..13d99dfbbc02 100644
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -728,22 +728,30 @@ pref("hal.processPriorityManager.gonk.BACKGROUND.KillUnderKB", 20480);
pref("hal.processPriorityManager.gonk.BACKGROUND.cgroup", "apps/bg_non_interactive");
// Control group definitions (i.e., CPU priority groups) for B2G processes.
+//
+// memory_swappiness - 0 - The kernel will swap only to avoid an out of memory condition
+// memory_swappiness - 60 - The default value.
+// memory_swappiness - 100 - The kernel will swap aggressively.
// Foreground apps
pref("hal.processPriorityManager.gonk.cgroups.apps.cpu_shares", 1024);
pref("hal.processPriorityManager.gonk.cgroups.apps.cpu_notify_on_migrate", 0);
+pref("hal.processPriorityManager.gonk.cgroups.apps.memory_swappiness", 10);
// Foreground apps with high priority, 16x more CPU than foreground ones
pref("hal.processPriorityManager.gonk.cgroups.apps/critical.cpu_shares", 16384);
pref("hal.processPriorityManager.gonk.cgroups.apps/critical.cpu_notify_on_migrate", 0);
+pref("hal.processPriorityManager.gonk.cgroups.apps/critical.memory_swappiness", 0);
// Background perceivable apps, ~10x less CPU than foreground ones
pref("hal.processPriorityManager.gonk.cgroups.apps/bg_perceivable.cpu_shares", 103);
pref("hal.processPriorityManager.gonk.cgroups.apps/bg_perceivable.cpu_notify_on_migrate", 0);
+pref("hal.processPriorityManager.gonk.cgroups.apps/bg_perceivable.memory_swappiness", 60);
// Background apps, ~20x less CPU than foreground ones and ~2x less than perceivable ones
pref("hal.processPriorityManager.gonk.cgroups.apps/bg_non_interactive.cpu_shares", 52);
pref("hal.processPriorityManager.gonk.cgroups.apps/bg_non_interactive.cpu_notify_on_migrate", 0);
+pref("hal.processPriorityManager.gonk.cgroups.apps/bg_non_interactive.memory_swappiness", 100);
// By default the compositor thread on gonk runs without real-time priority. RT
// priority can be enabled by setting this pref to a value between 1 and 99.
diff --git a/b2g/config/dolphin/sources.xml b/b2g/config/dolphin/sources.xml
index e7a7f27fd4d5..1b006a0d07cf 100644
--- a/b2g/config/dolphin/sources.xml
+++ b/b2g/config/dolphin/sources.xml
@@ -15,7 +15,7 @@
-
+
@@ -23,7 +23,7 @@
-
+
@@ -115,7 +115,7 @@
-
+
@@ -128,7 +128,7 @@
-
+
diff --git a/b2g/config/emulator-ics/sources.xml b/b2g/config/emulator-ics/sources.xml
index 048973569bb3..dc5a93f946d7 100644
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -19,13 +19,13 @@
-
+
-
+
diff --git a/b2g/config/emulator-jb/sources.xml b/b2g/config/emulator-jb/sources.xml
index f4854c918e9b..df9791cf8438 100644
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -17,10 +17,10 @@
-
+
-
+
@@ -117,7 +117,7 @@
-
+
diff --git a/b2g/config/emulator-kk/sources.xml b/b2g/config/emulator-kk/sources.xml
index b8f95ba88e3a..85dfea2ad313 100644
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -15,7 +15,7 @@
-
+
@@ -23,7 +23,7 @@
-
+
@@ -115,7 +115,7 @@
-
+
diff --git a/b2g/config/emulator/sources.xml b/b2g/config/emulator/sources.xml
index 048973569bb3..dc5a93f946d7 100644
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -19,13 +19,13 @@
-
+
-
+
diff --git a/b2g/config/flame-kk/sources.xml b/b2g/config/flame-kk/sources.xml
index 38148d02ac29..18ca3667cf40 100644
--- a/b2g/config/flame-kk/sources.xml
+++ b/b2g/config/flame-kk/sources.xml
@@ -15,7 +15,7 @@
-
+
@@ -23,7 +23,7 @@
-
+
@@ -110,7 +110,7 @@
-
+
diff --git a/b2g/config/flame/sources.xml b/b2g/config/flame/sources.xml
index 238300585aa7..e4f56ed9a092 100644
--- a/b2g/config/flame/sources.xml
+++ b/b2g/config/flame/sources.xml
@@ -17,10 +17,10 @@
-
+
-
+
diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json
index 34ba0077e8b6..be2d6e4725db 100644
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
{
"git": {
- "git_revision": "6afe4606da768aed62d8a200fd24e6a7fa52dc4b",
+ "git_revision": "94af4b42d2ace6c9f38f31de77240604fac68af1",
"remote": "https://git.mozilla.org/releases/gaia.git",
"branch": ""
},
- "revision": "f2adcd661905e0f45866472840a0bba016cd1b58",
+ "revision": "75ad0f9d0fd8fa16129eb2c5330f330ca0d9ee08",
"repo_path": "integration/gaia-central"
}
diff --git a/b2g/config/nexus-4/sources.xml b/b2g/config/nexus-4/sources.xml
index 0620024eaddc..0516ebb8b5a5 100644
--- a/b2g/config/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/sources.xml
@@ -17,10 +17,10 @@
-
+
-
+
@@ -117,7 +117,7 @@
-
+
diff --git a/b2g/config/nexus-5-l/sources.xml b/b2g/config/nexus-5-l/sources.xml
index 8359edaedacd..a1832a1f5be2 100644
--- a/b2g/config/nexus-5-l/sources.xml
+++ b/b2g/config/nexus-5-l/sources.xml
@@ -15,7 +15,7 @@
-
+
@@ -23,7 +23,7 @@
-
+
@@ -126,7 +126,7 @@
-
+
@@ -136,7 +136,7 @@
-
+
diff --git a/dom/bluetooth/bluedroid/BluetoothDaemonHelpers.cpp b/dom/bluetooth/bluedroid/BluetoothDaemonHelpers.cpp
index 3c637ad96687..9a9c6ebacec2 100644
--- a/dom/bluetooth/bluedroid/BluetoothDaemonHelpers.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothDaemonHelpers.cpp
@@ -69,6 +69,18 @@ Convert(int aIn, int16_t& aOut)
return NS_OK;
}
+nsresult
+Convert(int aIn, int32_t& aOut)
+{
+ if (NS_WARN_IF(aIn < std::numeric_limits::min()) ||
+ NS_WARN_IF(aIn > std::numeric_limits::max())) {
+ aOut = 0; // silences compiler warning
+ return NS_ERROR_ILLEGAL_VALUE;
+ }
+ aOut = static_cast(aIn);
+ return NS_OK;
+}
+
nsresult
Convert(int32_t aIn, BluetoothDeviceType& aOut)
{
diff --git a/dom/bluetooth/bluedroid/BluetoothDaemonHelpers.h b/dom/bluetooth/bluedroid/BluetoothDaemonHelpers.h
index af9c3748939e..582ddbec772e 100644
--- a/dom/bluetooth/bluedroid/BluetoothDaemonHelpers.h
+++ b/dom/bluetooth/bluedroid/BluetoothDaemonHelpers.h
@@ -148,6 +148,9 @@ Convert(int aIn, uint8_t& aOut);
nsresult
Convert(int aIn, int16_t& aOut);
+nsresult
+Convert(int aIn, int32_t& aOut);
+
nsresult
Convert(int32_t aIn, BluetoothDeviceType& aOut);
diff --git a/dom/bluetooth/bluedroid/BluetoothDaemonSocketInterface.cpp b/dom/bluetooth/bluedroid/BluetoothDaemonSocketInterface.cpp
index 7022d19a3f15..b293e9dd5d75 100644
--- a/dom/bluetooth/bluedroid/BluetoothDaemonSocketInterface.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothDaemonSocketInterface.cpp
@@ -36,7 +36,7 @@ BluetoothDaemonSocketModule::ListenCmd(BluetoothSocketType aType,
aType,
PackConversion(aServiceName),
PackArray(aServiceUuid, 16),
- PackConversion(aChannel),
+ PackConversion(aChannel),
SocketFlags(aEncrypt, aAuth), *pdu);
if (NS_FAILED(rv)) {
return rv;
@@ -65,7 +65,7 @@ BluetoothDaemonSocketModule::ConnectCmd(const nsAString& aBdAddr,
PackConversion(aBdAddr),
aType,
PackArray(aUuid, 16),
- PackConversion(aChannel),
+ PackConversion(aChannel),
SocketFlags(aEncrypt, aAuth), *pdu);
if (NS_FAILED(rv)) {
return rv;
diff --git a/dom/system/gonk/moz.build b/dom/system/gonk/moz.build
index 7f19ecea3bbf..f2699f392012 100644
--- a/dom/system/gonk/moz.build
+++ b/dom/system/gonk/moz.build
@@ -97,6 +97,7 @@ if CONFIG['MOZ_B2G_RIL']:
EXTRA_JS_MODULES += [
'ril_consts.js',
'ril_worker.js',
+ 'ril_worker_buf_object.js',
'RILSystemMessenger.jsm',
]
diff --git a/dom/system/gonk/ril_worker.js b/dom/system/gonk/ril_worker.js
index 0fe1831a629b..51fa7bbcd56c 100644
--- a/dom/system/gonk/ril_worker.js
+++ b/dom/system/gonk/ril_worker.js
@@ -36,10 +36,13 @@
* JavaScript, and that's intended.
*/
+/* global BufObject */
+
"use strict";
importScripts("ril_consts.js");
importScripts("resource://gre/modules/workers/require.js");
+importScripts("ril_worker_buf_object.js");
// set to true in ril_consts.js to see debug messages
let DEBUG = DEBUG_WORKER;
@@ -16023,8 +16026,6 @@ function Context(aClientId) {
this.clientId = aClientId;
this.Buf = new BufObject(this);
- this.Buf.init();
-
this.RIL = new RilObject(this);
this.RIL.initRILState();
}
diff --git a/dom/system/gonk/ril_worker_buf_object.js b/dom/system/gonk/ril_worker_buf_object.js
new file mode 100644
index 000000000000..f0853e073419
--- /dev/null
+++ b/dom/system/gonk/ril_worker_buf_object.js
@@ -0,0 +1,147 @@
+/* global require */
+/* global DEBUG, DEBUG_WORKER */
+/* global RESPONSE_TYPE_SOLICITED */
+/* global RESPONSE_TYPE_UNSOLICITED */
+
+"use strict";
+
+/**
+ * This is a specialized worker buffer for the Parcel protocol.
+ *
+ * NOTE: To prevent including/importing twice, this file should be included
+ * in a file which already includes 'ril_consts.js' and 'require.js'.
+ */
+(function(exports) {
+
+ // Set to true in ril_consts.js to see debug messages
+ let DEBUG = DEBUG_WORKER;
+ // Need to inherit it.
+ let Buf = require("resource://gre/modules/workers/worker_buf.js").Buf;
+
+ let BufObject = function(aContext) {
+ this.context = aContext;
+ // This gets incremented each time we send out a parcel.
+ this.mToken = 1;
+ // Maps tokens we send out with requests to the request type, so that
+ // when we get a response parcel back, we know what request it was for.
+ this.mTokenRequestMap = new Map();
+ // This is because the underlying 'Buf' is still using the 'init' pattern, so
+ // this derived one needs to invoke it.
+ // Using 'apply' style to mark it's a parent method calling explicitly.
+ Buf._init.apply(this);
+ };
+
+ /**
+ * "inherit" the basic worker buffer.
+ */
+ BufObject.prototype = Object.create(Buf);
+
+ /**
+ * Process one parcel.
+ */
+ BufObject.prototype.processParcel = function() {
+ let responseType = this.readInt32();
+
+ let requestType, options;
+ if (responseType == RESPONSE_TYPE_SOLICITED) {
+ let token = this.readInt32();
+ let error = this.readInt32();
+
+ options = this.mTokenRequestMap.get(token);
+ if (!options) {
+ if (DEBUG) {
+ this.context.debug("Suspicious uninvited request found: " +
+ token + ". Ignored!");
+ }
+ return;
+ }
+
+ this.mTokenRequestMap.delete(token);
+ requestType = options.rilRequestType;
+
+ options.rilRequestError = error;
+ if (DEBUG) {
+ this.context.debug("Solicited response for request type " + requestType +
+ ", token " + token + ", error " + error);
+ }
+ } else if (responseType == RESPONSE_TYPE_UNSOLICITED) {
+ requestType = this.readInt32();
+ if (DEBUG) {
+ this.context.debug("Unsolicited response for request type " + requestType);
+ }
+ } else {
+ if (DEBUG) {
+ this.context.debug("Unknown response type: " + responseType);
+ }
+ return;
+ }
+
+ this.context.RIL.handleParcel(requestType, this.readAvailable, options);
+ };
+
+ /**
+ * Start a new outgoing parcel.
+ *
+ * @param type
+ * Integer specifying the request type.
+ * @param options [optional]
+ * Object containing information about the request, e.g. the
+ * original main thread message object that led to the RIL request.
+ */
+ BufObject.prototype.newParcel = function(type, options) {
+ if (DEBUG) {
+ this.context.debug("New outgoing parcel of type " + type);
+ }
+
+ // We're going to leave room for the parcel size at the beginning.
+ this.outgoingIndex = this.PARCEL_SIZE_SIZE;
+ this.writeInt32(this._reMapRequestType(type));
+ this.writeInt32(this.mToken);
+
+ if (!options) {
+ options = {};
+ }
+ options.rilRequestType = type;
+ options.rilRequestError = null;
+ this.mTokenRequestMap.set(this.mToken, options);
+ this.mToken++;
+ return this.mToken;
+ };
+
+ BufObject.prototype.simpleRequest = function(type, options) {
+ this.newParcel(type, options);
+ this.sendParcel();
+ };
+
+ BufObject.prototype.onSendParcel = function(parcel) {
+ self.postRILMessage(this.context.clientId, parcel);
+ };
+
+ /**
+ * Remapping the request type to different values based on RIL version.
+ * We only have to do this for SUBSCRIPTION right now, so I just make it
+ * simple. A generic logic or structure could be discussed if we have more
+ * use cases, especially the cases from different partners.
+ */
+ BufObject.prototype._reMapRequestType = function(type) {
+ let newType = type;
+ switch (type) {
+ case REQUEST_SET_UICC_SUBSCRIPTION:
+ case REQUEST_SET_DATA_SUBSCRIPTION:
+ if (this.context.RIL.version < 9) {
+ // Shift the CAF's proprietary parcels. Please see
+ // https://www.codeaurora.org/cgit/quic/la/platform/hardware/ril/tree/include/telephony/ril.h?h=b2g_jb_3.2
+ newType = type - 1;
+ }
+ break;
+ }
+
+ return newType;
+ };
+
+ // Before we make sure to form it as a module would not add extra
+ // overhead of module loading, we need to define it in this way
+ // rather than 'module.exports' it as a module component.
+ exports.BufObject = BufObject;
+})(self); // in worker self is the global
+
diff --git a/hal/gonk/GonkHal.cpp b/hal/gonk/GonkHal.cpp
index e3b30a8b15c8..bda465ef85eb 100644
--- a/hal/gonk/GonkHal.cpp
+++ b/hal/gonk/GonkHal.cpp
@@ -1351,7 +1351,8 @@ private:
ProcessPriority mPriority;
int32_t mOomScoreAdj;
int32_t mKillUnderKB;
- int mCGroupProcsFd;
+ int mCpuCGroupProcsFd;
+ int mMemCGroupProcsFd;
nsCString mGroup;
/**
@@ -1368,7 +1369,7 @@ private:
/**
* Get the full path of the cgroup.procs file associated with the group.
*/
- nsCString CGroupProcsFilename()
+ nsCString CpuCGroupProcsFilename()
{
nsCString cgroupName = mGroup;
@@ -1384,9 +1385,30 @@ private:
NS_LITERAL_CSTRING("cgroup.procs");
}
- int OpenCGroupProcs()
+ nsCString MemCGroupProcsFilename()
{
- return open(CGroupProcsFilename().get(), O_WRONLY);
+ nsCString cgroupName = mGroup;
+
+ /* If mGroup is empty, our cgroup.procs file is the root procs file,
+ * located at /sys/fs/cgroup/memory/cgroup.procs. Otherwise our procs
+ * file is /sys/fs/cgroup/memory/NAME/cgroup.procs. */
+
+ if (!mGroup.IsEmpty()) {
+ cgroupName.AppendLiteral("/");
+ }
+
+ return NS_LITERAL_CSTRING("/sys/fs/cgroup/memory/") + cgroupName +
+ NS_LITERAL_CSTRING("cgroup.procs");
+ }
+
+ int OpenCpuCGroupProcs()
+ {
+ return open(CpuCGroupProcsFilename().get(), O_WRONLY);
+ }
+
+ int OpenMemCGroupProcs()
+ {
+ return open(MemCGroupProcsFilename().get(), O_WRONLY);
}
};
@@ -1401,11 +1423,14 @@ private:
* exists. Otherwise, return false.
*/
static bool
-EnsureCGroupExists(const nsACString &aGroup)
+EnsureCpuCGroupExists(const nsACString &aGroup)
{
NS_NAMED_LITERAL_CSTRING(kDevCpuCtl, "/dev/cpuctl/");
NS_NAMED_LITERAL_CSTRING(kSlash, "/");
+ nsAutoCString groupName(aGroup);
+ HAL_LOG("EnsureCpuCGroupExists for group '%s'", groupName.get());
+
nsAutoCString prefPrefix("hal.processPriorityManager.gonk.cgroups.");
/* If cgroup is not empty, append the cgroup name and a dot to obtain the
@@ -1436,6 +1461,7 @@ EnsureCGroupExists(const nsACString &aGroup)
offset++;
}
+ HAL_LOG("EnsureCpuCGroupExists created group '%s'", groupName.get());
nsAutoCString pathPrefix(kDevCpuCtl + aGroup + kSlash);
nsAutoCString cpuSharesPath(pathPrefix + NS_LITERAL_CSTRING("cpu.shares"));
@@ -1457,11 +1483,61 @@ EnsureCGroupExists(const nsACString &aGroup)
return true;
}
+static bool
+EnsureMemCGroupExists(const nsACString &aGroup)
+{
+ NS_NAMED_LITERAL_CSTRING(kMemCtl, "/sys/fs/cgroup/memory/");
+ NS_NAMED_LITERAL_CSTRING(kSlash, "/");
+
+ nsAutoCString groupName(aGroup);
+ HAL_LOG("EnsureMemCGroupExists for group '%s'", groupName.get());
+
+ nsAutoCString prefPrefix("hal.processPriorityManager.gonk.cgroups.");
+
+ /* If cgroup is not empty, append the cgroup name and a dot to obtain the
+ * group specific preferences. */
+ if (!aGroup.IsEmpty()) {
+ prefPrefix += aGroup + NS_LITERAL_CSTRING(".");
+ }
+
+ nsAutoCString memSwappinessPref(prefPrefix + NS_LITERAL_CSTRING("memory_swappiness"));
+ int memSwappiness = Preferences::GetInt(memSwappinessPref.get());
+
+ // Create mCGroup and its parent directories, as necessary.
+ nsCString cgroupIter = aGroup + kSlash;
+
+ int32_t offset = 0;
+ while ((offset = cgroupIter.FindChar('/', offset)) != -1) {
+ nsAutoCString path = kMemCtl + Substring(cgroupIter, 0, offset);
+ int rv = mkdir(path.get(), 0744);
+
+ if (rv == -1 && errno != EEXIST) {
+ HAL_LOG("Could not create the %s control group.", path.get());
+ return false;
+ }
+
+ offset++;
+ }
+ HAL_LOG("EnsureMemCGroupExists created group '%s'", groupName.get());
+
+ nsAutoCString pathPrefix(kMemCtl + aGroup + kSlash);
+ nsAutoCString memSwappinessPath(pathPrefix + NS_LITERAL_CSTRING("memory.swappiness"));
+ if (!WriteToFile(memSwappinessPath.get(),
+ nsPrintfCString("%d", memSwappiness).get())) {
+ HAL_LOG("Could not set the memory.swappiness for group %s", memSwappinessPath.get());
+ return false;
+ }
+ HAL_LOG("Set memory.swappiness for group %s to %d", memSwappinessPath.get(), memSwappiness);
+
+ return true;
+}
+
PriorityClass::PriorityClass(ProcessPriority aPriority)
: mPriority(aPriority)
, mOomScoreAdj(0)
, mKillUnderKB(0)
- , mCGroupProcsFd(-1)
+ , mCpuCGroupProcsFd(-1)
+ , mMemCGroupProcsFd(-1)
{
DebugOnly rv;
@@ -1475,14 +1551,18 @@ PriorityClass::PriorityClass(ProcessPriority aPriority)
rv = Preferences::GetCString(PriorityPrefName("cgroup").get(), &mGroup);
MOZ_ASSERT(NS_SUCCEEDED(rv), "Missing control group preference");
- if (EnsureCGroupExists(mGroup)) {
- mCGroupProcsFd = OpenCGroupProcs();
+ if (EnsureCpuCGroupExists(mGroup)) {
+ mCpuCGroupProcsFd = OpenCpuCGroupProcs();
+ }
+ if (EnsureMemCGroupExists(mGroup)) {
+ mMemCGroupProcsFd = OpenMemCGroupProcs();
}
}
PriorityClass::~PriorityClass()
{
- close(mCGroupProcsFd);
+ close(mCpuCGroupProcsFd);
+ close(mMemCGroupProcsFd);
}
PriorityClass::PriorityClass(const PriorityClass& aOther)
@@ -1491,7 +1571,8 @@ PriorityClass::PriorityClass(const PriorityClass& aOther)
, mKillUnderKB(aOther.mKillUnderKB)
, mGroup(aOther.mGroup)
{
- mCGroupProcsFd = OpenCGroupProcs();
+ mCpuCGroupProcsFd = OpenCpuCGroupProcs();
+ mMemCGroupProcsFd = OpenMemCGroupProcs();
}
PriorityClass& PriorityClass::operator=(const PriorityClass& aOther)
@@ -1500,20 +1581,26 @@ PriorityClass& PriorityClass::operator=(const PriorityClass& aOther)
mOomScoreAdj = aOther.mOomScoreAdj;
mKillUnderKB = aOther.mKillUnderKB;
mGroup = aOther.mGroup;
- mCGroupProcsFd = OpenCGroupProcs();
+ mCpuCGroupProcsFd = OpenCpuCGroupProcs();
+ mMemCGroupProcsFd = OpenMemCGroupProcs();
return *this;
}
void PriorityClass::AddProcess(int aPid)
{
- if (mCGroupProcsFd < 0) {
- return;
+ if (mCpuCGroupProcsFd >= 0) {
+ nsPrintfCString str("%d", aPid);
+
+ if (write(mCpuCGroupProcsFd, str.get(), strlen(str.get())) < 0) {
+ HAL_ERR("Couldn't add PID %d to the %s cpu control group", aPid, mGroup.get());
+ }
}
+ if (mMemCGroupProcsFd >= 0) {
+ nsPrintfCString str("%d", aPid);
- nsPrintfCString str("%d", aPid);
-
- if (write(mCGroupProcsFd, str.get(), strlen(str.get())) < 0) {
- HAL_ERR("Couldn't add PID %d to the %s control group", aPid, mGroup.get());
+ if (write(mMemCGroupProcsFd, str.get(), strlen(str.get())) < 0) {
+ HAL_ERR("Couldn't add PID %d to the %s memory control group", aPid, mGroup.get());
+ }
}
}
diff --git a/layout/ipc/RenderFrameParent.cpp b/layout/ipc/RenderFrameParent.cpp
index 1ae1b59be5a4..75d8b0c5c6a2 100644
--- a/layout/ipc/RenderFrameParent.cpp
+++ b/layout/ipc/RenderFrameParent.cpp
@@ -19,6 +19,7 @@
#include "mozilla/layers/CompositorParent.h"
#include "mozilla/layers/LayerTransactionParent.h"
#include "nsContentUtils.h"
+#include "nsFocusManager.h"
#include "nsFrameLoader.h"
#include "nsIObserver.h"
#include "nsSubDocumentFrame.h"
@@ -148,6 +149,7 @@ public:
return;
}
if (mRenderFrame) {
+ mRenderFrame->TakeFocusForClick();
TabParent* browser = TabParent::GetFrom(mRenderFrame->Manager());
browser->HandleSingleTap(aPoint, aModifiers, aGuid);
}
@@ -595,6 +597,25 @@ RenderFrameParent::GetTextureFactoryIdentifier(TextureFactoryIdentifier* aTextur
}
}
+void
+RenderFrameParent::TakeFocusForClick()
+{
+ nsIFocusManager* fm = nsFocusManager::GetFocusManager();
+ if (!fm) {
+ return;
+ }
+ nsCOMPtr owner = mFrameLoader->GetOwnerContent();
+ if (!owner) {
+ return;
+ }
+ nsCOMPtr element = do_QueryInterface(owner);
+ if (!element) {
+ return;
+ }
+ fm->SetFocus(element, nsIFocusManager::FLAG_BYMOUSE |
+ nsIFocusManager::FLAG_NOSCROLL);
+}
+
} // namespace layout
} // namespace mozilla
diff --git a/layout/ipc/RenderFrameParent.h b/layout/ipc/RenderFrameParent.h
index fee2b50bef75..e2fb97c9c946 100644
--- a/layout/ipc/RenderFrameParent.h
+++ b/layout/ipc/RenderFrameParent.h
@@ -116,6 +116,9 @@ public:
void GetTextureFactoryIdentifier(TextureFactoryIdentifier* aTextureFactoryIdentifier);
inline uint64_t GetLayersId() { return mLayersId; }
+
+ void TakeFocusForClick();
+
protected:
void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;