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 * @return Amount of physical memory in kilobytes, or 0 if there was
36 * an error trying to access the information.
38 private static int amountOfPhysicalMemoryKB() {
39 // Extract total memory RAM size by parsing /proc/meminfo, note that
40 // this is exactly what the implementation of sysconf(_SC_PHYS_PAGES)
41 // does. However, it can't be called because this method must be
42 // usable before any native code is loaded.
44 // An alternative is to use ActivityManager.getMemoryInfo(), but this
45 // requires a valid ActivityManager handle, which can only come from
46 // a valid Context object, which itself cannot be retrieved
47 // during early startup, where this method is called. And making it
48 // an explicit parameter here makes all call paths _much_ more
51 Pattern pattern = Pattern.compile("^MemTotal:\\s+([0-9]+) kB$");
52 // Synchronously reading files in /proc in the UI thread is safe.
53 StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
55 FileReader fileReader = new FileReader("/proc/meminfo");
57 BufferedReader reader = new BufferedReader(fileReader);
61 line = reader.readLine();
63 Log.w(TAG, "/proc/meminfo lacks a MemTotal entry?");
66 Matcher m = pattern.matcher(line);
67 if (!m.find()) continue;
69 int totalMemoryKB = Integer.parseInt(m.group(1));
71 if (totalMemoryKB <= 1024) {
72 Log.w(TAG, "Invalid /proc/meminfo total size in kB: " + m.group(1));
85 } catch (Exception e) {
86 Log.w(TAG, "Cannot get total physical size from /proc/meminfo", e);
88 StrictMode.setThreadPolicy(oldPolicy);
95 * @return Whether or not this device should be considered a low end device.
98 public static boolean isLowEndDevice() {
99 if (sLowEndDevice == null) {
100 sLowEndDevice = detectLowEndDevice();
102 return sLowEndDevice.booleanValue();
105 private static boolean detectLowEndDevice() {
106 if (CommandLine.isInitialized()) {
107 if (CommandLine.getInstance().hasSwitch(BaseSwitches.LOW_END_DEVICE_MODE)) {
108 int mode = Integer.parseInt(CommandLine.getInstance().getSwitchValue(
109 BaseSwitches.LOW_END_DEVICE_MODE));
117 if (Build.VERSION.SDK_INT <= ANDROID_LOW_MEMORY_ANDROID_SDK_THRESHOLD) {
121 int ramSizeKB = amountOfPhysicalMemoryKB();
122 return (ramSizeKB > 0 && ramSizeKB / 1024 < ANDROID_LOW_MEMORY_DEVICE_THRESHOLD_MB);