telemetry_session.cpp 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. // Copyright 2017 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <array>
  5. #include <mbedtls/ctr_drbg.h>
  6. #include <mbedtls/entropy.h>
  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 "core/file_sys/control_metadata.h"
  12. #include "core/file_sys/patch_manager.h"
  13. #include "core/loader/loader.h"
  14. #include "core/settings.h"
  15. #include "core/telemetry_session.h"
  16. #ifdef ENABLE_WEB_SERVICE
  17. #include "web_service/telemetry_json.h"
  18. #include "web_service/verify_login.h"
  19. #endif
  20. namespace Core {
  21. namespace Telemetry = Common::Telemetry;
  22. static u64 GenerateTelemetryId() {
  23. u64 telemetry_id{};
  24. mbedtls_entropy_context entropy;
  25. mbedtls_entropy_init(&entropy);
  26. mbedtls_ctr_drbg_context ctr_drbg;
  27. constexpr std::array<char, 18> personalization{{"yuzu Telemetry ID"}};
  28. mbedtls_ctr_drbg_init(&ctr_drbg);
  29. ASSERT(mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
  30. reinterpret_cast<const unsigned char*>(personalization.data()),
  31. personalization.size()) == 0);
  32. ASSERT(mbedtls_ctr_drbg_random(&ctr_drbg, reinterpret_cast<unsigned char*>(&telemetry_id),
  33. sizeof(u64)) == 0);
  34. mbedtls_ctr_drbg_free(&ctr_drbg);
  35. mbedtls_entropy_free(&entropy);
  36. return telemetry_id;
  37. }
  38. static const char* TranslateRenderer(Settings::RendererBackend backend) {
  39. switch (backend) {
  40. case Settings::RendererBackend::OpenGL:
  41. return "OpenGL";
  42. case Settings::RendererBackend::Vulkan:
  43. return "Vulkan";
  44. }
  45. return "Unknown";
  46. }
  47. static const char* TranslateGPUAccuracyLevel(Settings::GPUAccuracy backend) {
  48. switch (backend) {
  49. case Settings::GPUAccuracy::Normal:
  50. return "Normal";
  51. case Settings::GPUAccuracy::High:
  52. return "High";
  53. case Settings::GPUAccuracy::Extreme:
  54. return "Extreme";
  55. }
  56. return "Unknown";
  57. }
  58. u64 GetTelemetryId() {
  59. u64 telemetry_id{};
  60. const std::string filename{Common::FS::GetUserPath(Common::FS::UserPath::ConfigDir) +
  61. "telemetry_id"};
  62. bool generate_new_id = !Common::FS::Exists(filename);
  63. if (!generate_new_id) {
  64. Common::FS::IOFile file(filename, "rb");
  65. if (!file.IsOpen()) {
  66. LOG_ERROR(Core, "failed to open telemetry_id: {}", filename);
  67. return {};
  68. }
  69. file.ReadBytes(&telemetry_id, sizeof(u64));
  70. if (telemetry_id == 0) {
  71. LOG_ERROR(Frontend, "telemetry_id is 0. Generating a new one.", telemetry_id);
  72. generate_new_id = true;
  73. }
  74. }
  75. if (generate_new_id) {
  76. Common::FS::IOFile file(filename, "wb");
  77. if (!file.IsOpen()) {
  78. LOG_ERROR(Core, "failed to open telemetry_id: {}", filename);
  79. return {};
  80. }
  81. telemetry_id = GenerateTelemetryId();
  82. file.WriteBytes(&telemetry_id, sizeof(u64));
  83. }
  84. return telemetry_id;
  85. }
  86. u64 RegenerateTelemetryId() {
  87. const u64 new_telemetry_id{GenerateTelemetryId()};
  88. const std::string filename{Common::FS::GetUserPath(Common::FS::UserPath::ConfigDir) +
  89. "telemetry_id"};
  90. Common::FS::IOFile file(filename, "wb");
  91. if (!file.IsOpen()) {
  92. LOG_ERROR(Core, "failed to open telemetry_id: {}", filename);
  93. return {};
  94. }
  95. file.WriteBytes(&new_telemetry_id, sizeof(u64));
  96. return new_telemetry_id;
  97. }
  98. bool VerifyLogin(const std::string& username, const std::string& token) {
  99. #ifdef ENABLE_WEB_SERVICE
  100. return WebService::VerifyLogin(Settings::values.web_api_url, username, token);
  101. #else
  102. return false;
  103. #endif
  104. }
  105. TelemetrySession::TelemetrySession() = default;
  106. TelemetrySession::~TelemetrySession() {
  107. // Log one-time session end information
  108. const s64 shutdown_time{std::chrono::duration_cast<std::chrono::milliseconds>(
  109. std::chrono::system_clock::now().time_since_epoch())
  110. .count()};
  111. AddField(Telemetry::FieldType::Session, "Shutdown_Time", shutdown_time);
  112. #ifdef ENABLE_WEB_SERVICE
  113. auto backend = std::make_unique<WebService::TelemetryJson>(
  114. Settings::values.web_api_url, Settings::values.yuzu_username, Settings::values.yuzu_token);
  115. #else
  116. auto backend = std::make_unique<Telemetry::NullVisitor>();
  117. #endif
  118. // Complete the session, submitting to the web service backend if necessary
  119. field_collection.Accept(*backend);
  120. if (Settings::values.enable_telemetry) {
  121. backend->Complete();
  122. }
  123. }
  124. void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader) {
  125. // Log one-time top-level information
  126. AddField(Telemetry::FieldType::None, "TelemetryId", GetTelemetryId());
  127. // Log one-time session start information
  128. const s64 init_time{std::chrono::duration_cast<std::chrono::milliseconds>(
  129. std::chrono::system_clock::now().time_since_epoch())
  130. .count()};
  131. AddField(Telemetry::FieldType::Session, "Init_Time", init_time);
  132. u64 program_id{};
  133. const Loader::ResultStatus res{app_loader.ReadProgramId(program_id)};
  134. if (res == Loader::ResultStatus::Success) {
  135. const std::string formatted_program_id{fmt::format("{:016X}", program_id)};
  136. AddField(Telemetry::FieldType::Session, "ProgramId", formatted_program_id);
  137. std::string name;
  138. app_loader.ReadTitle(name);
  139. if (name.empty()) {
  140. const auto metadata = FileSys::PatchManager(program_id).GetControlMetadata();
  141. if (metadata.first != nullptr) {
  142. name = metadata.first->GetApplicationName();
  143. }
  144. }
  145. if (!name.empty()) {
  146. AddField(Telemetry::FieldType::Session, "ProgramName", name);
  147. }
  148. }
  149. AddField(Telemetry::FieldType::Session, "ProgramFormat",
  150. static_cast<u8>(app_loader.GetFileType()));
  151. // Log application information
  152. Telemetry::AppendBuildInfo(field_collection);
  153. // Log user system information
  154. Telemetry::AppendCPUInfo(field_collection);
  155. Telemetry::AppendOSInfo(field_collection);
  156. // Log user configuration information
  157. constexpr auto field_type = Telemetry::FieldType::UserConfig;
  158. AddField(field_type, "Audio_SinkId", Settings::values.sink_id);
  159. AddField(field_type, "Audio_EnableAudioStretching",
  160. Settings::values.enable_audio_stretching.GetValue());
  161. AddField(field_type, "Core_UseMultiCore", Settings::values.use_multi_core.GetValue());
  162. AddField(field_type, "Renderer_Backend",
  163. TranslateRenderer(Settings::values.renderer_backend.GetValue()));
  164. AddField(field_type, "Renderer_ResolutionFactor",
  165. Settings::values.resolution_factor.GetValue());
  166. AddField(field_type, "Renderer_UseFrameLimit", Settings::values.use_frame_limit.GetValue());
  167. AddField(field_type, "Renderer_FrameLimit", Settings::values.frame_limit.GetValue());
  168. AddField(field_type, "Renderer_UseDiskShaderCache",
  169. Settings::values.use_disk_shader_cache.GetValue());
  170. AddField(field_type, "Renderer_GPUAccuracyLevel",
  171. TranslateGPUAccuracyLevel(Settings::values.gpu_accuracy.GetValue()));
  172. AddField(field_type, "Renderer_UseAsynchronousGpuEmulation",
  173. Settings::values.use_asynchronous_gpu_emulation.GetValue());
  174. AddField(field_type, "Renderer_UseVsync", Settings::values.use_vsync.GetValue());
  175. AddField(field_type, "Renderer_UseAssemblyShaders",
  176. Settings::values.use_assembly_shaders.GetValue());
  177. AddField(field_type, "Renderer_UseAsynchronousShaders",
  178. Settings::values.use_asynchronous_shaders.GetValue());
  179. AddField(field_type, "System_UseDockedMode", Settings::values.use_docked_mode);
  180. }
  181. bool TelemetrySession::SubmitTestcase() {
  182. #ifdef ENABLE_WEB_SERVICE
  183. auto backend = std::make_unique<WebService::TelemetryJson>(
  184. Settings::values.web_api_url, Settings::values.yuzu_username, Settings::values.yuzu_token);
  185. field_collection.Accept(*backend);
  186. return backend->SubmitTestcase();
  187. #else
  188. return false;
  189. #endif
  190. }
  191. } // namespace Core