summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordigit@chromium.org <digit@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-11-08 01:04:57 +0000
committerdigit@chromium.org <digit@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-11-08 01:04:57 +0000
commit095e4dc9888210cb153f712830e7f07e8c9c9a51 (patch)
tree8524937dae2c4ce3986362f1cb28d455ec356c42
parentf0ad54cdb589d9054b86f49872d338b682ba590d (diff)
downloadchromium_src-095e4dc9888210cb153f712830e7f07e8c9c9a51.zip
chromium_src-095e4dc9888210cb153f712830e7f07e8c9c9a51.tar.gz
chromium_src-095e4dc9888210cb153f712830e7f07e8c9c9a51.tar.bz2
android: Make org.chromium.base.SysUtils.isLowEndDevice() work without native code.
This patch modifies the implementation if SysUtils.isLowEndDevice() to not rely on any native code, which is required to run it before the native libraries are actually loaded (e.g. when running certain tests). + Simplify the content linker that doesn't need a specific native method anymore to replicate the yet-unloaded native SysUtils::IsLowEndDevice(). BUG=309926 R=dtrainor@chromium.org,tedchoc@chromium.org,frankf@chromium.org,bulach@chromium.org TEST=build/android/test_runner.py linker Review URL: https://codereview.chromium.org/59033008 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@233739 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--base/android/java/src/org/chromium/base/SysUtils.java88
-rw-r--r--base/android/sys_utils.cc26
-rw-r--r--base/android/sys_utils.h4
-rw-r--r--base/android/sys_utils_unittest.cc23
-rw-r--r--base/base.gyp1
-rw-r--r--build/android/pylib/linker/setup.py3
-rw-r--r--build/android/pylib/linker/test_case.py64
-rw-r--r--content/common/android/linker/linker_jni.cc37
-rw-r--r--content/public/android/java/src/org/chromium/content/app/Linker.java7
9 files changed, 125 insertions, 128 deletions
diff --git a/base/android/java/src/org/chromium/base/SysUtils.java b/base/android/java/src/org/chromium/base/SysUtils.java
index 7af5a40..c100aee 100644
--- a/base/android/java/src/org/chromium/base/SysUtils.java
+++ b/base/android/java/src/org/chromium/base/SysUtils.java
@@ -4,27 +4,109 @@
package org.chromium.base;
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
import android.app.ActivityManager;
import android.app.ActivityManager.MemoryInfo;
import android.content.Context;
import android.os.Build;
+import android.util.Log;
/**
* Exposes system related information about the current device.
*/
public class SysUtils {
+ // Any device that runs this or an older version of the system cannot be considered 'low-end'
+ private static final int ANDROID_LOW_MEMORY_ANDROID_SDK_THRESHOLD =
+ Build.VERSION_CODES.JELLY_BEAN_MR2;
+
+ // A device reporting strictly more total memory in megabytes cannot be considered 'low-end'.
+ private static final long ANDROID_LOW_MEMORY_DEVICE_THRESHOLD_MB = 512;
+
+ private static final String TAG = "SysUtils";
+
private static Boolean sLowEndDevice;
private SysUtils() { }
/**
+ * Return the amount of physical memory on this device in kilobytes.
+ * Note: the only reason this is public is for testability reason.
+ * @return Amount of physical memory in kilobytes, or 0 if there was
+ * an error trying to access the information.
+ *
+ * Note that this is CalledByNative for testing purpose only.
+ */
+ @CalledByNative
+ public static int amountOfPhysicalMemoryKB() {
+ // Extract total memory RAM size by parsing /proc/meminfo, note that
+ // this is exactly what the implementation of sysconf(_SC_PHYS_PAGES)
+ // does. However, it can't be called because this method must be
+ // usable before any native code is loaded.
+
+ // An alternative is to use ActivityManager.getMemoryInfo(), but this
+ // requires a valid ActivityManager handle, which can only come from
+ // a valid Context object, which itself cannot be retrieved
+ // during early startup, where this method is called. And making it
+ // an explicit parameter here makes all call paths _much_ more
+ // complicated.
+
+ Pattern pattern = Pattern.compile("^MemTotal:\\s+([0-9]+) kB$");
+ try {
+ FileReader fileReader = new FileReader("/proc/meminfo");
+ try {
+ BufferedReader reader = new BufferedReader(fileReader);
+ try {
+ String line;
+ for (;;) {
+ line = reader.readLine();
+ if (line == null) {
+ Log.w(TAG, "/proc/meminfo lacks a MemTotal entry?");
+ break;
+ }
+ Matcher m = pattern.matcher(line);
+ if (!m.find()) continue;
+
+ int totalMemoryKB = Integer.parseInt(m.group(1));
+ // Sanity check.
+ if (totalMemoryKB <= 1024) {
+ Log.w(TAG, "Invalid /proc/meminfo total size in kB: " + m.group(1));
+ break;
+ }
+
+ return totalMemoryKB;
+ }
+
+ } finally {
+ reader.close();
+ }
+ } finally {
+ fileReader.close();
+ }
+ } catch (Exception e) {
+ Log.w(TAG, "Cannot get total physical size from /proc/meminfo", e);
+ }
+
+ return 0;
+ }
+
+ /**
* @return Whether or not this device should be considered a low end device.
*/
+ @CalledByNative
public static boolean isLowEndDevice() {
- if (sLowEndDevice == null) sLowEndDevice = nativeIsLowEndDevice();
+ if (Build.VERSION.SDK_INT <= ANDROID_LOW_MEMORY_ANDROID_SDK_THRESHOLD) {
+ return false;
+ }
+ if (sLowEndDevice == null) {
+ int ramSizeKB = amountOfPhysicalMemoryKB();
+ sLowEndDevice = (ramSizeKB > 0 &&
+ ramSizeKB * 1024 < ANDROID_LOW_MEMORY_DEVICE_THRESHOLD_MB);
+ }
return sLowEndDevice.booleanValue();
}
-
- private static native boolean nativeIsLowEndDevice();
}
diff --git a/base/android/sys_utils.cc b/base/android/sys_utils.cc
index 2a7db19..103324d 100644
--- a/base/android/sys_utils.cc
+++ b/base/android/sys_utils.cc
@@ -8,23 +8,6 @@
#include "base/sys_info.h"
#include "jni/SysUtils_jni.h"
-// Any device that reports a physical RAM size less than this, in megabytes
-// is considered 'low-end'. IMPORTANT: Read the LinkerLowMemoryThresholdTest
-// comments in build/android/pylib/linker/test_case.py before modifying this
-// value.
-#define ANDROID_LOW_MEMORY_DEVICE_THRESHOLD_MB 512
-
-const int64 kLowEndMemoryThreshold =
- 1024 * 1024 * ANDROID_LOW_MEMORY_DEVICE_THRESHOLD_MB;
-
-// Only support low end device changes on builds greater than JB MR2.
-const int kLowEndSdkIntThreshold = 18;
-
-// Defined and called by JNI
-static jboolean IsLowEndDevice(JNIEnv* env, jclass clazz) {
- return base::android::SysUtils::IsLowEndDevice();
-}
-
namespace base {
namespace android {
@@ -33,8 +16,13 @@ bool SysUtils::Register(JNIEnv* env) {
}
bool SysUtils::IsLowEndDevice() {
- return SysInfo::AmountOfPhysicalMemory() <= kLowEndMemoryThreshold &&
- BuildInfo::GetInstance()->sdk_int() > kLowEndSdkIntThreshold;
+ JNIEnv* env = AttachCurrentThread();
+ return Java_SysUtils_isLowEndDevice(env);
+}
+
+size_t SysUtils::AmountOfPhysicalMemoryKB() {
+ JNIEnv* env = AttachCurrentThread();
+ return static_cast<size_t>(Java_SysUtils_amountOfPhysicalMemoryKB(env));
}
SysUtils::SysUtils() { }
diff --git a/base/android/sys_utils.h b/base/android/sys_utils.h
index 78122ff..318c75e 100644
--- a/base/android/sys_utils.h
+++ b/base/android/sys_utils.h
@@ -14,8 +14,12 @@ class BASE_EXPORT SysUtils {
public:
static bool Register(JNIEnv* env);
+ // Returns true iff this is a low-end device.
static bool IsLowEndDevice();
+ // Return the device's RAM size in kilo-bytes. Used for testing.
+ static size_t AmountOfPhysicalMemoryKB();
+
private:
SysUtils();
};
diff --git a/base/android/sys_utils_unittest.cc b/base/android/sys_utils_unittest.cc
new file mode 100644
index 0000000..2a5a17d
--- /dev/null
+++ b/base/android/sys_utils_unittest.cc
@@ -0,0 +1,23 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/sys_utils.h"
+
+#include <unistd.h>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace android {
+
+TEST(SysUtils, AmountOfPhysicalMemory) {
+ // Check that the RAM size reported by sysconf() matches the one
+ // computed by base::android::SysUtils::AmountOfPhysicalMemory().
+ size_t sys_ram_size =
+ static_cast<size_t>(sysconf(_SC_PHYS_PAGES) * PAGE_SIZE);
+ EXPECT_EQ(sys_ram_size, SysUtils::AmountOfPhysicalMemoryKB() * 1024UL);
+}
+
+} // namespace android
+} // namespace base
diff --git a/base/base.gyp b/base/base.gyp
index 6fba8d3d..f9ac7f3 100644
--- a/base/base.gyp
+++ b/base/base.gyp
@@ -460,6 +460,7 @@
'android/jni_string_unittest.cc',
'android/path_utils_unittest.cc',
'android/scoped_java_ref_unittest.cc',
+ 'android/sys_utils_unittest.cc',
'async_socket_io_handler_unittest.cc',
'at_exit_unittest.cc',
'atomicops_unittest.cc',
diff --git a/build/android/pylib/linker/setup.py b/build/android/pylib/linker/setup.py
index 4024fa7..a13ea4d 100644
--- a/build/android/pylib/linker/setup.py
+++ b/build/android/pylib/linker/setup.py
@@ -27,8 +27,7 @@ def Setup(options, devices):
test_cases = [
test_case.LinkerLibraryAddressTest,
test_case.LinkerSharedRelroTest,
- test_case.LinkerRandomizationTest,
- test_case.LinkerLowMemoryThresholdTest ]
+ test_case.LinkerRandomizationTest ]
low_memory_modes = [False, True]
all_tests = [t(is_low_memory=m) for t in test_cases for m in low_memory_modes]
diff --git a/build/android/pylib/linker/test_case.py b/build/android/pylib/linker/test_case.py
index 3f8ea73..b4bddc7 100644
--- a/build/android/pylib/linker/test_case.py
+++ b/build/android/pylib/linker/test_case.py
@@ -554,67 +554,3 @@ class LinkerRandomizationTest(LinkerTestCaseBase):
return ResultType.FAIL, renderer_logs
return ResultType.PASS, logs
-
-
-class LinkerLowMemoryThresholdTest(LinkerTestCaseBase):
- """This test checks that the definitions for the low-memory device physical
- RAM threshold are identical in the base/ and linker sources. Because these
- two components should absolutely not depend on each other, it's difficult
- to perform this check correctly at runtime inside the linker test binary
- without introducing hairy dependency issues in the build, or complicated
- plumbing at runtime.
-
- To work-around this, this test looks directly into the sources for a
- definition of the same constant that should look like:
-
- #define ANDROID_LOW_MEMORY_DEVICE_THRESHOLD_MB <number>
-
- And will check that the values for <number> are identical in all of
- them."""
-
- # A regular expression used to find the definition of the threshold in all
- # sources:
- _RE_THRESHOLD_DEFINITION = re.compile(
- r'^\s*#\s*define\s+ANDROID_LOW_MEMORY_DEVICE_THRESHOLD_MB\s+(\d+)\s*$',
- re.MULTILINE)
-
- # The list of source files, relative to DIR_SOURCE_ROOT, which must contain
- # a line that matches the re above.
- _SOURCES_LIST = [
- 'base/android/sys_utils.cc',
- 'content/common/android/linker/linker_jni.cc' ]
-
- def _RunTest(self, adb):
- failure = False
- values = []
- # First, collect all the values in all input sources.
- re = LinkerLowMemoryThresholdTest._RE_THRESHOLD_DEFINITION
- for source in LinkerLowMemoryThresholdTest._SOURCES_LIST:
- source_path = os.path.join(constants.DIR_SOURCE_ROOT, source);
- if not os.path.exists(source_path):
- logging.error('Missing source file: ' + source_path)
- failure = True
- continue
- with open(source_path) as f:
- source_text = f.read()
- # For some reason, re.match() never works here.
- source_values = re.findall(source_text)
- if not source_values:
- logging.error('Missing low-memory threshold definition in ' + \
- source_path)
- logging.error('Source:\n%s\n' % source_text)
- failure = True
- continue
- values += source_values
-
- # Second, check that they are all the same.
- if not failure:
- for value in values[1:]:
- if value != values[0]:
- logging.error('Value mismatch: ' + repr(values))
- failure = True
-
- if failure:
- return ResultType.FAIL, 'Incorrect low-end memory threshold definitions!'
-
- return ResultType.PASS, ''
diff --git a/content/common/android/linker/linker_jni.cc b/content/common/android/linker/linker_jni.cc
index 4254def..7db9fea 100644
--- a/content/common/android/linker/linker_jni.cc
+++ b/content/common/android/linker/linker_jni.cc
@@ -19,12 +19,6 @@
#include <stdlib.h>
#include <unistd.h>
-// Any device that reports a physical RAM size less than this, in megabytes
-// is considered 'low-end'. IMPORTANT: Read the LinkerLowMemoryThresholdTest
-// comments in build/android/pylib/linker/test_case.py before modifying this
-// value.
-#define ANDROID_LOW_MEMORY_DEVICE_THRESHOLD_MB 512
-
// Set this to 1 to enable debug traces to the Android log.
// Note that LOG() from "base/logging.h" cannot be used, since it is
// in base/ which hasn't been loaded yet.
@@ -388,30 +382,6 @@ jlong GetPageSize(JNIEnv* env, jclass clazz) {
return result;
}
-jboolean IsLowMemoryDevice(JNIEnv* env, jclass clazz) {
- // This matches the implementation of org.chromium.base.SysUtils.isLowEnd(),
- // however this Java method relies on native code from base/, which isn't
- // available since the library hasn't been loaded yet.
- // The value ANDROID_LOW_MEMORY_DEVICE_THRESHOLD_MB is the same for both
- // sources.
-
- // Threshold for low-end memory devices.
- const size_t kMegaBytes = 1024 * 1024;
- const size_t kLowMemoryDeviceThreshold =
- ANDROID_LOW_MEMORY_DEVICE_THRESHOLD_MB * kMegaBytes;
-
- // Compute the amount of physical RAM on the device.
- size_t pages = static_cast<size_t>(sysconf(_SC_PHYS_PAGES));
- size_t page_size = static_cast<size_t>(sysconf(_SC_PAGESIZE));
- size_t physical_size = pages * page_size;
-
- LOG_INFO("%s: System physical size is %zu MB\n",
- __FUNCTION__,
- physical_size / kMegaBytes);
-
- return physical_size <= kLowMemoryDeviceThreshold;
-}
-
const JNINativeMethod kNativeMethods[] = {
{"nativeLoadLibrary",
"("
@@ -445,12 +415,7 @@ const JNINativeMethod kNativeMethods[] = {
"("
")"
"J",
- reinterpret_cast<void*>(&GetPageSize)},
- {"nativeIsLowMemoryDevice",
- "("
- ")"
- "Z",
- reinterpret_cast<void*>(&IsLowMemoryDevice)}, };
+ reinterpret_cast<void*>(&GetPageSize)}, };
} // namespace
diff --git a/content/public/android/java/src/org/chromium/content/app/Linker.java b/content/public/android/java/src/org/chromium/content/app/Linker.java
index 5cfa822..3bcef73 100644
--- a/content/public/android/java/src/org/chromium/content/app/Linker.java
+++ b/content/public/android/java/src/org/chromium/content/app/Linker.java
@@ -18,6 +18,8 @@ import android.os.Parcelable;
import android.os.ParcelFileDescriptor;
import android.util.Log;
+import org.chromium.base.SysUtils;
+
/*
* Technical note:
*
@@ -240,7 +242,7 @@ public class Linker {
}
if (sMemoryDeviceConfig == MEMORY_DEVICE_CONFIG_INIT) {
- sMemoryDeviceConfig = nativeIsLowMemoryDevice() ?
+ sMemoryDeviceConfig = SysUtils.isLowEndDevice() ?
MEMORY_DEVICE_CONFIG_LOW : MEMORY_DEVICE_CONFIG_NORMAL;
}
@@ -886,9 +888,6 @@ public class Linker {
// Returns the native page size in bytes.
private static native long nativeGetPageSize();
- // Checks whether this is a low-memory device.
- private static native boolean nativeIsLowMemoryDevice();
-
/**
* Record information for a given library.
* IMPORTANT: Native code knows about this class's fields, so