blob: 96968df1e0bdd11d5db1b99f6ef58e5d7c3bef44 [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];
49 if ([client_id isEqualToString:kZeroUUID])
50 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
71bool IsRunningOnHighRamDevice() {
72 uint64_t memory_size = 0;
73 size_t size = sizeof(memory_size);
74 if (sysctlbyname("hw.memsize", &memory_size, &size, NULL, 0) == 0) {
75 // Anything >= 250M, call high ram.
76 return memory_size >= 250 * 1024 * 1024;
77 }
78 return false;
79}
80
81bool IsSingleCoreDevice() {
82 uint64_t cpu_number = 0;
83 size_t sizes = sizeof(cpu_number);
84 sysctlbyname("hw.physicalcpu", &cpu_number, &sizes, NULL, 0);
85 return cpu_number == 1;
86}
87
88std::string GetMacAddress(const std::string& interface_name) {
89 std::string mac_string;
90 struct ifaddrs* addresses;
91 if (getifaddrs(&addresses) == 0) {
92 for (struct ifaddrs* address = addresses; address;
93 address = address->ifa_next) {
94 if ((address->ifa_addr->sa_family == AF_LINK) &&
95 strcmp(interface_name.c_str(), address->ifa_name) == 0) {
96 const struct sockaddr_dl* found_address_struct =
97 reinterpret_cast<const struct sockaddr_dl*>(address->ifa_addr);
98
99 // |found_address_struct->sdl_data| contains the interface name followed
100 // by the interface address. The address part can be accessed based on
101 // the length of the name, that is, |found_address_struct->sdl_nlen|.
102 const unsigned char* found_address =
103 reinterpret_cast<const unsigned char*>(
104 &found_address_struct->sdl_data[
105 found_address_struct->sdl_nlen]);
106
107 int found_address_length = found_address_struct->sdl_alen;
108 for (int i = 0; i < found_address_length; ++i) {
109 if (i != 0)
110 mac_string.push_back(':');
111 base::StringAppendF(&mac_string, "%02X", found_address[i]);
112 }
113 break;
114 }
115 }
116 freeifaddrs(addresses);
117 }
118 return mac_string;
119}
120
121std::string GetRandomId() {
122 base::mac::ScopedCFTypeRef<CFUUIDRef>
123 uuid_object(CFUUIDCreate(kCFAllocatorDefault));
124 base::mac::ScopedCFTypeRef<CFStringRef> uuid_string(
125 CFUUIDCreateString(kCFAllocatorDefault, uuid_object));
126 return base::SysCFStringRefToUTF8(uuid_string);
127}
128
129std::string GetDeviceIdentifier(const char* salt) {
130 NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
[email protected]af6a8c92012-12-20 16:41:33131
132 NSString* last_seen_hardware =
133 [defaults stringForKey:kHardwareTypePreferenceKey];
134 NSString* current_hardware = base::SysUTF8ToNSString(GetPlatform());
135 if (!last_seen_hardware) {
136 last_seen_hardware = current_hardware;
137 [defaults setObject:current_hardware forKey:kHardwareTypePreferenceKey];
138 [defaults synchronize];
139 }
140
[email protected]e16e8732012-08-07 11:03:11141 NSString* client_id = [defaults stringForKey:kClientIdPreferenceKey];
142
[email protected]af6a8c92012-12-20 16:41:33143 if (!client_id || ![last_seen_hardware isEqualToString:current_hardware]) {
[email protected]d724b552012-12-13 17:39:47144 client_id = GenerateClientId();
[email protected]e16e8732012-08-07 11:03:11145 [defaults setObject:client_id forKey:kClientIdPreferenceKey];
[email protected]af6a8c92012-12-20 16:41:33146 [defaults setObject:current_hardware forKey:kHardwareTypePreferenceKey];
[email protected]e16e8732012-08-07 11:03:11147 [defaults synchronize];
148 }
149
150 NSData* hash_data = [[NSString stringWithFormat:@"%@%s", client_id,
151 salt ? salt : kDefaultSalt] dataUsingEncoding:NSUTF8StringEncoding];
152
153 unsigned char hash[CC_SHA256_DIGEST_LENGTH];
154 CC_SHA256([hash_data bytes], [hash_data length], hash);
155 CFUUIDBytes* uuid_bytes = reinterpret_cast<CFUUIDBytes*>(hash);
156
157 base::mac::ScopedCFTypeRef<CFUUIDRef>
158 uuid_object(CFUUIDCreateFromUUIDBytes(kCFAllocatorDefault, *uuid_bytes));
159 base::mac::ScopedCFTypeRef<CFStringRef> device_id(
160 CFUUIDCreateString(kCFAllocatorDefault, uuid_object));
161 return base::SysCFStringRefToUTF8(device_id);
162}
163
164} // namespace device_util
165} // namespace ios