/ src / core / telemetry_session.cpp
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