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;