PageRenderTime 58ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/base/ios/device_util.mm

https://github.com/chromium/chromium
Objective C++ | 183 lines | 135 code | 30 blank | 18 comment | 18 complexity | 1eacf257948f847609de344cc34c0000 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, Apache-2.0, BSD-3-Clause
  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. #include "base/ios/device_util.h"
  5. #include <CommonCrypto/CommonDigest.h>
  6. #import <UIKit/UIKit.h>
  7. #include <ifaddrs.h>
  8. #include <net/if_dl.h>
  9. #include <stddef.h>
  10. #include <string.h>
  11. #include <sys/socket.h>
  12. #include <sys/sysctl.h>
  13. #include <memory>
  14. #include "base/check.h"
  15. #include "base/mac/scoped_cftyperef.h"
  16. #include "base/strings/string_util.h"
  17. #include "base/strings/stringprintf.h"
  18. #include "base/strings/sys_string_conversions.h"
  19. namespace {
  20. // Client ID key in the user preferences.
  21. NSString* const kLegacyClientIdPreferenceKey = @"ChromiumClientID";
  22. NSString* const kClientIdPreferenceKey = @"ChromeClientID";
  23. // Current hardware type. This is used to detect that a device has been backed
  24. // up and restored to another device, and allows regenerating a new device id.
  25. NSString* const kHardwareTypePreferenceKey = @"ClientIDGenerationHardwareType";
  26. // Default salt for device ids.
  27. const char kDefaultSalt[] = "Salt";
  28. // Zero UUID returned on buggy iOS devices.
  29. NSString* const kZeroUUID = @"00000000-0000-0000-0000-000000000000";
  30. NSString* GenerateClientId() {
  31. NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
  32. // Try to migrate from legacy client id.
  33. NSString* client_id = [defaults stringForKey:kLegacyClientIdPreferenceKey];
  34. // Some iOS6 devices return a buggy identifierForVendor:
  35. // http://openradar.appspot.com/12377282. If this is the case, revert to
  36. // generating a new one.
  37. if (!client_id || [client_id isEqualToString:kZeroUUID]) {
  38. client_id = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
  39. if ([client_id isEqualToString:kZeroUUID])
  40. client_id = base::SysUTF8ToNSString(ios::device_util::GetRandomId());
  41. }
  42. return client_id;
  43. }
  44. } // namespace
  45. namespace ios {
  46. namespace device_util {
  47. std::string GetPlatform() {
  48. std::string platform;
  49. size_t size = 0;
  50. sysctlbyname("hw.machine", NULL, &size, NULL, 0);
  51. sysctlbyname("hw.machine", base::WriteInto(&platform, size), &size, NULL, 0);
  52. return platform;
  53. }
  54. bool RamIsAtLeast512Mb() {
  55. // 512MB devices report anywhere from 502-504 MB, use 450 MB just to be safe.
  56. return RamIsAtLeast(450);
  57. }
  58. bool RamIsAtLeast1024Mb() {
  59. // 1GB devices report anywhere from 975-999 MB, use 900 MB just to be safe.
  60. return RamIsAtLeast(900);
  61. }
  62. bool RamIsAtLeast(uint64_t ram_in_mb) {
  63. uint64_t memory_size = 0;
  64. size_t size = sizeof(memory_size);
  65. if (sysctlbyname("hw.memsize", &memory_size, &size, NULL, 0) == 0) {
  66. // Anything >= 500M, call high ram.
  67. return memory_size >= ram_in_mb * 1024 * 1024;
  68. }
  69. return false;
  70. }
  71. bool IsSingleCoreDevice() {
  72. uint64_t cpu_number = 0;
  73. size_t sizes = sizeof(cpu_number);
  74. sysctlbyname("hw.physicalcpu", &cpu_number, &sizes, NULL, 0);
  75. return cpu_number == 1;
  76. }
  77. std::string GetMacAddress(const std::string& interface_name) {
  78. std::string mac_string;
  79. struct ifaddrs* addresses;
  80. if (getifaddrs(&addresses) == 0) {
  81. for (struct ifaddrs* address = addresses; address;
  82. address = address->ifa_next) {
  83. if ((address->ifa_addr->sa_family == AF_LINK) &&
  84. strcmp(interface_name.c_str(), address->ifa_name) == 0) {
  85. const struct sockaddr_dl* found_address_struct =
  86. reinterpret_cast<const struct sockaddr_dl*>(address->ifa_addr);
  87. // |found_address_struct->sdl_data| contains the interface name followed
  88. // by the interface address. The address part can be accessed based on
  89. // the length of the name, that is, |found_address_struct->sdl_nlen|.
  90. const unsigned char* found_address =
  91. reinterpret_cast<const unsigned char*>(
  92. &found_address_struct->sdl_data[
  93. found_address_struct->sdl_nlen]);
  94. int found_address_length = found_address_struct->sdl_alen;
  95. for (int i = 0; i < found_address_length; ++i) {
  96. if (i != 0)
  97. mac_string.push_back(':');
  98. base::StringAppendF(&mac_string, "%02X", found_address[i]);
  99. }
  100. break;
  101. }
  102. }
  103. freeifaddrs(addresses);
  104. }
  105. return mac_string;
  106. }
  107. std::string GetRandomId() {
  108. base::ScopedCFTypeRef<CFUUIDRef> uuid_object(
  109. CFUUIDCreate(kCFAllocatorDefault));
  110. base::ScopedCFTypeRef<CFStringRef> uuid_string(
  111. CFUUIDCreateString(kCFAllocatorDefault, uuid_object));
  112. return base::SysCFStringRefToUTF8(uuid_string);
  113. }
  114. std::string GetDeviceIdentifier(const char* salt) {
  115. NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
  116. NSString* last_seen_hardware =
  117. [defaults stringForKey:kHardwareTypePreferenceKey];
  118. NSString* current_hardware = base::SysUTF8ToNSString(GetPlatform());
  119. if (!last_seen_hardware) {
  120. last_seen_hardware = current_hardware;
  121. [defaults setObject:current_hardware forKey:kHardwareTypePreferenceKey];
  122. [defaults synchronize];
  123. }
  124. NSString* client_id = [defaults stringForKey:kClientIdPreferenceKey];
  125. if (!client_id || ![last_seen_hardware isEqualToString:current_hardware]) {
  126. client_id = GenerateClientId();
  127. [defaults setObject:client_id forKey:kClientIdPreferenceKey];
  128. [defaults setObject:current_hardware forKey:kHardwareTypePreferenceKey];
  129. [defaults synchronize];
  130. }
  131. return GetSaltedString(base::SysNSStringToUTF8(client_id),
  132. salt ? salt : kDefaultSalt);
  133. }
  134. std::string GetVendorId() {
  135. return base::SysNSStringToUTF8(
  136. [[[UIDevice currentDevice] identifierForVendor] UUIDString]);
  137. }
  138. std::string GetSaltedString(const std::string& in_string,
  139. const std::string& salt) {
  140. DCHECK(salt.length());
  141. NSData* hash_data = [base::SysUTF8ToNSString(in_string + salt)
  142. dataUsingEncoding:NSUTF8StringEncoding];
  143. unsigned char hash[CC_SHA256_DIGEST_LENGTH];
  144. CC_SHA256([hash_data bytes], [hash_data length], hash);
  145. CFUUIDBytes* uuid_bytes = reinterpret_cast<CFUUIDBytes*>(hash);
  146. base::ScopedCFTypeRef<CFUUIDRef> uuid_object(
  147. CFUUIDCreateFromUUIDBytes(kCFAllocatorDefault, *uuid_bytes));
  148. base::ScopedCFTypeRef<CFStringRef> device_id(
  149. CFUUIDCreateString(kCFAllocatorDefault, uuid_object));
  150. return base::SysCFStringRefToUTF8(device_id);
  151. }
  152. } // namespace device_util
  153. } // namespace ios