telemetry_session.cpp
1 // Copyright 2017 Citra Emulator Project 2 // Licensed under GPLv2 or any later version 3 // Refer to the license.txt file included. 4 5 #include <cryptopp/osrng.h> 6 7 #include "common/assert.h" 8 #include "common/common_types.h" 9 #include "common/file_util.h" 10 #include "common/logging/log.h" 11 #include "common/scm_rev.h" 12 #include "common/settings.h" 13 #include "core/core.h" 14 #include "core/loader/loader.h" 15 #include "core/telemetry_session.h" 16 #include "network/network_settings.h" 17 18 #ifdef ENABLE_WEB_SERVICE 19 #include "web_service/telemetry_json.h" 20 #include "web_service/verify_login.h" 21 #endif 22 23 namespace Core { 24 25 namespace Telemetry = Common::Telemetry; 26 27 static u64 GenerateTelemetryId() { 28 u64 telemetry_id{}; 29 CryptoPP::AutoSeededRandomPool rng; 30 rng.GenerateBlock(reinterpret_cast<CryptoPP::byte*>(&telemetry_id), sizeof(u64)); 31 return telemetry_id; 32 } 33 34 u64 GetTelemetryId() { 35 u64 telemetry_id{}; 36 const std::string filename{FileUtil::GetUserPath(FileUtil::UserPath::ConfigDir) + 37 "telemetry_id"}; 38 39 if (FileUtil::Exists(filename)) { 40 FileUtil::IOFile file(filename, "rb"); 41 if (!file.IsOpen()) { 42 LOG_ERROR(Core, "failed to open telemetry_id: {}", filename); 43 return {}; 44 } 45 file.ReadBytes(&telemetry_id, sizeof(u64)); 46 } else { 47 FileUtil::IOFile file(filename, "wb"); 48 if (!file.IsOpen()) { 49 LOG_ERROR(Core, "failed to open telemetry_id: {}", filename); 50 return {}; 51 } 52 telemetry_id = GenerateTelemetryId(); 53 file.WriteBytes(&telemetry_id, sizeof(u64)); 54 } 55 56 return telemetry_id; 57 } 58 59 u64 RegenerateTelemetryId() { 60 const u64 new_telemetry_id{GenerateTelemetryId()}; 61 const std::string filename{FileUtil::GetUserPath(FileUtil::UserPath::ConfigDir) + 62 "telemetry_id"}; 63 64 FileUtil::IOFile file(filename, "wb"); 65 if (!file.IsOpen()) { 66 LOG_ERROR(Core, "failed to open telemetry_id: {}", filename); 67 return {}; 68 } 69 file.WriteBytes(&new_telemetry_id, sizeof(u64)); 70 return new_telemetry_id; 71 } 72 73 bool VerifyLogin(const std::string& username, const std::string& token) { 74 #ifdef ENABLE_WEB_SERVICE 75 return WebService::VerifyLogin(NetSettings::values.web_api_url, username, token); 76 #else 77 return false; 78 #endif 79 } 80 81 TelemetrySession::TelemetrySession() = default; 82 83 TelemetrySession::~TelemetrySession() { 84 // Log one-time session end information 85 const s64 shutdown_time{std::chrono::duration_cast<std::chrono::milliseconds>( 86 std::chrono::system_clock::now().time_since_epoch()) 87 .count()}; 88 AddField(Telemetry::FieldType::Session, "Shutdown_Time", shutdown_time); 89 90 #ifdef ENABLE_WEB_SERVICE 91 auto backend = std::make_unique<WebService::TelemetryJson>(NetSettings::values.web_api_url, 92 NetSettings::values.citra_username, 93 NetSettings::values.citra_token); 94 #else 95 auto backend = std::make_unique<Telemetry::NullVisitor>(); 96 #endif 97 98 // Complete the session, submitting to the web service backend if necessary 99 field_collection.Accept(*backend); 100 if (NetSettings::values.enable_telemetry) { 101 backend->Complete(); 102 } 103 } 104 105 void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader) { 106 // Log one-time top-level information 107 AddField(Telemetry::FieldType::None, "TelemetryId", GetTelemetryId()); 108 109 // Log one-time session start information 110 const s64 init_time{std::chrono::duration_cast<std::chrono::milliseconds>( 111 std::chrono::system_clock::now().time_since_epoch()) 112 .count()}; 113 AddField(Telemetry::FieldType::Session, "Init_Time", init_time); 114 std::string program_name; 115 const Loader::ResultStatus res{app_loader.ReadTitle(program_name)}; 116 if (res == Loader::ResultStatus::Success) { 117 AddField(Telemetry::FieldType::Session, "ProgramName", program_name); 118 } 119 120 // Log application information 121 Telemetry::AppendBuildInfo(field_collection); 122 123 // Log user system information 124 Telemetry::AppendCPUInfo(field_collection); 125 Telemetry::AppendOSInfo(field_collection); 126 127 // Log user configuration information 128 AddField(Telemetry::FieldType::UserConfig, "Audio_SinkId", 129 static_cast<int>(Settings::values.output_type.GetValue())); 130 AddField(Telemetry::FieldType::UserConfig, "Audio_EnableAudioStretching", 131 Settings::values.enable_audio_stretching.GetValue()); 132 AddField(Telemetry::FieldType::UserConfig, "Core_UseCpuJit", 133 Settings::values.use_cpu_jit.GetValue()); 134 AddField(Telemetry::FieldType::UserConfig, "Renderer_ResolutionFactor", 135 Settings::values.resolution_factor.GetValue()); 136 AddField(Telemetry::FieldType::UserConfig, "Renderer_FrameLimit", 137 Settings::values.frame_limit.GetValue()); 138 AddField(Telemetry::FieldType::UserConfig, "Renderer_Backend", 139 static_cast<int>(Settings::values.graphics_api.GetValue())); 140 AddField(Telemetry::FieldType::UserConfig, "Renderer_UseHwShader", 141 Settings::values.use_hw_shader.GetValue()); 142 AddField(Telemetry::FieldType::UserConfig, "Renderer_ShadersAccurateMul", 143 Settings::values.shaders_accurate_mul.GetValue()); 144 AddField(Telemetry::FieldType::UserConfig, "Renderer_UseShaderJit", 145 Settings::values.use_shader_jit.GetValue()); 146 AddField(Telemetry::FieldType::UserConfig, "Renderer_UseVsync", 147 Settings::values.use_vsync_new.GetValue()); 148 AddField(Telemetry::FieldType::UserConfig, "Renderer_FilterMode", 149 Settings::values.filter_mode.GetValue()); 150 AddField(Telemetry::FieldType::UserConfig, "Renderer_Render3d", 151 static_cast<int>(Settings::values.render_3d.GetValue())); 152 AddField(Telemetry::FieldType::UserConfig, "Renderer_Factor3d", 153 Settings::values.factor_3d.GetValue()); 154 AddField(Telemetry::FieldType::UserConfig, "Renderer_MonoRenderOption", 155 static_cast<int>(Settings::values.mono_render_option.GetValue())); 156 AddField(Telemetry::FieldType::UserConfig, "System_IsNew3ds", 157 Settings::values.is_new_3ds.GetValue()); 158 AddField(Telemetry::FieldType::UserConfig, "System_LLEApplets", 159 Settings::values.lle_applets.GetValue()); 160 AddField(Telemetry::FieldType::UserConfig, "System_RegionValue", 161 Settings::values.region_value.GetValue()); 162 } 163 164 bool TelemetrySession::SubmitTestcase() { 165 #ifdef ENABLE_WEB_SERVICE 166 auto backend = std::make_unique<WebService::TelemetryJson>(NetSettings::values.web_api_url, 167 NetSettings::values.citra_username, 168 NetSettings::values.citra_token); 169 field_collection.Accept(*backend); 170 return backend->SubmitTestcase(); 171 #else 172 return false; 173 #endif 174 } 175 176 } // namespace Core