PreallocatedProcessManager.cpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  4. * You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #include "mozilla/PreallocatedProcessManager.h"
  6. #include "mozilla/ClearOnShutdown.h"
  7. #include "mozilla/Preferences.h"
  8. #include "mozilla/Unused.h"
  9. #include "mozilla/dom/ContentParent.h"
  10. #include "mozilla/dom/ScriptSettings.h"
  11. #include "nsIPropertyBag2.h"
  12. #include "ProcessPriorityManager.h"
  13. #include "nsServiceManagerUtils.h"
  14. // This number is fairly arbitrary ... the intention is to put off
  15. // launching another app process until the last one has finished
  16. // loading its content, to reduce CPU/memory/IO contention.
  17. #define DEFAULT_ALLOCATE_DELAY 1000
  18. using namespace mozilla;
  19. using namespace mozilla::hal;
  20. using namespace mozilla::dom;
  21. namespace {
  22. /**
  23. * This singleton class implements the static methods on
  24. * PreallocatedProcessManager.
  25. */
  26. class PreallocatedProcessManagerImpl final
  27. : public nsIObserver
  28. {
  29. public:
  30. static PreallocatedProcessManagerImpl* Singleton();
  31. NS_DECL_ISUPPORTS
  32. NS_DECL_NSIOBSERVER
  33. // See comments on PreallocatedProcessManager for these methods.
  34. void AllocateAfterDelay();
  35. void AllocateOnIdle();
  36. void AllocateNow();
  37. already_AddRefed<ContentParent> Take();
  38. private:
  39. static mozilla::StaticRefPtr<PreallocatedProcessManagerImpl> sSingleton;
  40. PreallocatedProcessManagerImpl();
  41. ~PreallocatedProcessManagerImpl() {}
  42. DISALLOW_EVIL_CONSTRUCTORS(PreallocatedProcessManagerImpl);
  43. void Init();
  44. void RereadPrefs();
  45. void Enable();
  46. void Disable();
  47. void ObserveProcessShutdown(nsISupports* aSubject);
  48. bool mEnabled;
  49. bool mShutdown;
  50. RefPtr<ContentParent> mPreallocatedAppProcess;
  51. };
  52. /* static */ StaticRefPtr<PreallocatedProcessManagerImpl>
  53. PreallocatedProcessManagerImpl::sSingleton;
  54. /* static */ PreallocatedProcessManagerImpl*
  55. PreallocatedProcessManagerImpl::Singleton()
  56. {
  57. if (!sSingleton) {
  58. sSingleton = new PreallocatedProcessManagerImpl();
  59. sSingleton->Init();
  60. ClearOnShutdown(&sSingleton);
  61. }
  62. return sSingleton;
  63. }
  64. NS_IMPL_ISUPPORTS(PreallocatedProcessManagerImpl, nsIObserver)
  65. PreallocatedProcessManagerImpl::PreallocatedProcessManagerImpl()
  66. :
  67. mEnabled(false)
  68. , mShutdown(false)
  69. {}
  70. void
  71. PreallocatedProcessManagerImpl::Init()
  72. {
  73. Preferences::AddStrongObserver(this, "dom.ipc.processPrelaunch.enabled");
  74. nsCOMPtr<nsIObserverService> os = services::GetObserverService();
  75. if (os) {
  76. os->AddObserver(this, "ipc:content-shutdown",
  77. /* weakRef = */ false);
  78. os->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID,
  79. /* weakRef = */ false);
  80. }
  81. {
  82. RereadPrefs();
  83. }
  84. }
  85. NS_IMETHODIMP
  86. PreallocatedProcessManagerImpl::Observe(nsISupports* aSubject,
  87. const char* aTopic,
  88. const char16_t* aData)
  89. {
  90. if (!strcmp("ipc:content-shutdown", aTopic)) {
  91. ObserveProcessShutdown(aSubject);
  92. } else if (!strcmp("nsPref:changed", aTopic)) {
  93. // The only other observer we registered was for our prefs.
  94. RereadPrefs();
  95. } else if (!strcmp(NS_XPCOM_SHUTDOWN_OBSERVER_ID, aTopic)) {
  96. mShutdown = true;
  97. } else {
  98. MOZ_ASSERT(false);
  99. }
  100. return NS_OK;
  101. }
  102. void
  103. PreallocatedProcessManagerImpl::RereadPrefs()
  104. {
  105. if (Preferences::GetBool("dom.ipc.processPrelaunch.enabled")) {
  106. Enable();
  107. } else {
  108. Disable();
  109. }
  110. }
  111. already_AddRefed<ContentParent>
  112. PreallocatedProcessManagerImpl::Take()
  113. {
  114. return mPreallocatedAppProcess.forget();
  115. }
  116. void
  117. PreallocatedProcessManagerImpl::Enable()
  118. {
  119. if (mEnabled) {
  120. return;
  121. }
  122. mEnabled = true;
  123. AllocateAfterDelay();
  124. }
  125. void
  126. PreallocatedProcessManagerImpl::AllocateAfterDelay()
  127. {
  128. if (!mEnabled || mPreallocatedAppProcess) {
  129. return;
  130. }
  131. MessageLoop::current()->PostDelayedTask(
  132. NewRunnableMethod(this, &PreallocatedProcessManagerImpl::AllocateOnIdle),
  133. Preferences::GetUint("dom.ipc.processPrelaunch.delayMs",
  134. DEFAULT_ALLOCATE_DELAY));
  135. }
  136. void
  137. PreallocatedProcessManagerImpl::AllocateOnIdle()
  138. {
  139. if (!mEnabled || mPreallocatedAppProcess) {
  140. return;
  141. }
  142. MessageLoop::current()->PostIdleTask(NewRunnableMethod(this, &PreallocatedProcessManagerImpl::AllocateNow));
  143. }
  144. void
  145. PreallocatedProcessManagerImpl::AllocateNow()
  146. {
  147. if (!mEnabled || mPreallocatedAppProcess) {
  148. return;
  149. }
  150. mPreallocatedAppProcess = ContentParent::PreallocateAppProcess();
  151. }
  152. void
  153. PreallocatedProcessManagerImpl::Disable()
  154. {
  155. if (!mEnabled) {
  156. return;
  157. }
  158. mEnabled = false;
  159. if (mPreallocatedAppProcess) {
  160. mPreallocatedAppProcess->Close();
  161. mPreallocatedAppProcess = nullptr;
  162. }
  163. }
  164. void
  165. PreallocatedProcessManagerImpl::ObserveProcessShutdown(nsISupports* aSubject)
  166. {
  167. if (!mPreallocatedAppProcess) {
  168. return;
  169. }
  170. nsCOMPtr<nsIPropertyBag2> props = do_QueryInterface(aSubject);
  171. NS_ENSURE_TRUE_VOID(props);
  172. uint64_t childID = CONTENT_PROCESS_ID_UNKNOWN;
  173. props->GetPropertyAsUint64(NS_LITERAL_STRING("childID"), &childID);
  174. NS_ENSURE_TRUE_VOID(childID != CONTENT_PROCESS_ID_UNKNOWN);
  175. if (childID == mPreallocatedAppProcess->ChildID()) {
  176. mPreallocatedAppProcess = nullptr;
  177. }
  178. }
  179. inline PreallocatedProcessManagerImpl* GetPPMImpl()
  180. {
  181. return PreallocatedProcessManagerImpl::Singleton();
  182. }
  183. } // namespace
  184. namespace mozilla {
  185. /* static */ void
  186. PreallocatedProcessManager::AllocateAfterDelay()
  187. {
  188. GetPPMImpl()->AllocateAfterDelay();
  189. }
  190. /* static */ void
  191. PreallocatedProcessManager::AllocateOnIdle()
  192. {
  193. GetPPMImpl()->AllocateOnIdle();
  194. }
  195. /* static */ void
  196. PreallocatedProcessManager::AllocateNow()
  197. {
  198. GetPPMImpl()->AllocateNow();
  199. }
  200. /* static */ already_AddRefed<ContentParent>
  201. PreallocatedProcessManager::Take()
  202. {
  203. return GetPPMImpl()->Take();
  204. }
  205. } // namespace mozilla