• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 package org.chromium.base;
6 
7 import android.os.StrictMode;
8 import android.util.Log;
9 
10 import org.chromium.base.annotations.CalledByNative;
11 
12 import java.io.BufferedReader;
13 import java.io.FileReader;
14 import java.util.regex.Matcher;
15 import java.util.regex.Pattern;
16 
17 /**
18  * Exposes system related information about the current device.
19  */
20 public class SysUtils {
21     // A device reporting strictly more total memory in megabytes cannot be considered 'low-end'.
22     private static final int ANDROID_LOW_MEMORY_DEVICE_THRESHOLD_MB = 512;
23 
24     private static final String TAG = "SysUtils";
25 
26     private static Boolean sLowEndDevice;
27 
SysUtils()28     private SysUtils() { }
29 
30     /**
31      * Return the amount of physical memory on this device in kilobytes.
32      * @return Amount of physical memory in kilobytes, or 0 if there was
33      *         an error trying to access the information.
34      */
amountOfPhysicalMemoryKB()35     private static int amountOfPhysicalMemoryKB() {
36         // Extract total memory RAM size by parsing /proc/meminfo, note that
37         // this is exactly what the implementation of sysconf(_SC_PHYS_PAGES)
38         // does. However, it can't be called because this method must be
39         // usable before any native code is loaded.
40 
41         // An alternative is to use ActivityManager.getMemoryInfo(), but this
42         // requires a valid ActivityManager handle, which can only come from
43         // a valid Context object, which itself cannot be retrieved
44         // during early startup, where this method is called. And making it
45         // an explicit parameter here makes all call paths _much_ more
46         // complicated.
47 
48         Pattern pattern = Pattern.compile("^MemTotal:\\s+([0-9]+) kB$");
49         // Synchronously reading files in /proc in the UI thread is safe.
50         StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
51         try {
52             FileReader fileReader = new FileReader("/proc/meminfo");
53             try {
54                 BufferedReader reader = new BufferedReader(fileReader);
55                 try {
56                     String line;
57                     for (;;) {
58                         line = reader.readLine();
59                         if (line == null) {
60                             Log.w(TAG, "/proc/meminfo lacks a MemTotal entry?");
61                             break;
62                         }
63                         Matcher m = pattern.matcher(line);
64                         if (!m.find()) continue;
65 
66                         int totalMemoryKB = Integer.parseInt(m.group(1));
67                         // Sanity check.
68                         if (totalMemoryKB <= 1024) {
69                             Log.w(TAG, "Invalid /proc/meminfo total size in kB: " + m.group(1));
70                             break;
71                         }
72 
73                         return totalMemoryKB;
74                     }
75 
76                 } finally {
77                     reader.close();
78                 }
79             } finally {
80                 fileReader.close();
81             }
82         } catch (Exception e) {
83             Log.w(TAG, "Cannot get total physical size from /proc/meminfo", e);
84         } finally {
85             StrictMode.setThreadPolicy(oldPolicy);
86         }
87 
88         return 0;
89     }
90 
91     /**
92      * @return Whether or not this device should be considered a low end device.
93      */
94     @CalledByNative
isLowEndDevice()95     public static boolean isLowEndDevice() {
96         if (sLowEndDevice == null) {
97             sLowEndDevice = detectLowEndDevice();
98         }
99         return sLowEndDevice.booleanValue();
100     }
101 
detectLowEndDevice()102     private static boolean detectLowEndDevice() {
103         assert CommandLine.isInitialized();
104         if (CommandLine.getInstance().hasSwitch(BaseSwitches.ENABLE_LOW_END_DEVICE_MODE)) {
105             return true;
106         }
107         if (CommandLine.getInstance().hasSwitch(BaseSwitches.DISABLE_LOW_END_DEVICE_MODE)) {
108             return false;
109         }
110 
111         int ramSizeKB = amountOfPhysicalMemoryKB();
112         return (ramSizeKB > 0 && ramSizeKB / 1024 <= ANDROID_LOW_MEMORY_DEVICE_THRESHOLD_MB);
113     }
114 }
115