1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #include "AvailableMemoryWatcher.h"
8 
9 #include "mozilla/ClearOnShutdown.h"
10 #include "mozilla/dom/Promise.h"
11 #include "mozilla/ErrorResult.h"
12 #include "mozilla/RefPtr.h"
13 #include "mozilla/StaticPtr.h"
14 #include "nsMemoryPressure.h"
15 #include "nsXULAppAPI.h"
16 
17 namespace mozilla {
18 
19 // Use this class as the initial value of
20 // nsAvailableMemoryWatcherBase::mCallback until RegisterCallback() is called
21 // so that nsAvailableMemoryWatcherBase does not have to check if its callback
22 // object is valid or not.
23 class NullTabUnloader final : public nsITabUnloader {
24   ~NullTabUnloader() = default;
25 
26  public:
27   NullTabUnloader() = default;
28 
29   NS_DECL_ISUPPORTS
30   NS_DECL_NSITABUNLOADER
31 };
32 
NS_IMPL_ISUPPORTS(NullTabUnloader,nsITabUnloader)33 NS_IMPL_ISUPPORTS(NullTabUnloader, nsITabUnloader)
34 
35 NS_IMETHODIMP NullTabUnloader::UnloadTabAsync() {
36   return NS_ERROR_NOT_IMPLEMENTED;
37 }
38 
39 StaticRefPtr<nsAvailableMemoryWatcherBase>
40     nsAvailableMemoryWatcherBase::sSingleton;
41 
42 /*static*/
43 already_AddRefed<nsAvailableMemoryWatcherBase>
GetSingleton()44 nsAvailableMemoryWatcherBase::GetSingleton() {
45   if (!sSingleton) {
46     sSingleton = CreateAvailableMemoryWatcher();
47     ClearOnShutdown(&sSingleton);
48   }
49 
50   return do_AddRef(sSingleton);
51 }
52 
53 NS_IMPL_ISUPPORTS(nsAvailableMemoryWatcherBase, nsIAvailableMemoryWatcherBase);
54 
nsAvailableMemoryWatcherBase()55 nsAvailableMemoryWatcherBase::nsAvailableMemoryWatcherBase()
56     : mTabUnloader(new NullTabUnloader) {
57   MOZ_ASSERT(XRE_IsParentProcess(),
58              "Watching memory only in the main process.");
59 }
60 
RegisterTabUnloader(nsITabUnloader * aTabUnloader)61 nsresult nsAvailableMemoryWatcherBase::RegisterTabUnloader(
62     nsITabUnloader* aTabUnloader) {
63   mTabUnloader = aTabUnloader;
64   return NS_OK;
65 }
66 
OnUnloadAttemptCompleted(nsresult aResult)67 nsresult nsAvailableMemoryWatcherBase::OnUnloadAttemptCompleted(
68     nsresult aResult) {
69   if (aResult == NS_ERROR_NOT_AVAILABLE) {
70     // If there was no unloadable tab, declare the memory-pressure
71     NS_NotifyOfEventualMemoryPressure(MemoryPressureState::LowMemory);
72   }
73   return NS_OK;
74 }
75 
76 // Define the fallback method for a platform for which a platform-specific
77 // CreateAvailableMemoryWatcher() is not defined.
78 #if !defined(XP_WIN)
CreateAvailableMemoryWatcher()79 already_AddRefed<nsAvailableMemoryWatcherBase> CreateAvailableMemoryWatcher() {
80   RefPtr instance(new nsAvailableMemoryWatcherBase);
81   return do_AddRef(instance);
82 }
83 #endif
84 
85 }  // namespace mozilla
86