1// Copyright (c) 2012 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#include "base/sys_info.h" 6 7#include <dlfcn.h> 8#include <sys/system_properties.h> 9 10#include "base/lazy_instance.h" 11#include "base/logging.h" 12#include "base/strings/string_number_conversions.h" 13#include "base/strings/string_piece.h" 14#include "base/strings/stringprintf.h" 15#include "base/sys_info_internal.h" 16 17// TODO(rmcilroy): Update API level when 'L' gets an official API level. 18#if (__ANDROID_API__ >= 9999 /* 'L' */) 19 20namespace { 21 22typedef int (SystemPropertyGetFunction)(const char*, char*); 23 24SystemPropertyGetFunction* DynamicallyLoadRealSystemPropertyGet() { 25 // libc.so should already be open, get a handle to it. 26 void* handle = dlopen("libc.so", RTLD_NOLOAD); 27 if (!handle) { 28 LOG(FATAL) << "Cannot dlopen libc.so: " << dlerror(); 29 } 30 SystemPropertyGetFunction* real_system_property_get = 31 reinterpret_cast<SystemPropertyGetFunction*>( 32 dlsym(handle, "__system_property_get")); 33 if (!real_system_property_get) { 34 LOG(FATAL) << "Cannot resolve __system_property_get(): " << dlerror(); 35 } 36 return real_system_property_get; 37} 38 39static base::LazyInstance<base::internal::LazySysInfoValue< 40 SystemPropertyGetFunction*, DynamicallyLoadRealSystemPropertyGet> >::Leaky 41 g_lazy_real_system_property_get = LAZY_INSTANCE_INITIALIZER; 42 43} // namespace 44 45// Android 'L' removes __system_property_get from the NDK, however it is still 46// a hidden symbol in libc. Until we remove all calls of __system_property_get 47// from Chrome we work around this by defining a weak stub here, which uses 48// dlsym to but ensures that Chrome uses the real system 49// implementatation when loaded. http://crbug.com/392191. 50int __system_property_get(const char* name, char* value) { 51 return g_lazy_real_system_property_get.Get().value()(name, value); 52} 53 54#endif 55 56namespace { 57 58// Default version of Android to fall back to when actual version numbers 59// cannot be acquired. Use the latest Android release with a higher bug fix 60// version to avoid unnecessarily comparison errors with the latest release. 61// This should be manually kept up-to-date on each Android release. 62const int kDefaultAndroidMajorVersion = 4; 63const int kDefaultAndroidMinorVersion = 4; 64const int kDefaultAndroidBugfixVersion = 99; 65 66// Parse out the OS version numbers from the system properties. 67void ParseOSVersionNumbers(const char* os_version_str, 68 int32 *major_version, 69 int32 *minor_version, 70 int32 *bugfix_version) { 71 if (os_version_str[0]) { 72 // Try to parse out the version numbers from the string. 73 int num_read = sscanf(os_version_str, "%d.%d.%d", major_version, 74 minor_version, bugfix_version); 75 76 if (num_read > 0) { 77 // If we don't have a full set of version numbers, make the extras 0. 78 if (num_read < 2) *minor_version = 0; 79 if (num_read < 3) *bugfix_version = 0; 80 return; 81 } 82 } 83 84 // For some reason, we couldn't parse the version number string. 85 *major_version = kDefaultAndroidMajorVersion; 86 *minor_version = kDefaultAndroidMinorVersion; 87 *bugfix_version = kDefaultAndroidBugfixVersion; 88} 89 90// Parses a system property (specified with unit 'k','m' or 'g'). 91// Returns a value in bytes. 92// Returns -1 if the string could not be parsed. 93int64 ParseSystemPropertyBytes(const base::StringPiece& str) { 94 const int64 KB = 1024; 95 const int64 MB = 1024 * KB; 96 const int64 GB = 1024 * MB; 97 if (str.size() == 0u) 98 return -1; 99 int64 unit_multiplier = 1; 100 size_t length = str.size(); 101 if (str[length - 1] == 'k') { 102 unit_multiplier = KB; 103 length--; 104 } else if (str[length - 1] == 'm') { 105 unit_multiplier = MB; 106 length--; 107 } else if (str[length - 1] == 'g') { 108 unit_multiplier = GB; 109 length--; 110 } 111 int64 result = 0; 112 bool parsed = base::StringToInt64(str.substr(0, length), &result); 113 bool negative = result <= 0; 114 bool overflow = result >= std::numeric_limits<int64>::max() / unit_multiplier; 115 if (!parsed || negative || overflow) 116 return -1; 117 return result * unit_multiplier; 118} 119 120int GetDalvikHeapSizeMB() { 121 char heap_size_str[PROP_VALUE_MAX]; 122 __system_property_get("dalvik.vm.heapsize", heap_size_str); 123 // dalvik.vm.heapsize property is writable by a root user. 124 // Clamp it to reasonable range as a sanity check, 125 // a typical android device will never have less than 48MB. 126 const int64 MB = 1024 * 1024; 127 int64 result = ParseSystemPropertyBytes(heap_size_str); 128 if (result == -1) { 129 // We should consider not exposing these values if they are not reliable. 130 LOG(ERROR) << "Can't parse dalvik.vm.heapsize: " << heap_size_str; 131 result = base::SysInfo::AmountOfPhysicalMemoryMB() / 3; 132 } 133 result = std::min<int64>(std::max<int64>(32 * MB, result), 1024 * MB) / MB; 134 return static_cast<int>(result); 135} 136 137int GetDalvikHeapGrowthLimitMB() { 138 char heap_size_str[PROP_VALUE_MAX]; 139 __system_property_get("dalvik.vm.heapgrowthlimit", heap_size_str); 140 // dalvik.vm.heapgrowthlimit property is writable by a root user. 141 // Clamp it to reasonable range as a sanity check, 142 // a typical android device will never have less than 24MB. 143 const int64 MB = 1024 * 1024; 144 int64 result = ParseSystemPropertyBytes(heap_size_str); 145 if (result == -1) { 146 // We should consider not exposing these values if they are not reliable. 147 LOG(ERROR) << "Can't parse dalvik.vm.heapgrowthlimit: " << heap_size_str; 148 result = base::SysInfo::AmountOfPhysicalMemoryMB() / 6; 149 } 150 result = std::min<int64>(std::max<int64>(16 * MB, result), 512 * MB) / MB; 151 return static_cast<int>(result); 152} 153 154} // anonymous namespace 155 156namespace base { 157 158std::string SysInfo::OperatingSystemName() { 159 return "Android"; 160} 161 162std::string SysInfo::GetAndroidBuildCodename() { 163 char os_version_codename_str[PROP_VALUE_MAX]; 164 __system_property_get("ro.build.version.codename", os_version_codename_str); 165 return std::string(os_version_codename_str); 166} 167 168std::string SysInfo::GetAndroidBuildID() { 169 char os_build_id_str[PROP_VALUE_MAX]; 170 __system_property_get("ro.build.id", os_build_id_str); 171 return std::string(os_build_id_str); 172} 173 174std::string SysInfo::GetDeviceName() { 175 char device_model_str[PROP_VALUE_MAX]; 176 __system_property_get("ro.product.model", device_model_str); 177 return std::string(device_model_str); 178} 179 180std::string SysInfo::OperatingSystemVersion() { 181 int32 major, minor, bugfix; 182 OperatingSystemVersionNumbers(&major, &minor, &bugfix); 183 return StringPrintf("%d.%d.%d", major, minor, bugfix); 184} 185 186void SysInfo::OperatingSystemVersionNumbers(int32* major_version, 187 int32* minor_version, 188 int32* bugfix_version) { 189 // Read the version number string out from the properties. 190 char os_version_str[PROP_VALUE_MAX]; 191 __system_property_get("ro.build.version.release", os_version_str); 192 193 // Parse out the numbers. 194 ParseOSVersionNumbers(os_version_str, major_version, minor_version, 195 bugfix_version); 196} 197 198int SysInfo::DalvikHeapSizeMB() { 199 static int heap_size = GetDalvikHeapSizeMB(); 200 return heap_size; 201} 202 203int SysInfo::DalvikHeapGrowthLimitMB() { 204 static int heap_growth_limit = GetDalvikHeapGrowthLimitMB(); 205 return heap_growth_limit; 206} 207 208 209} // namespace base 210