1108d9ed555b83b37bb84ea1f1701a7fda3c8f7f
[platform/framework/web/crosswalk.git] / src / base / android / java / src / org / chromium / base / SysUtils.java
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.Build;
8 import android.os.StrictMode;
9 import android.util.Log;
10
11 import java.io.BufferedReader;
12 import java.io.FileReader;
13 import java.util.regex.Matcher;
14 import java.util.regex.Pattern;
15
16 /**
17  * Exposes system related information about the current device.
18  */
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;
23
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;
26
27     private static final String TAG = "SysUtils";
28
29     private static Boolean sLowEndDevice;
30
31     private SysUtils() { }
32
33     /**
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.
37      */
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.
43
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
49         // complicated.
50
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();
54         try {
55             FileReader fileReader = new FileReader("/proc/meminfo");
56             try {
57                 BufferedReader reader = new BufferedReader(fileReader);
58                 try {
59                     String line;
60                     for (;;) {
61                         line = reader.readLine();
62                         if (line == null) {
63                             Log.w(TAG, "/proc/meminfo lacks a MemTotal entry?");
64                             break;
65                         }
66                         Matcher m = pattern.matcher(line);
67                         if (!m.find()) continue;
68
69                         int totalMemoryKB = Integer.parseInt(m.group(1));
70                         // Sanity check.
71                         if (totalMemoryKB <= 1024) {
72                             Log.w(TAG, "Invalid /proc/meminfo total size in kB: " + m.group(1));
73                             break;
74                         }
75
76                         return totalMemoryKB;
77                     }
78
79                 } finally {
80                     reader.close();
81                 }
82             } finally {
83                 fileReader.close();
84             }
85         } catch (Exception e) {
86             Log.w(TAG, "Cannot get total physical size from /proc/meminfo", e);
87         } finally {
88             StrictMode.setThreadPolicy(oldPolicy);
89         }
90
91         return 0;
92     }
93
94     /**
95      * @return Whether or not this device should be considered a low end device.
96      */
97     @CalledByNative
98     public static boolean isLowEndDevice() {
99         if (sLowEndDevice == null) {
100             sLowEndDevice = detectLowEndDevice();
101         }
102         return sLowEndDevice.booleanValue();
103     }
104
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));
110                 if (mode == 1)
111                     return true;
112                 if (mode == 0)
113                     return false;
114             }
115         }
116
117         if (Build.VERSION.SDK_INT <= ANDROID_LOW_MEMORY_ANDROID_SDK_THRESHOLD) {
118             return false;
119         }
120
121         int ramSizeKB = amountOfPhysicalMemoryKB();
122         return (ramSizeKB > 0 && ramSizeKB / 1024 < ANDROID_LOW_MEMORY_DEVICE_THRESHOLD_MB);
123     }
124 }