Upstream version 7.36.149.0
[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      * 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.
38      *
39      * Note that this is CalledByNative for testing purpose only.
40      */
41     @CalledByNative
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.
47
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
53         // complicated.
54
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();
58         try {
59             FileReader fileReader = new FileReader("/proc/meminfo");
60             try {
61                 BufferedReader reader = new BufferedReader(fileReader);
62                 try {
63                     String line;
64                     for (;;) {
65                         line = reader.readLine();
66                         if (line == null) {
67                             Log.w(TAG, "/proc/meminfo lacks a MemTotal entry?");
68                             break;
69                         }
70                         Matcher m = pattern.matcher(line);
71                         if (!m.find()) continue;
72
73                         int totalMemoryKB = Integer.parseInt(m.group(1));
74                         // Sanity check.
75                         if (totalMemoryKB <= 1024) {
76                             Log.w(TAG, "Invalid /proc/meminfo total size in kB: " + m.group(1));
77                             break;
78                         }
79
80                         return totalMemoryKB;
81                     }
82
83                 } finally {
84                     reader.close();
85                 }
86             } finally {
87                 fileReader.close();
88             }
89         } catch (Exception e) {
90             Log.w(TAG, "Cannot get total physical size from /proc/meminfo", e);
91         } finally {
92             StrictMode.setThreadPolicy(oldPolicy);
93         }
94
95         return 0;
96     }
97
98     /**
99      * @return Whether or not this device should be considered a low end device.
100      */
101     @CalledByNative
102     public static boolean isLowEndDevice() {
103         if (sLowEndDevice == null) {
104             sLowEndDevice = detectLowEndDevice();
105         }
106         return sLowEndDevice.booleanValue();
107     }
108
109     private static boolean detectLowEndDevice() {
110         if (CommandLine.isInitialized()) {
111             if (CommandLine.getInstance().hasSwitch(BaseSwitches.ENABLE_LOW_END_DEVICE_MODE)) {
112                 return true;
113             }
114             if (CommandLine.getInstance().hasSwitch(BaseSwitches.DISABLE_LOW_END_DEVICE_MODE)) {
115                 return false;
116             }
117         }
118
119         if (Build.VERSION.SDK_INT <= ANDROID_LOW_MEMORY_ANDROID_SDK_THRESHOLD) {
120             return false;
121         }
122
123         int ramSizeKB = amountOfPhysicalMemoryKB();
124         return (ramSizeKB > 0 && ramSizeKB / 1024 < ANDROID_LOW_MEMORY_DEVICE_THRESHOLD_MB);
125     }
126 }