Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/xpcom/base/nsMemoryImpl.cpp
Line
Count
Source (jump to first uncovered line)
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 "nsMemoryImpl.h"
8
#include "nsThreadUtils.h"
9
10
#include "nsIObserver.h"
11
#include "nsIObserverService.h"
12
#include "nsISimpleEnumerator.h"
13
14
#include "nsCOMPtr.h"
15
#include "mozilla/Services.h"
16
17
#ifdef ANDROID
18
#include <stdio.h>
19
20
// Minimum memory threshold for a device to be considered
21
// a low memory platform. This value has be in sync with
22
// Java's equivalent threshold, defined in
23
// mobile/android/base/util/HardwareUtils.java
24
#define LOW_MEMORY_THRESHOLD_KB (384 * 1024)
25
#endif
26
27
static nsMemoryImpl sGlobalMemory;
28
29
NS_IMPL_QUERY_INTERFACE(nsMemoryImpl, nsIMemory)
30
31
NS_IMETHODIMP
32
nsMemoryImpl::HeapMinimize(bool aImmediate)
33
0
{
34
0
  return FlushMemory(u"heap-minimize", aImmediate);
35
0
}
36
37
NS_IMETHODIMP
38
nsMemoryImpl::IsLowMemoryPlatform(bool* aResult)
39
0
{
40
#ifdef ANDROID
41
  static int sLowMemory = -1; // initialize to unknown, lazily evaluate to 0 or 1
42
  if (sLowMemory == -1) {
43
    sLowMemory = 0; // assume "not low memory" in case file operations fail
44
    *aResult = false;
45
46
    // check if MemTotal from /proc/meminfo is less than LOW_MEMORY_THRESHOLD_KB
47
    FILE* fd = fopen("/proc/meminfo", "r");
48
    if (!fd) {
49
      return NS_OK;
50
    }
51
    uint64_t mem = 0;
52
    int rv = fscanf(fd, "MemTotal: %" PRIu64 " kB", &mem);
53
    if (fclose(fd)) {
54
      return NS_OK;
55
    }
56
    if (rv != 1) {
57
      return NS_OK;
58
    }
59
    sLowMemory = (mem < LOW_MEMORY_THRESHOLD_KB) ? 1 : 0;
60
  }
61
  *aResult = (sLowMemory == 1);
62
#else
63
  *aResult = false;
64
0
#endif
65
0
  return NS_OK;
66
0
}
67
68
/*static*/ nsresult
69
nsMemoryImpl::Create(nsISupports* aOuter, const nsIID& aIID, void** aResult)
70
0
{
71
0
  if (NS_WARN_IF(aOuter)) {
72
0
    return NS_ERROR_NO_AGGREGATION;
73
0
  }
74
0
  return sGlobalMemory.QueryInterface(aIID, aResult);
75
0
}
76
77
nsresult
78
nsMemoryImpl::FlushMemory(const char16_t* aReason, bool aImmediate)
79
0
{
80
0
  nsresult rv = NS_OK;
81
0
82
0
  if (aImmediate) {
83
0
    // They've asked us to run the flusher *immediately*. We've
84
0
    // got to be on the UI main thread for us to be able to do
85
0
    // that...are we?
86
0
    if (!NS_IsMainThread()) {
87
0
      NS_ERROR("can't synchronously flush memory: not on UI thread");
88
0
      return NS_ERROR_FAILURE;
89
0
    }
90
0
  }
91
0
92
0
  bool lastVal = sIsFlushing.exchange(true);
93
0
  if (lastVal) {
94
0
    return NS_OK;
95
0
  }
96
0
97
0
  PRIntervalTime now = PR_IntervalNow();
98
0
99
0
  // Run the flushers immediately if we can; otherwise, proxy to the
100
0
  // UI thread an run 'em asynchronously.
101
0
  if (aImmediate) {
102
0
    rv = RunFlushers(aReason);
103
0
  } else {
104
0
    // Don't broadcast more than once every 1000ms to avoid being noisy
105
0
    if (PR_IntervalToMicroseconds(now - sLastFlushTime) > 1000) {
106
0
      sFlushEvent.mReason = aReason;
107
0
      rv = NS_DispatchToMainThread(&sFlushEvent);
108
0
    }
109
0
  }
110
0
111
0
  sLastFlushTime = now;
112
0
  return rv;
113
0
}
114
115
nsresult
116
nsMemoryImpl::RunFlushers(const char16_t* aReason)
117
0
{
118
0
  nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
119
0
  if (os) {
120
0
121
0
    // Instead of:
122
0
    //  os->NotifyObservers(this, "memory-pressure", aReason);
123
0
    // we are going to do this manually to see who/what is
124
0
    // deallocating.
125
0
126
0
    nsCOMPtr<nsISimpleEnumerator> e;
127
0
    os->EnumerateObservers("memory-pressure", getter_AddRefs(e));
128
0
129
0
    if (e) {
130
0
      nsCOMPtr<nsIObserver> observer;
131
0
      bool loop = true;
132
0
133
0
      while (NS_SUCCEEDED(e->HasMoreElements(&loop)) && loop) {
134
0
        nsCOMPtr<nsISupports> supports;
135
0
        e->GetNext(getter_AddRefs(supports));
136
0
137
0
        if (!supports) {
138
0
          continue;
139
0
        }
140
0
141
0
        observer = do_QueryInterface(supports);
142
0
        observer->Observe(observer, "memory-pressure", aReason);
143
0
      }
144
0
    }
145
0
  }
146
0
147
0
  sIsFlushing = false;
148
0
  return NS_OK;
149
0
}
150
151
// XXX need NS_IMPL_STATIC_ADDREF/RELEASE
152
NS_IMETHODIMP_(MozExternalRefCountType)
153
nsMemoryImpl::FlushEvent::AddRef()
154
0
{
155
0
  return 2;
156
0
}
157
NS_IMETHODIMP_(MozExternalRefCountType)
158
nsMemoryImpl::FlushEvent::Release()
159
0
{
160
0
  return 1;
161
0
}
162
NS_IMPL_QUERY_INTERFACE(nsMemoryImpl::FlushEvent, nsIRunnable)
163
164
NS_IMETHODIMP
165
nsMemoryImpl::FlushEvent::Run()
166
0
{
167
0
  sGlobalMemory.RunFlushers(mReason);
168
0
  return NS_OK;
169
0
}
170
171
mozilla::Atomic<bool>
172
nsMemoryImpl::sIsFlushing;
173
174
PRIntervalTime
175
nsMemoryImpl::sLastFlushTime = 0;
176
177
nsMemoryImpl::FlushEvent
178
nsMemoryImpl::sFlushEvent;
179
180
nsresult
181
NS_GetMemoryManager(nsIMemory** aResult)
182
0
{
183
0
  return sGlobalMemory.QueryInterface(NS_GET_IID(nsIMemory), (void**)aResult);
184
0
}