blob: c3e9c2079fe5a92ad03f0c15952893af52c78d99 [file] [log] [blame]
[email protected]e16e8732012-08-07 11:03:111// 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/ios/device_util.h"
6
7#include <CommonCrypto/CommonDigest.h>
[email protected]aebcd0dd2012-10-05 17:48:588#import <UIKit/UIKit.h>
[email protected]e16e8732012-08-07 11:03:119
10#include <ifaddrs.h>
11#include <net/if_dl.h>
12#include <string.h>
13#include <sys/socket.h>
14#include <sys/sysctl.h>
15
[email protected]aebcd0dd2012-10-05 17:48:5816#include "base/ios/ios_util.h"
[email protected]e16e8732012-08-07 11:03:1117#include "base/logging.h"
[email protected]e16e8732012-08-07 11:03:1118#include "base/mac/scoped_cftyperef.h"
19#include "base/memory/scoped_ptr.h"
[email protected]d1a5a2f2013-06-10 21:17:4020#include "base/strings/string_util.h"
21#include "base/strings/stringprintf.h"
[email protected]9fe1a5b2013-02-07 19:18:0322#include "base/strings/sys_string_conversions.h"
[email protected]e16e8732012-08-07 11:03:1123
24namespace {
25
26// Client ID key in the user preferences.
[email protected]d724b552012-12-13 17:39:4727NSString* const kLegacyClientIdPreferenceKey = @"ChromiumClientID";
28NSString* const kClientIdPreferenceKey = @"ChromeClientID";
[email protected]af6a8c92012-12-20 16:41:3329// Current hardware type. This is used to detect that a device has been backed
30// up and restored to another device, and allows regenerating a new device id.
31NSString* const kHardwareTypePreferenceKey = @"ClientIDGenerationHardwareType";
[email protected]e16e8732012-08-07 11:03:1132// Default salt for device ids.
33const char kDefaultSalt[] = "Salt";
[email protected]d724b552012-12-13 17:39:4734// Zero UUID returned on buggy iOS devices.
35NSString* const kZeroUUID = @"00000000-0000-0000-0000-000000000000";
36
37NSString* GenerateClientId() {
38 NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
39
40 // Try to migrate from legacy client id.
41 NSString* client_id = [defaults stringForKey:kLegacyClientIdPreferenceKey];
42
43 // Some iOS6 devices return a buggy identifierForVendor:
44 // http://openradar.appspot.com/12377282. If this is the case, revert to
45 // generating a new one.
46 if (!client_id || [client_id isEqualToString:kZeroUUID]) {
47 if (base::ios::IsRunningOnIOS6OrLater()) {
48 client_id = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
[email protected]0644db72014-06-05 20:05:4349 if (!client_id || [client_id isEqualToString:kZeroUUID])
[email protected]d724b552012-12-13 17:39:4750 client_id = base::SysUTF8ToNSString(ios::device_util::GetRandomId());
51 } else {
52 client_id = base::SysUTF8ToNSString(ios::device_util::GetRandomId());
53 }
54 }
55 return client_id;
56}
[email protected]e16e8732012-08-07 11:03:1157
58} // namespace
59
60namespace ios {
61namespace device_util {
62
63std::string GetPlatform() {
64 std::string platform;
65 size_t size = 0;
66 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
67 sysctlbyname("hw.machine", WriteInto(&platform, size), &size, NULL, 0);
68 return platform;
69}
70
[email protected]4f150ec2014-03-18 21:54:4271bool RamIsAtLeast512Mb() {
72 // 512MB devices report anywhere from 502-504 MB, use 450 MB just to be safe.
73 return RamIsAtLeast(450);
74}
75
76bool RamIsAtLeast1024Mb() {
77 // 1GB devices report anywhere from 975-999 MB, use 900 MB just to be safe.
78 return RamIsAtLeast(900);
79}
80
81bool RamIsAtLeast(uint64_t ram_in_mb) {
[email protected]e16e8732012-08-07 11:03:1182 uint64_t memory_size = 0;
83 size_t size = sizeof(memory_size);
84 if (sysctlbyname("hw.memsize", &memory_size, &size, NULL, 0) == 0) {
[email protected]9317c2492013-12-11 22:18:4185 // Anything >= 500M, call high ram.
[email protected]4f150ec2014-03-18 21:54:4286 return memory_size >= ram_in_mb * 1024 * 1024;
[email protected]e16e8732012-08-07 11:03:1187 }
88 return false;
89}
90
91bool IsSingleCoreDevice() {
92 uint64_t cpu_number = 0;
93 size_t sizes = sizeof(cpu_number);
94 sysctlbyname("hw.physicalcpu", &cpu_number, &sizes, NULL, 0);
95 return cpu_number == 1;
96}
97
98std::string GetMacAddress(const std::string& interface_name) {
99 std::string mac_string;
100 struct ifaddrs* addresses;
101 if (getifaddrs(&addresses) == 0) {
102 for (struct ifaddrs* address = addresses; address;
103 address = address->ifa_next) {
104 if ((address->ifa_addr->sa_family == AF_LINK) &&
105 strcmp(interface_name.c_str(), address->ifa_name) == 0) {
106 const struct sockaddr_dl* found_address_struct =
107 reinterpret_cast<const struct sockaddr_dl*>(address->ifa_addr);
108
109 // |found_address_struct->sdl_data| contains the interface name followed
110 // by the interface address. The address part can be accessed based on
111 // the length of the name, that is, |found_address_struct->sdl_nlen|.
112 const unsigned char* found_address =
113 reinterpret_cast<const unsigned char*>(
114 &found_address_struct->sdl_data[
115 found_address_struct->sdl_nlen]);
116
117 int found_address_length = found_address_struct->sdl_alen;
118 for (int i = 0; i < found_address_length; ++i) {
119 if (i != 0)
120 mac_string.push_back(':');
121 base::StringAppendF(&mac_string, "%02X", found_address[i]);
122 }
123 break;
124 }
125 }
126 freeifaddrs(addresses);
127 }
128 return mac_string;
129}
130
131std::string GetRandomId() {
[email protected]3df79f42013-06-24 18:49:05132 base::ScopedCFTypeRef<CFUUIDRef> uuid_object(
133 CFUUIDCreate(kCFAllocatorDefault));
134 base::ScopedCFTypeRef<CFStringRef> uuid_string(
[email protected]e16e8732012-08-07 11:03:11135 CFUUIDCreateString(kCFAllocatorDefault, uuid_object));
136 return base::SysCFStringRefToUTF8(uuid_string);
137}
138
139std::string GetDeviceIdentifier(const char* salt) {
140 NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
[email protected]af6a8c92012-12-20 16:41:33141
142 NSString* last_seen_hardware =
143 [defaults stringForKey:kHardwareTypePreferenceKey];
144 NSString* current_hardware = base::SysUTF8ToNSString(GetPlatform());
145 if (!last_seen_hardware) {
146 last_seen_hardware = current_hardware;
147 [defaults setObject:current_hardware forKey:kHardwareTypePreferenceKey];
148 [defaults synchronize];
149 }
150
[email protected]e16e8732012-08-07 11:03:11151 NSString* client_id = [defaults stringForKey:kClientIdPreferenceKey];
152
[email protected]af6a8c92012-12-20 16:41:33153 if (!client_id || ![last_seen_hardware isEqualToString:current_hardware]) {
[email protected]d724b552012-12-13 17:39:47154 client_id = GenerateClientId();
[email protected]e16e8732012-08-07 11:03:11155 [defaults setObject:client_id forKey:kClientIdPreferenceKey];
[email protected]af6a8c92012-12-20 16:41:33156 [defaults setObject:current_hardware forKey:kHardwareTypePreferenceKey];
[email protected]e16e8732012-08-07 11:03:11157 [defaults synchronize];
158 }
159
[email protected]0644db72014-06-05 20:05:43160 return GetSaltedString(base::SysNSStringToUTF8(client_id),
161 salt ? salt : kDefaultSalt);
[email protected]940b67d2014-06-03 14:27:18162}
163
164std::string GetSaltedString(const std::string& in_string,
165 const std::string& salt) {
166 DCHECK(in_string.length());
167 DCHECK(salt.length());
[email protected]0644db72014-06-05 20:05:43168 NSData* hash_data = [base::SysUTF8ToNSString(in_string + salt)
169 dataUsingEncoding:NSUTF8StringEncoding];
[email protected]e16e8732012-08-07 11:03:11170
171 unsigned char hash[CC_SHA256_DIGEST_LENGTH];
172 CC_SHA256([hash_data bytes], [hash_data length], hash);
173 CFUUIDBytes* uuid_bytes = reinterpret_cast<CFUUIDBytes*>(hash);
174
[email protected]3df79f42013-06-24 18:49:05175 base::ScopedCFTypeRef<CFUUIDRef> uuid_object(
176 CFUUIDCreateFromUUIDBytes(kCFAllocatorDefault, *uuid_bytes));
177 base::ScopedCFTypeRef<CFStringRef> device_id(
[email protected]e16e8732012-08-07 11:03:11178 CFUUIDCreateString(kCFAllocatorDefault, uuid_object));
179 return base::SysCFStringRefToUTF8(device_id);
180}
181
182} // namespace device_util
183} // namespace ios