blob: 09252d92bac6ff90d1af3c8fe8d6adce36b57477 [file] [log] [blame]
// Copyright 2017 The Cobalt Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdlib.h>
#include <algorithm>
#include <string>
#include <vector>
#include "starboard/common/device_type.h"
#include "starboard/common/log.h"
#include "starboard/common/string.h"
#include "starboard/configuration_constants.h"
#include "starboard/memory.h"
#include "starboard/shared/uwp/application_uwp.h"
#include "starboard/shared/uwp/keys.h"
#include "starboard/shared/win32/wchar_utils.h"
#include "starboard/system.h"
#include "starboard/xb1/shared/internal_shims.h"
#include "starboard/xb1/system_properties.h"
using starboard::shared::win32::platformStringToString;
using Windows::Security::ExchangeActiveSyncProvisioning::
EasClientDeviceInformation;
using Windows::System::Profile::AnalyticsInfo;
using Windows::System::Profile::AnalyticsVersionInfo;
using Windows::System::UserProfile::AdvertisingManager;
namespace {
#define arraysize(array) (sizeof(array) / sizeof(*array))
struct UwpDevice {
const char* deviceForm;
const char* chipsetModel;
const char* model;
const char* year;
} UwpDevices;
// Array of model name and year for known UWP devices.
struct UwpDevice kDevices[] = {
{"Xbox One", "XboxOne", "XboxOne", "2013"},
{"Xbox One S", "XboxOne", "XboxOne S", "2016"},
{"Xbox One X", "XboxOne", "XboxOne X", "2017"},
{"Xbox One X DevKit", "XboxOne", "XboxOne X", "2017"},
{"Xbox Series X", "XboxScarlett", "XboxScarlett Series X", "2020"},
{"Xbox Series X Devkit", "XboxScarlett", "XboxScarlett Series X", "2020"},
{"Xbox Series S", "XboxScarlett", "XboxScarlett Series S", "2020"},
};
const char kSystemIntegrator[] = "YouTube";
const char kXboxDeviceFormField[] = "Xbox";
// Year for unknown Uwp devices. This assumes that they will be as
// capable as the most recent known device.
const char kUnknownModelYear[] = "2020";
// Chipset for unidentified device forms.
const char kUnknownChipset[] = "UwpUnknown";
bool CopyStringAndTestIfSuccess(char* out_value,
int value_length,
const char* from_value) {
if (strlen(from_value) + 1 > value_length)
return false;
starboard::strlcpy(out_value, from_value, value_length);
return true;
}
bool CopyStringAndTestIfSuccess(char* out_value,
int value_length,
const wchar_t* from_value) {
char* from_value_str = new char[value_length];
int len = wcstombs(from_value_str, from_value, value_length);
bool result = len < 0 ? false
: CopyStringAndTestIfSuccess(out_value, value_length,
from_value_str);
delete from_value_str;
return result;
}
const std::size_t kOsVersionSize = 128;
struct WindowsVersion {
uint16_t major_version;
uint16_t minor_version;
uint16_t build_version;
uint16_t revision;
};
bool GetWindowsVersion(WindowsVersion* version) {
SB_DCHECK(version);
AnalyticsVersionInfo ^ version_info = AnalyticsInfo::VersionInfo;
std::string device_family_version =
platformStringToString(version_info->DeviceFamilyVersion);
if (device_family_version.empty()) {
return false;
}
uint64_t version_info_all =
strtoull(device_family_version.c_str(), nullptr, 10);
if (version_info_all == 0) {
return false;
}
version->major_version = (version_info_all >> 48) & 0xFFFF;
version->minor_version = (version_info_all >> 32) & 0xFFFF;
version->build_version = (version_info_all >> 16) & 0xFFFF;
version->revision = version_info_all & 0xFFFF;
return true;
}
std::string GetDeviceForm() {
Platform::String ^ device_form = AnalyticsInfo::DeviceForm;
return platformStringToString(device_form);
}
bool GetBrandName(char* out_value, int value_length) {
EasClientDeviceInformation ^ current_device_info =
ref new EasClientDeviceInformation();
std::string brand_name =
platformStringToString(current_device_info->SystemManufacturer);
if (brand_name.empty()) {
return false;
}
return CopyStringAndTestIfSuccess(out_value, value_length,
brand_name.c_str());
}
bool GetChipsetModelNumber(char* out_value, int value_length) {
std::string deviceForm = GetDeviceForm();
// If the device form is a known device, return the chipset model from the
// table.
for (size_t i = 0; i < arraysize(kDevices); i++) {
const UwpDevice* device = kDevices + i;
if (deviceForm == device->deviceForm) {
return CopyStringAndTestIfSuccess(out_value, value_length,
device->chipsetModel);
}
}
// The device form is not a known value, return unknown chipset.
return CopyStringAndTestIfSuccess(out_value, value_length, kUnknownChipset);
}
bool GetFirmwareVersion(char* out_value, int value_length) {
WindowsVersion version = {0};
if (!GetWindowsVersion(&version)) {
return false;
}
// The caller expects that the the output string will only be written if
// when true is returned. Therefore we have to buffer the string in case
// there is a false condition, such as small memory input size to hold
// the output parameter.
std::vector<char> out_path_copy(kSbFileMaxPath + 1, 0);
int len = std::min<int>(kSbFileMaxPath, value_length);
int return_value =
snprintf(out_path_copy.data(), len, "%u.%u.%u.%u", version.major_version,
version.minor_version, version.build_version, version.revision);
const bool ok = ((return_value > 0) && (return_value < value_length));
if (ok) {
starboard::strlcpy(out_value, out_path_copy.data(), len);
}
return ok;
}
bool GetFriendlyName(char* out_value, int value_length) {
EasClientDeviceInformation ^ current_device_info =
ref new EasClientDeviceInformation();
std::string friendly_name =
platformStringToString(current_device_info->FriendlyName);
if (friendly_name.empty()) {
return false;
}
return CopyStringAndTestIfSuccess(out_value, value_length,
friendly_name.c_str());
}
bool GetModelYear(char* out_value, int value_length) {
std::string deviceForm = GetDeviceForm();
for (size_t i = 0; i < arraysize(kDevices); i++) {
const UwpDevice* device = kDevices + i;
if (deviceForm == device->deviceForm) {
return CopyStringAndTestIfSuccess(out_value, value_length, device->year);
}
}
return CopyStringAndTestIfSuccess(out_value, value_length, kUnknownModelYear);
}
bool GetModelName(char* out_value, int value_length) {
std::string deviceForm = GetDeviceForm();
for (size_t i = 0; i < arraysize(kDevices); i++) {
const UwpDevice* device = kDevices + i;
if (deviceForm == device->deviceForm) {
return CopyStringAndTestIfSuccess(out_value, value_length, device->model);
}
}
// The device form is not a known value, return the device form verbatim.
return CopyStringAndTestIfSuccess(out_value, value_length,
deviceForm.c_str());
}
bool GetPlatformName(char* out_value, int value_length) {
EasClientDeviceInformation ^ current_device_info =
ref new EasClientDeviceInformation();
std::string operating_system =
platformStringToString(current_device_info->OperatingSystem);
AnalyticsVersionInfo ^ version_info = AnalyticsInfo::VersionInfo;
std::string os_name_and_version =
platformStringToString(current_device_info->OperatingSystem);
if (os_name_and_version.empty()) {
return false;
}
WindowsVersion os_version;
if (!GetWindowsVersion(&os_version)) {
return false;
}
os_name_and_version += " ";
char os_version_buffer[kOsVersionSize];
os_version_buffer[0] = '\0';
int return_value =
snprintf(os_version_buffer, value_length, "%u.%u",
os_version.major_version, os_version.minor_version);
if ((return_value < 0) || (return_value >= value_length)) {
return false;
}
os_name_and_version.append(os_version_buffer);
return CopyStringAndTestIfSuccess(out_value, value_length,
os_name_and_version.c_str());
}
bool GetAppXVersion(char* out_value, int value_length) {
Windows::ApplicationModel::PackageVersion version =
Windows::ApplicationModel::Package::Current->Id->Version;
std::stringstream version_string;
version_string << version.Major << '.' << version.Minor << '.'
<< version.Build << '.' << version.Revision;
return CopyStringAndTestIfSuccess(out_value, value_length,
version_string.str().c_str());
}
std::string GetAdvertisingId() {
Platform::String ^ advertising_id = AdvertisingManager::AdvertisingId;
return platformStringToString(advertising_id);
}
bool GetDeviceType(char* out_value, int value_length) {
AnalyticsVersionInfo ^ version_info = AnalyticsInfo::VersionInfo;
std::string family = starboard::shared::win32::platformStringToString(
version_info->DeviceFamily);
std::string device_type;
if (family.compare("Windows.Desktop") == 0) {
return CopyStringAndTestIfSuccess(out_value, value_length,
starboard::kSystemDeviceTypeDesktopPC);
}
if (family.compare("Windows.Xbox") == 0) {
return CopyStringAndTestIfSuccess(out_value, value_length,
starboard::kSystemDeviceTypeGameConsole);
}
SB_NOTREACHED();
return CopyStringAndTestIfSuccess(out_value, value_length,
starboard::kSystemDeviceTypeUnknown);
}
} // namespace
bool SbSystemGetProperty(SbSystemPropertyId property_id,
char* out_value,
int value_length) {
if (!out_value || !value_length) {
return false;
}
using starboard::shared::uwp::SpeechApiKey;
switch (property_id) {
case kSbSystemPropertyCertificationScope: {
Platform::String ^ scope = starboard::xb1::shared::GetCertScope();
if (scope->IsEmpty()) {
if (kCertificationScope[0] == '\0')
return false;
return CopyStringAndTestIfSuccess(out_value, value_length,
kCertificationScope);
}
bool result =
CopyStringAndTestIfSuccess(out_value, value_length, scope->Data());
return result;
}
case kSbSystemPropertyChipsetModelNumber:
return GetChipsetModelNumber(out_value, value_length);
case kSbSystemPropertyFirmwareVersion:
return GetFirmwareVersion(out_value, value_length);
case kSbSystemPropertyFriendlyName:
return GetFriendlyName(out_value, value_length);
case kSbSystemPropertyBrandName:
return GetBrandName(out_value, value_length);
case kSbSystemPropertyModelName:
return GetModelName(out_value, value_length);
case kSbSystemPropertyModelYear:
return GetModelYear(out_value, value_length);
case kSbSystemPropertySystemIntegratorName:
return CopyStringAndTestIfSuccess(out_value, value_length,
kSystemIntegrator);
case kSbSystemPropertyPlatformName:
return GetPlatformName(out_value, value_length);
case kSbSystemPropertySpeechApiKey:
CopyStringAndTestIfSuccess(out_value, value_length, SpeechApiKey());
return true;
case kSbSystemPropertyUserAgentAuxField:
return GetAppXVersion(out_value, value_length);
#if SB_API_VERSION >= 14
case kSbSystemPropertyAdvertisingId: {
std::string advertising_id = GetAdvertisingId();
return CopyStringAndTestIfSuccess(out_value, value_length,
advertising_id.c_str());
}
case kSbSystemPropertyLimitAdTracking: {
std::string advertising_id = GetAdvertisingId();
// If we get an empty ID, that means the user disabled it.
return CopyStringAndTestIfSuccess(out_value, value_length,
advertising_id.empty() ? "1" : "0");
}
#endif // SB_API_VERSION >= 14
#if SB_API_VERSION >= 15
case kSbSystemPropertyDeviceType:
return GetDeviceType(out_value, value_length);
#endif
default:
SB_DLOG(WARNING) << __FUNCTION__
<< ": Unrecognized property: " << property_id;
break;
}
return false;
}