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