From c5c101d2019d3c510001e8d54d2237d35ba80f65 Mon Sep 17 00:00:00 2001 From: Will Hawkins Date: Tue, 4 Jun 2019 19:41:06 +0000 Subject: [PATCH] Bug 894567: Use MemoryInfo.totalMem to get the device's total memory rather than parse /proc/meminfo. r=nalexander Differential Revision: https://phabricator.services.mozilla.com/D33549 --HG-- extra : moz-landing-system : lando --- .../java/org/mozilla/gecko/ANRReporter.java | 16 +-- .../java/org/mozilla/gecko/GeckoAppShell.java | 10 +- .../main/java/org/mozilla/gecko/SysInfo.java | 104 ++++-------------- .../org/mozilla/gecko/util/HardwareUtils.java | 5 - 4 files changed, 32 insertions(+), 103 deletions(-) diff --git a/mobile/android/base/java/org/mozilla/gecko/ANRReporter.java b/mobile/android/base/java/org/mozilla/gecko/ANRReporter.java index e9469a8a3718..ac9de3595fc9 100644 --- a/mobile/android/base/java/org/mozilla/gecko/ANRReporter.java +++ b/mobile/android/base/java/org/mozilla/gecko/ANRReporter.java @@ -300,7 +300,7 @@ public final class ANRReporter extends BroadcastReceiver return data.length; } - private static void fillPingHeader(OutputStream ping, String slug) + private static void fillPingHeader(Context context, OutputStream ping, String slug) throws IOException { // ping file header @@ -332,7 +332,7 @@ public final class ANRReporter extends BroadcastReceiver "\"platformBuildID\":" + JSONObject.quote(AppConstants.MOZ_APP_BUILDID) + "," + "\"locale\":" + JSONObject.quote(Locales.getLanguageTag(Locale.getDefault())) + "," + "\"cpucount\":" + String.valueOf(SysInfo.getCPUCount()) + "," + - "\"memsize\":" + String.valueOf(SysInfo.getMemSize()) + "," + + "\"memsize\":" + String.valueOf(SysInfo.getMemSize(context)) + "," + "\"arch\":" + JSONObject.quote(SysInfo.getArchABI()) + "," + "\"kernel_version\":" + JSONObject.quote(SysInfo.getKernelVersion()) + "," + "\"device\":" + JSONObject.quote(SysInfo.getDevice()) + "," + @@ -479,19 +479,19 @@ public final class ANRReporter extends BroadcastReceiver } } - private static void processTraces(Reader traces, File pingFile) { + private static void processTraces(Context context, Reader traces, File pingFile) { // Only get native stack if Gecko is running. // Also, unwinding is memory intensive, so only unwind if we have enough memory. final boolean haveNativeStack = GeckoThread.isRunning() ? - requestNativeStack(/* unwind */ SysInfo.getMemSize() >= 640) : false; + requestNativeStack(/* unwind */ SysInfo.getMemSize(context) >= 640) : false; try { OutputStream ping = new BufferedOutputStream( new FileOutputStream(pingFile), TRACES_BLOCK_SIZE); try { - fillPingHeader(ping, pingFile.getName()); + fillPingHeader(context, ping, pingFile.getName()); // Traces file has the format // ----- pid xxx at xxx ----- // Cmd line: org.mozilla.xxx @@ -527,12 +527,12 @@ public final class ANRReporter extends BroadcastReceiver } } - private static void processTraces(File tracesFile, File pingFile) { + private static void processTraces(Context context, File tracesFile, File pingFile) { try { Reader traces = new InputStreamReader( new FileInputStream(tracesFile), TRACES_CHARSET); try { - processTraces(traces, pingFile); + processTraces(context, traces, pingFile); } finally { traces.close(); } @@ -596,6 +596,6 @@ public final class ANRReporter extends BroadcastReceiver return; } Log.i(LOGTAG, "processing Gecko ANR"); - processTraces(tracesFile, pingFile); + processTraces(context, tracesFile, pingFile); } } diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java index baabf1b288da..b32cbdba4b28 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java @@ -1036,8 +1036,8 @@ public class GeckoAppShell { return sDensity; } - private static boolean isHighMemoryDevice() { - return HardwareUtils.getMemSize() > HIGH_MEMORY_DEVICE_THRESHOLD_MB; + private static boolean isHighMemoryDevice(final Context context) { + return SysInfo.getMemSize(context) > HIGH_MEMORY_DEVICE_THRESHOLD_MB; } public static synchronized void useMaxScreenDepth(final boolean enable) { @@ -1052,11 +1052,11 @@ public class GeckoAppShell { public static synchronized int getScreenDepth() { if (sScreenDepth == 0) { sScreenDepth = 16; + final Context applicationContext = getApplicationContext(); PixelFormat info = new PixelFormat(); - final WindowManager wm = (WindowManager) - getApplicationContext().getSystemService(Context.WINDOW_SERVICE); + final WindowManager wm = (WindowManager) applicationContext.getSystemService(Context.WINDOW_SERVICE); PixelFormat.getPixelFormatInfo(wm.getDefaultDisplay().getPixelFormat(), info); - if (info.bitsPerPixel >= 24 && isHighMemoryDevice()) { + if (info.bitsPerPixel >= 24 && isHighMemoryDevice(applicationContext)) { sScreenDepth = sUseMaxScreenDepth ? info.bitsPerPixel : 24; } } diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/SysInfo.java b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/SysInfo.java index b660bc30983b..9fe71f9ac21d 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/SysInfo.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/SysInfo.java @@ -5,15 +5,15 @@ package org.mozilla.gecko; +import android.app.ActivityManager; +import android.app.ActivityManager.MemoryInfo; +import android.content.Context; import android.util.Log; import org.mozilla.gecko.util.StrictModeContext; import java.io.File; import java.io.FileFilter; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; import java.util.regex.Pattern; @@ -77,96 +77,30 @@ public final class SysInfo { } /** - * Helper functions used to extract key/value data from /proc/meminfo - * Pulled from: - * http://androidxref.com/4.2_r1/xref/frameworks/base/core/java/com/android/internal/util/MemInfoReader.java + * Fetch the total memory of the device in MB. + * + * NB: This cannot be called before GeckoAppShell has been + * initialized. + * + * @return Memory size in MB. */ - private static boolean matchMemText(final byte[] buffer, final int index, - final int bufferLength, final byte[] text) { - final int N = text.length; - if ((index + N) >= bufferLength) { - return false; - } - for (int i = 0; i < N; i++) { - if (buffer[index + i] != text[i]) { - return false; - } - } - return true; - } - - /** - * Parses a line like: - * - * MemTotal: 1605324 kB - * - * into 1605324. - * - * @return the first uninterrupted sequence of digits following the - * specified index, parsed as an integer value in KB. - */ - private static int extractMemValue(final byte[] buffer, final int offset, final int length) { - if (offset >= length) { - return 0; - } - - int i = offset; - while (i < length && buffer[i] != '\n') { - if (buffer[i] >= '0' && buffer[i] <= '9') { - int start = i++; - while (i < length && buffer[i] >= '0' && buffer[i] <= '9') { - ++i; - } - return Integer.parseInt(new String(buffer, start, i - start), 10); - } - ++i; - } - return 0; - } - - /** - * Fetch the total memory of the device in MB by parsing /proc/meminfo. - * - * Of course, Android doesn't have a neat and tidy way to find total - * RAM, so we do it by parsing /proc/meminfo. - * - * @return 0 if a problem occurred, or memory size in MB. - */ - @SuppressWarnings("try") - public static int getMemSize() { + public static int getMemSize(final Context context) { if (totalRAM >= 0) { return totalRAM; } - // This is the string "MemTotal" that we're searching for in the buffer. - final byte[] MEMTOTAL = {'M', 'e', 'm', 'T', 'o', 't', 'a', 'l'}; + final MemoryInfo memInfo = new MemoryInfo(); - // `/proc/meminfo` is not a real file and thus safe to read on the main thread. - try (StrictModeContext unused = StrictModeContext.allowDiskReads()) { - final byte[] buffer = new byte[MEMINFO_BUFFER_SIZE_BYTES]; - final FileInputStream is = new FileInputStream("/proc/meminfo"); - try { - final int length = is.read(buffer); + final ActivityManager am = (ActivityManager) context + .getSystemService(Context.ACTIVITY_SERVICE); + am.getMemoryInfo(memInfo); - for (int i = 0; i < length; i++) { - if (matchMemText(buffer, i, length, MEMTOTAL)) { - i += 8; - totalRAM = extractMemValue(buffer, i, length) / 1024; - Log.d(LOG_TAG, "System memory: " + totalRAM + "MB."); - return totalRAM; - } - } - } finally { - is.close(); - } + // `getMemoryInfo()` returns a value in B. Convert to MB. + totalRAM = (int)(memInfo.totalMem / (1024 * 1024)); - Log.w(LOG_TAG, "Did not find MemTotal line in /proc/meminfo."); - return totalRAM = 0; - } catch (FileNotFoundException f) { - return totalRAM = 0; - } catch (IOException e) { - return totalRAM = 0; - } + Log.d(LOG_TAG, "System memory: " + totalRAM + "MB."); + + return totalRAM; } /** diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/HardwareUtils.java b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/HardwareUtils.java index 34f66c5b7910..cecb17f18862 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/HardwareUtils.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/HardwareUtils.java @@ -12,7 +12,6 @@ import android.os.Build; import android.system.Os; import android.util.Log; -import org.mozilla.gecko.SysInfo; import org.mozilla.geckoview.BuildConfig; import java.io.File; @@ -79,10 +78,6 @@ public final class HardwareUtils { return sIsTelevision; } - public static int getMemSize() { - return SysInfo.getMemSize(); - } - private static String getPreferredAbi() { String abi = null; if (Build.VERSION.SDK_INT >= 21) {