1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 package org.chromium.base;
7 import android.os.Build;
8 import android.os.StrictMode;
9 import android.util.Log;
11 import java.io.BufferedReader;
12 import java.io.FileReader;
13 import java.util.regex.Matcher;
14 import java.util.regex.Pattern;
17 * Exposes system related information about the current device.
19 public class SysUtils {
20 // Any device that runs this or an older version of the system cannot be considered 'low-end'
21 private static final int ANDROID_LOW_MEMORY_ANDROID_SDK_THRESHOLD =
22 Build.VERSION_CODES.JELLY_BEAN_MR2;
24 // A device reporting strictly more total memory in megabytes cannot be considered 'low-end'.
25 private static final long ANDROID_LOW_MEMORY_DEVICE_THRESHOLD_MB = 512;
27 private static final String TAG = "SysUtils";
29 private static Boolean sLowEndDevice;
31 private SysUtils() { }
34 * Return the amount of physical memory on this device in kilobytes.
35 * Note: the only reason this is public is for testability reason.
36 * @return Amount of physical memory in kilobytes, or 0 if there was
37 * an error trying to access the information.
39 * Note that this is CalledByNative for testing purpose only.
42 public static int amountOfPhysicalMemoryKB() {
43 // Extract total memory RAM size by parsing /proc/meminfo, note that
44 // this is exactly what the implementation of sysconf(_SC_PHYS_PAGES)
45 // does. However, it can't be called because this method must be
46 // usable before any native code is loaded.
48 // An alternative is to use ActivityManager.getMemoryInfo(), but this
49 // requires a valid ActivityManager handle, which can only come from
50 // a valid Context object, which itself cannot be retrieved
51 // during early startup, where this method is called. And making it
52 // an explicit parameter here makes all call paths _much_ more
55 Pattern pattern = Pattern.compile("^MemTotal:\\s+([0-9]+) kB$");
56 // Synchronously reading files in /proc in the UI thread is safe.
57 StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
59 FileReader fileReader = new FileReader("/proc/meminfo");
61 BufferedReader reader = new BufferedReader(fileReader);
65 line = reader.readLine();
67 Log.w(TAG, "/proc/meminfo lacks a MemTotal entry?");
70 Matcher m = pattern.matcher(line);
71 if (!m.find()) continue;
73 int totalMemoryKB = Integer.parseInt(m.group(1));
75 if (totalMemoryKB <= 1024) {
76 Log.w(TAG, "Invalid /proc/meminfo total size in kB: " + m.group(1));
89 } catch (Exception e) {
90 Log.w(TAG, "Cannot get total physical size from /proc/meminfo", e);
92 StrictMode.setThreadPolicy(oldPolicy);
99 * @return Whether or not this device should be considered a low end device.
102 public static boolean isLowEndDevice() {
103 if (sLowEndDevice == null) {
104 sLowEndDevice = detectLowEndDevice();
106 return sLowEndDevice.booleanValue();
109 private static boolean detectLowEndDevice() {
110 if (CommandLine.isInitialized()) {
111 if (CommandLine.getInstance().hasSwitch(BaseSwitches.ENABLE_LOW_END_DEVICE_MODE)) {
114 if (CommandLine.getInstance().hasSwitch(BaseSwitches.DISABLE_LOW_END_DEVICE_MODE)) {
119 if (Build.VERSION.SDK_INT <= ANDROID_LOW_MEMORY_ANDROID_SDK_THRESHOLD) {
123 int ramSizeKB = amountOfPhysicalMemoryKB();
124 return (ramSizeKB > 0 && ramSizeKB / 1024 < ANDROID_LOW_MEMORY_DEVICE_THRESHOLD_MB);