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