cast_main_delegate.cc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. // Copyright 2014 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "chromecast/app/cast_main_delegate.h"
  5. #include <algorithm>
  6. #include <string>
  7. #include <tuple>
  8. #include <vector>
  9. #include "base/command_line.h"
  10. #include "base/cpu.h"
  11. #include "base/debug/leak_annotations.h"
  12. #include "base/files/file.h"
  13. #include "base/files/file_enumerator.h"
  14. #include "base/files/file_util.h"
  15. #include "base/logging.h"
  16. #include "base/metrics/field_trial.h"
  17. #include "base/no_destructor.h"
  18. #include "base/path_service.h"
  19. #include "base/posix/global_descriptors.h"
  20. #include "build/build_config.h"
  21. #include "chromecast/base/cast_paths.h"
  22. #include "chromecast/base/chromecast_switches.h"
  23. #include "chromecast/base/process_types.h"
  24. #include "chromecast/browser/cast_content_browser_client.h"
  25. #include "chromecast/browser/cast_feature_list_creator.h"
  26. #include "chromecast/chromecast_buildflags.h"
  27. #include "chromecast/common/cast_resource_delegate.h"
  28. #include "chromecast/common/global_descriptors.h"
  29. #include "chromecast/gpu/cast_content_gpu_client.h"
  30. #include "chromecast/renderer/cast_content_renderer_client.h"
  31. #include "chromecast/utility/cast_content_utility_client.h"
  32. #include "components/crash/core/app/crash_reporter_client.h"
  33. #include "components/crash/core/common/crash_key.h"
  34. #include "content/public/browser/browser_main_runner.h"
  35. #include "content/public/common/content_switches.h"
  36. #include "third_party/abseil-cpp/absl/types/variant.h"
  37. #include "ui/base/resource/resource_bundle.h"
  38. #if BUILDFLAG(IS_ANDROID)
  39. #include "base/android/apk_assets.h"
  40. #include "chromecast/app/android/cast_crash_reporter_client_android.h"
  41. #include "chromecast/app/android/crash_handler.h"
  42. #include "ui/base/resource/resource_bundle_android.h"
  43. #elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
  44. #include "chromecast/app/linux/cast_crash_reporter_client.h"
  45. #include "sandbox/policy/switches.h"
  46. #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
  47. namespace {
  48. #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
  49. chromecast::CastCrashReporterClient* GetCastCrashReporter() {
  50. static base::NoDestructor<chromecast::CastCrashReporterClient>
  51. crash_reporter_client;
  52. return crash_reporter_client.get();
  53. }
  54. #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
  55. #if BUILDFLAG(IS_ANDROID)
  56. const int kMaxCrashFiles = 10;
  57. #endif // BUILDFLAG(IS_ANDROID)
  58. } // namespace
  59. namespace chromecast {
  60. namespace shell {
  61. CastMainDelegate::CastMainDelegate() {}
  62. CastMainDelegate::~CastMainDelegate() {}
  63. absl::optional<int> CastMainDelegate::BasicStartupComplete() {
  64. RegisterPathProvider();
  65. logging::LoggingSettings settings;
  66. settings.logging_dest =
  67. logging::LOG_TO_SYSTEM_DEBUG_LOG | logging::LOG_TO_STDERR;
  68. const base::CommandLine* command_line(base::CommandLine::ForCurrentProcess());
  69. std::string process_type =
  70. command_line->GetSwitchValueASCII(switches::kProcessType);
  71. // Must be created outside of the if scope below to avoid lifetime concerns.
  72. std::string log_path_as_string;
  73. if (command_line->HasSwitch(switches::kLogFile)) {
  74. auto file_path = command_line->GetSwitchValuePath(switches::kLogFile);
  75. DCHECK(!file_path.empty());
  76. log_path_as_string = file_path.value();
  77. settings.logging_dest = logging::LOG_TO_ALL;
  78. settings.log_file_path = log_path_as_string.c_str();
  79. settings.lock_log = logging::DONT_LOCK_LOG_FILE;
  80. // If this is the browser process, delete the old log file. Else, append to
  81. // it.
  82. settings.delete_old = process_type.empty()
  83. ? logging::DELETE_OLD_LOG_FILE
  84. : logging::APPEND_TO_OLD_LOG_FILE;
  85. }
  86. #if BUILDFLAG(IS_ANDROID)
  87. // Browser process logs are recorded for attaching with crash dumps.
  88. if (process_type.empty()) {
  89. base::FilePath log_file;
  90. base::PathService::Get(FILE_CAST_ANDROID_LOG, &log_file);
  91. settings.logging_dest =
  92. logging::LOG_TO_SYSTEM_DEBUG_LOG | logging::LOG_TO_STDERR;
  93. log_path_as_string = log_file.value();
  94. settings.log_file_path = log_path_as_string.c_str();
  95. settings.delete_old = logging::DELETE_OLD_LOG_FILE;
  96. }
  97. #endif // BUILDFLAG(IS_ANDROID)
  98. logging::InitLogging(settings);
  99. #if BUILDFLAG(IS_CAST_DESKTOP_BUILD)
  100. logging::SetLogItems(true, true, true, false);
  101. #else
  102. // Timestamp available through logcat -v time.
  103. logging::SetLogItems(true, true, false, false);
  104. #endif // BUILDFLAG(IS_CAST_DESKTOP_BUILD)
  105. #if BUILDFLAG(IS_ANDROID)
  106. // Only delete the old crash dumps if the current process is the browser
  107. // process. Empty |process_type| signifies browser process.
  108. if (process_type.empty()) {
  109. // Get a listing of all of the crash dump files.
  110. base::FilePath crash_directory;
  111. if (CastCrashReporterClientAndroid::GetCrashReportsLocation(
  112. process_type, &crash_directory)) {
  113. base::FileEnumerator crash_directory_list(crash_directory, false,
  114. base::FileEnumerator::FILES);
  115. std::vector<base::FilePath> crash_files;
  116. for (base::FilePath file = crash_directory_list.Next(); !file.empty();
  117. file = crash_directory_list.Next()) {
  118. crash_files.push_back(file);
  119. }
  120. // Delete crash dumps except for the |kMaxCrashFiles| most recent ones.
  121. if (crash_files.size() > kMaxCrashFiles) {
  122. auto newest_first =
  123. [](const base::FilePath& l, const base::FilePath& r) -> bool {
  124. base::File::Info l_info, r_info;
  125. base::GetFileInfo(l, &l_info);
  126. base::GetFileInfo(r, &r_info);
  127. return l_info.last_modified > r_info.last_modified;
  128. };
  129. std::partial_sort(crash_files.begin(),
  130. crash_files.begin() + kMaxCrashFiles,
  131. crash_files.end(), newest_first);
  132. for (auto file = crash_files.begin() + kMaxCrashFiles;
  133. file != crash_files.end(); ++file) {
  134. base::DeleteFile(*file);
  135. }
  136. }
  137. }
  138. }
  139. #endif // BUILDFLAG(IS_ANDROID)
  140. if (settings.logging_dest & logging::LOG_TO_FILE) {
  141. LOG(INFO) << "Logging to file: " << settings.log_file_path;
  142. }
  143. return absl::nullopt;
  144. }
  145. void CastMainDelegate::PreSandboxStartup() {
  146. #if defined(ARCH_CPU_ARM_FAMILY) && \
  147. (BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS))
  148. // Create an instance of the CPU class to parse /proc/cpuinfo and cache the
  149. // results. This data needs to be cached when file-reading is still allowed,
  150. // since base::CPU expects to be callable later, when file-reading is no
  151. // longer allowed.
  152. base::CPU cpu_info;
  153. #endif
  154. const base::CommandLine* command_line(base::CommandLine::ForCurrentProcess());
  155. std::string process_type =
  156. command_line->GetSwitchValueASCII(switches::kProcessType);
  157. bool enable_crash_reporter = !command_line->HasSwitch(
  158. switches::kDisableCrashReporter);
  159. if (enable_crash_reporter) {
  160. // TODO(crbug.com/1226159): Complete crash reporting integration on Fuchsia.
  161. #if BUILDFLAG(IS_ANDROID)
  162. base::FilePath log_file;
  163. base::PathService::Get(FILE_CAST_ANDROID_LOG, &log_file);
  164. chromecast::CrashHandler::Initialize(process_type, log_file);
  165. #elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
  166. crash_reporter::SetCrashReporterClient(GetCastCrashReporter());
  167. if (process_type != switches::kZygoteProcess) {
  168. CastCrashReporterClient::InitCrashReporter(process_type);
  169. }
  170. #endif // BUILDFLAG(IS_ANDROID)
  171. crash_reporter::InitializeCrashKeys();
  172. }
  173. InitializeResourceBundle();
  174. }
  175. absl::variant<int, content::MainFunctionParams> CastMainDelegate::RunProcess(
  176. const std::string& process_type,
  177. content::MainFunctionParams main_function_params) {
  178. #if BUILDFLAG(IS_ANDROID)
  179. if (!process_type.empty())
  180. return std::move(main_function_params);
  181. // Note: Android must handle running its own browser process.
  182. // See ChromeMainDelegateAndroid::RunProcess.
  183. browser_runner_ = content::BrowserMainRunner::Create();
  184. int exit_code = browser_runner_->Initialize(std::move(main_function_params));
  185. // On Android we do not run BrowserMain(), so the above initialization of a
  186. // BrowserMainRunner is all we want to occur. Preserve any error codes > 0.
  187. if (exit_code > 0)
  188. return exit_code;
  189. return 0;
  190. #else
  191. return std::move(main_function_params);
  192. #endif // BUILDFLAG(IS_ANDROID)
  193. }
  194. #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
  195. void CastMainDelegate::ZygoteForked() {
  196. const base::CommandLine* command_line(base::CommandLine::ForCurrentProcess());
  197. bool enable_crash_reporter = !command_line->HasSwitch(
  198. switches::kDisableCrashReporter);
  199. if (enable_crash_reporter) {
  200. std::string process_type =
  201. command_line->GetSwitchValueASCII(switches::kProcessType);
  202. CastCrashReporterClient::InitCrashReporter(process_type);
  203. }
  204. }
  205. #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
  206. bool CastMainDelegate::ShouldCreateFeatureList(InvokedIn invoked_in) {
  207. return absl::holds_alternative<InvokedInChildProcess>(invoked_in);
  208. }
  209. absl::optional<int> CastMainDelegate::PostEarlyInitialization(
  210. InvokedIn invoked_in) {
  211. if (ShouldCreateFeatureList(invoked_in)) {
  212. // content is handling the feature list.
  213. return absl::nullopt;
  214. }
  215. DCHECK(cast_feature_list_creator_);
  216. #if !BUILDFLAG(IS_ANDROID)
  217. // PrefService requires the home directory to be created before the pref store
  218. // can be initialized properly.
  219. base::FilePath home_dir;
  220. CHECK(base::PathService::Get(DIR_CAST_HOME, &home_dir));
  221. CHECK(base::CreateDirectory(home_dir));
  222. #endif // !BUILDFLAG(IS_ANDROID)
  223. // TODO(crbug/1249485): If we're able to create the MetricsStateManager
  224. // earlier, clean up the below if and else blocks and call
  225. // MetricsStateManager::InstantiateFieldTrialList().
  226. //
  227. // The FieldTrialList is a dependency of the feature list. In tests, it is
  228. // constructed as part of the test suite.
  229. const auto* invoked_in_browser =
  230. absl::get_if<InvokedInBrowserProcess>(&invoked_in);
  231. if (invoked_in_browser && invoked_in_browser->is_running_test) {
  232. DCHECK(base::FieldTrialList::GetInstance());
  233. } else {
  234. // This is intentionally leaked since it needs to live for the duration of
  235. // the browser process and there's no benefit to cleaning it up at exit.
  236. base::FieldTrialList* leaked_field_trial_list =
  237. new base::FieldTrialList(nullptr);
  238. ANNOTATE_LEAKING_OBJECT_PTR(leaked_field_trial_list);
  239. std::ignore = leaked_field_trial_list;
  240. }
  241. // Initialize the base::FeatureList and the PrefService (which it depends on),
  242. // so objects initialized after this point can use features from
  243. // base::FeatureList.
  244. const base::CommandLine* command_line =
  245. base::CommandLine::ForCurrentProcess();
  246. const bool use_browser_config =
  247. command_line->HasSwitch(switches::kUseCastBrowserPrefConfig);
  248. ProcessType process_type = use_browser_config ? ProcessType::kCastBrowser
  249. : ProcessType::kCastService;
  250. cast_feature_list_creator_->CreatePrefServiceAndFeatureList(process_type);
  251. return absl::nullopt;
  252. }
  253. void CastMainDelegate::InitializeResourceBundle() {
  254. base::FilePath pak_file;
  255. CHECK(base::PathService::Get(FILE_CAST_PAK, &pak_file));
  256. #if BUILDFLAG(IS_ANDROID)
  257. // On Android, the renderer runs with a different UID and can never access
  258. // the file system. Use the file descriptor passed in at launch time.
  259. auto* global_descriptors = base::GlobalDescriptors::GetInstance();
  260. int pak_fd = global_descriptors->MaybeGet(kAndroidPakDescriptor);
  261. base::MemoryMappedFile::Region pak_region;
  262. if (pak_fd >= 0) {
  263. pak_region = global_descriptors->GetRegion(kAndroidPakDescriptor);
  264. base::File android_pak_file(pak_fd);
  265. ui::ResourceBundle::InitSharedInstanceWithPakFileRegion(
  266. android_pak_file.Duplicate(), pak_region);
  267. ui::ResourceBundle::GetSharedInstance().AddDataPackFromFileRegion(
  268. std::move(android_pak_file), pak_region, ui::k100Percent);
  269. return;
  270. } else {
  271. pak_fd = base::android::OpenApkAsset("assets/cast_shell.pak", &pak_region);
  272. // Loaded from disk for browsertests.
  273. if (pak_fd < 0) {
  274. int flags = base::File::FLAG_OPEN | base::File::FLAG_READ;
  275. pak_fd = base::File(pak_file, flags).TakePlatformFile();
  276. pak_region = base::MemoryMappedFile::Region::kWholeFile;
  277. }
  278. DCHECK_GE(pak_fd, 0);
  279. global_descriptors->Set(kAndroidPakDescriptor, pak_fd, pak_region);
  280. }
  281. ui::SetLocalePaksStoredInApk(true);
  282. #endif // BUILDFLAG(IS_ANDROID)
  283. resource_delegate_.reset(new CastResourceDelegate());
  284. // TODO(gunsch): Use LOAD_COMMON_RESOURCES once ResourceBundle no longer
  285. // hardcodes resource file names.
  286. ui::ResourceBundle::InitSharedInstanceWithLocale(
  287. "en-US", resource_delegate_.get(),
  288. ui::ResourceBundle::DO_NOT_LOAD_COMMON_RESOURCES);
  289. #if BUILDFLAG(IS_ANDROID)
  290. ui::ResourceBundle::GetSharedInstance().AddDataPackFromFileRegion(
  291. base::File(pak_fd), pak_region, ui::kScaleFactorNone);
  292. #else
  293. ui::ResourceBundle::GetSharedInstance().AddDataPackFromPath(
  294. pak_file, ui::kScaleFactorNone);
  295. #endif // BUILDFLAG(IS_ANDROID)
  296. }
  297. content::ContentClient* CastMainDelegate::CreateContentClient() {
  298. return &content_client_;
  299. }
  300. content::ContentBrowserClient* CastMainDelegate::CreateContentBrowserClient() {
  301. DCHECK(!cast_feature_list_creator_);
  302. cast_feature_list_creator_ = std::make_unique<CastFeatureListCreator>();
  303. browser_client_ =
  304. CastContentBrowserClient::Create(cast_feature_list_creator_.get());
  305. return browser_client_.get();
  306. }
  307. content::ContentGpuClient* CastMainDelegate::CreateContentGpuClient() {
  308. gpu_client_ = CastContentGpuClient::Create();
  309. return gpu_client_.get();
  310. }
  311. content::ContentRendererClient*
  312. CastMainDelegate::CreateContentRendererClient() {
  313. renderer_client_ = CastContentRendererClient::Create();
  314. return renderer_client_.get();
  315. }
  316. content::ContentUtilityClient* CastMainDelegate::CreateContentUtilityClient() {
  317. utility_client_ = CastContentUtilityClient::Create();
  318. return utility_client_.get();
  319. }
  320. } // namespace shell
  321. } // namespace chromecast