content_main_delegate_impl.cc 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442
  1. // Copyright 2019 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 "weblayer/app/content_main_delegate_impl.h"
  5. #include <iostream>
  6. #include <tuple>
  7. #include "base/base_switches.h"
  8. #include "base/command_line.h"
  9. #include "base/containers/contains.h"
  10. #include "base/containers/flat_set.h"
  11. #include "base/cpu.h"
  12. #include "base/files/file_util.h"
  13. #include "base/lazy_instance.h"
  14. #include "base/logging.h"
  15. #include "base/path_service.h"
  16. #include "base/strings/string_split.h"
  17. #include "build/build_config.h"
  18. #include "build/chromeos_buildflags.h"
  19. #include "components/content_capture/common/content_capture_features.h"
  20. #include "components/startup_metric_utils/browser/startup_metric_utils.h"
  21. #include "components/translate/core/common/translate_util.h"
  22. #include "components/variations/variations_ids_provider.h"
  23. #include "content/public/browser/browser_main_runner.h"
  24. #include "content/public/common/content_features.h"
  25. #include "content/public/common/content_switches.h"
  26. #include "content/public/common/main_function_params.h"
  27. #include "content/public/common/url_constants.h"
  28. #include "media/base/media_switches.h"
  29. #include "services/network/public/cpp/features.h"
  30. #include "third_party/abseil-cpp/absl/types/variant.h"
  31. #include "third_party/blink/public/common/features.h"
  32. #include "third_party/blink/public/platform/web_runtime_features.h"
  33. #include "ui/base/resource/resource_bundle.h"
  34. #include "ui/base/ui_base_paths.h"
  35. #include "weblayer/browser/background_fetch/background_fetch_delegate_factory.h"
  36. #include "weblayer/browser/content_browser_client_impl.h"
  37. #include "weblayer/common/content_client_impl.h"
  38. #include "weblayer/common/weblayer_paths.h"
  39. #include "weblayer/public/common/switches.h"
  40. #include "weblayer/renderer/content_renderer_client_impl.h"
  41. #include "weblayer/utility/content_utility_client_impl.h"
  42. #if BUILDFLAG(IS_ANDROID)
  43. #include "base/android/apk_assets.h"
  44. #include "base/android/build_info.h"
  45. #include "base/android/bundle_utils.h"
  46. #include "base/android/java_exception_reporter.h"
  47. #include "base/android/locale_utils.h"
  48. #include "base/i18n/rtl.h"
  49. #include "base/posix/global_descriptors.h"
  50. #include "components/autofill/core/common/autofill_features.h"
  51. #include "components/viz/common/features.h"
  52. #include "content/public/browser/android/compositor.h"
  53. #include "ui/base/resource/resource_bundle_android.h"
  54. #include "ui/base/ui_base_switches.h"
  55. #include "weblayer/browser/android/application_info_helper.h"
  56. #include "weblayer/browser/android/exception_filter.h"
  57. #include "weblayer/browser/android_descriptors.h"
  58. #include "weblayer/common/crash_reporter/crash_keys.h"
  59. #include "weblayer/common/crash_reporter/crash_reporter_client.h"
  60. #endif
  61. #if BUILDFLAG(IS_WIN)
  62. #include <windows.h>
  63. #include <initguid.h>
  64. #include "base/logging_win.h"
  65. #endif
  66. namespace weblayer {
  67. namespace {
  68. void InitLogging(MainParams* params) {
  69. if (params->log_filename.empty())
  70. return;
  71. logging::LoggingSettings settings;
  72. settings.logging_dest = logging::LOG_TO_ALL;
  73. settings.log_file_path = params->log_filename.value().c_str();
  74. settings.delete_old = logging::DELETE_OLD_LOG_FILE;
  75. logging::InitLogging(settings);
  76. logging::SetLogItems(true /* Process ID */, true /* Thread ID */,
  77. true /* Timestamp */, false /* Tick count */);
  78. }
  79. // Enables each feature in |features_to_enable| unless it is already set in the
  80. // command line, and similarly disables each feature in |features_to_disable|
  81. // unless it is already set in the command line.
  82. void ConfigureFeaturesIfNotSet(
  83. const std::vector<base::Feature>& features_to_enable,
  84. const std::vector<base::Feature>& features_to_disable) {
  85. auto* cl = base::CommandLine::ForCurrentProcess();
  86. std::vector<std::string> enabled_features;
  87. base::flat_set<std::string> feature_names_enabled_via_command_line;
  88. std::string enabled_features_str =
  89. cl->GetSwitchValueASCII(::switches::kEnableFeatures);
  90. for (const auto& f :
  91. base::FeatureList::SplitFeatureListString(enabled_features_str)) {
  92. enabled_features.emplace_back(f);
  93. // "<" is used as separator for field trial/groups.
  94. std::vector<base::StringPiece> parts = base::SplitStringPiece(
  95. f, "<", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
  96. // Split with supplied params should always return at least one entry.
  97. DCHECK(!parts.empty());
  98. if (parts[0].length() > 0)
  99. feature_names_enabled_via_command_line.insert(std::string(parts[0]));
  100. }
  101. std::vector<std::string> disabled_features;
  102. std::string disabled_features_str =
  103. cl->GetSwitchValueASCII(::switches::kDisableFeatures);
  104. for (const auto& f :
  105. base::FeatureList::SplitFeatureListString(disabled_features_str)) {
  106. disabled_features.emplace_back(f);
  107. }
  108. for (const auto& feature : features_to_enable) {
  109. if (!base::Contains(disabled_features, feature.name) &&
  110. !base::Contains(feature_names_enabled_via_command_line, feature.name)) {
  111. enabled_features.push_back(feature.name);
  112. }
  113. }
  114. cl->AppendSwitchASCII(::switches::kEnableFeatures,
  115. base::JoinString(enabled_features, ","));
  116. for (const auto& feature : features_to_disable) {
  117. if (!base::Contains(disabled_features, feature.name) &&
  118. !base::Contains(feature_names_enabled_via_command_line, feature.name)) {
  119. disabled_features.push_back(feature.name);
  120. }
  121. }
  122. cl->AppendSwitchASCII(::switches::kDisableFeatures,
  123. base::JoinString(disabled_features, ","));
  124. }
  125. } // namespace
  126. ContentMainDelegateImpl::ContentMainDelegateImpl(MainParams params)
  127. : params_(std::move(params)) {
  128. #if !BUILDFLAG(IS_ANDROID)
  129. // On non-Android, the application start time is recorded in this constructor,
  130. // which runs early during application lifetime. On Android, the application
  131. // start time is sampled when the Java code is entered, and it is retrieved
  132. // from C++ after initializing the JNI (see
  133. // BrowserMainPartsImpl::PreMainMessageLoopRun()).
  134. startup_metric_utils::RecordApplicationStartTime(base::TimeTicks::Now());
  135. #endif
  136. }
  137. ContentMainDelegateImpl::~ContentMainDelegateImpl() = default;
  138. absl::optional<int> ContentMainDelegateImpl::BasicStartupComplete() {
  139. // Disable features which are not currently supported in WebLayer. This allows
  140. // sites to do feature detection, and prevents crashes in some not fully
  141. // implemented features.
  142. base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
  143. // TODO(crbug.com/1025610): make notifications work with WebLayer.
  144. // This also turns off Push messaging.
  145. cl->AppendSwitch(::switches::kDisableNotifications);
  146. std::vector<base::Feature> enabled_features = {
  147. #if BUILDFLAG(IS_ANDROID)
  148. // Overlay promotion requires some guarantees we don't have on WebLayer
  149. // (e.g. ensuring fullscreen, no movement of the parent view). Given that
  150. // we're unsure about the benefits when used embedded in a parent app, we
  151. // will only promote to overlays if needed for secure videos.
  152. media::kUseAndroidOverlayForSecureOnly,
  153. #endif
  154. };
  155. std::vector<base::Feature> disabled_features = {
  156. // TODO(crbug.com/1313771): Support Digital Goods API.
  157. ::features::kDigitalGoodsApi,
  158. // TODO(crbug.com/1091212): make Notification triggers work with
  159. // WebLayer.
  160. ::features::kNotificationTriggers,
  161. // TODO(crbug.com/1091211): Support PeriodicBackgroundSync on WebLayer.
  162. ::features::kPeriodicBackgroundSync,
  163. // TODO(crbug.com/1174856): Support Portals.
  164. blink::features::kPortals,
  165. // TODO(crbug.com/1144912): Support BackForwardCache on WebLayer.
  166. ::features::kBackForwardCache,
  167. // TODO(crbug.com/1247836): Enable TFLite/Optimization Guide on WebLayer.
  168. translate::kTFLiteLanguageDetectionEnabled,
  169. #if BUILDFLAG(IS_ANDROID)
  170. // TODO(crbug.com/1131016): Support Picture in Picture API on WebLayer.
  171. media::kPictureInPictureAPI,
  172. ::features::kDisableDeJelly,
  173. ::features::kDynamicColorGamut,
  174. #else
  175. // WebOTP is supported only on Android in WebLayer.
  176. ::features::kWebOTP,
  177. #endif
  178. };
  179. #if BUILDFLAG(IS_ANDROID)
  180. if (base::android::BuildInfo::GetInstance()->sdk_int() >=
  181. base::android::SDK_VERSION_OREO) {
  182. enabled_features.push_back(
  183. autofill::features::kAutofillExtractAllDatalists);
  184. enabled_features.push_back(
  185. autofill::features::kAutofillSkipComparingInferredLabels);
  186. }
  187. if (GetApplicationMetadataAsBoolean(
  188. "org.chromium.weblayer.ENABLE_LOGGING_OF_JS_CONSOLE_MESSAGES",
  189. /*default_value=*/false)) {
  190. enabled_features.push_back(features::kLogJsConsoleMessages);
  191. }
  192. #endif
  193. ConfigureFeaturesIfNotSet(enabled_features, disabled_features);
  194. // TODO(crbug.com/1097105): Support Web GPU on WebLayer.
  195. blink::WebRuntimeFeatures::EnableWebGPU(false);
  196. #if BUILDFLAG(IS_ANDROID)
  197. content::Compositor::Initialize();
  198. #endif
  199. InitLogging(&params_);
  200. RegisterPathProvider();
  201. return absl::nullopt;
  202. }
  203. bool ContentMainDelegateImpl::ShouldCreateFeatureList(InvokedIn invoked_in) {
  204. #if BUILDFLAG(IS_ANDROID)
  205. // On android WebLayer is in charge of creating its own FeatureList in the
  206. // browser process.
  207. return absl::holds_alternative<InvokedInChildProcess>(invoked_in);
  208. #else
  209. // TODO(weblayer-dev): Support feature lists on desktop.
  210. return true;
  211. #endif
  212. }
  213. variations::VariationsIdsProvider*
  214. ContentMainDelegateImpl::CreateVariationsIdsProvider() {
  215. // As the embedder supplies the set of ids, the signed-in state does not make
  216. // sense and is ignored.
  217. return variations::VariationsIdsProvider::Create(
  218. variations::VariationsIdsProvider::Mode::kIgnoreSignedInState);
  219. }
  220. void ContentMainDelegateImpl::PreSandboxStartup() {
  221. // TODO(crbug.com/1052397): Revisit once build flag switch of lacros-chrome is
  222. // complete.
  223. #if defined(ARCH_CPU_ARM_FAMILY) && \
  224. (BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || \
  225. BUILDFLAG(IS_CHROMEOS_LACROS))
  226. // Create an instance of the CPU class to parse /proc/cpuinfo and cache
  227. // cpu_brand info.
  228. base::CPU cpu_info;
  229. #endif
  230. const base::CommandLine& command_line =
  231. *base::CommandLine::ForCurrentProcess();
  232. const bool is_browser_process =
  233. command_line.GetSwitchValueASCII(::switches::kProcessType).empty();
  234. if (is_browser_process &&
  235. command_line.HasSwitch(switches::kWebLayerUserDataDir)) {
  236. base::FilePath path =
  237. command_line.GetSwitchValuePath(switches::kWebLayerUserDataDir);
  238. if (base::DirectoryExists(path) || base::CreateDirectory(path)) {
  239. // Profile needs an absolute path, which we would normally get via
  240. // PathService. In this case, manually ensure the path is absolute.
  241. if (!path.IsAbsolute())
  242. path = base::MakeAbsoluteFilePath(path);
  243. } else {
  244. LOG(ERROR) << "Unable to create data-path directory: " << path.value();
  245. }
  246. CHECK(base::PathService::OverrideAndCreateIfNeeded(
  247. DIR_USER_DATA, path, true /* is_absolute */, false /* create */));
  248. }
  249. InitializeResourceBundle();
  250. #if BUILDFLAG(IS_ANDROID)
  251. EnableCrashReporter(
  252. command_line.GetSwitchValueASCII(::switches::kProcessType));
  253. if (is_browser_process) {
  254. base::android::SetJavaExceptionFilter(
  255. base::BindRepeating(&WebLayerJavaExceptionFilter));
  256. }
  257. SetWebLayerCrashKeys();
  258. #endif
  259. }
  260. absl::optional<int> ContentMainDelegateImpl::PostEarlyInitialization(
  261. InvokedIn invoked_in) {
  262. if (absl::holds_alternative<InvokedInBrowserProcess>(invoked_in))
  263. browser_client_->CreateFeatureListAndFieldTrials();
  264. return absl::nullopt;
  265. }
  266. absl::variant<int, content::MainFunctionParams>
  267. ContentMainDelegateImpl::RunProcess(
  268. const std::string& process_type,
  269. content::MainFunctionParams main_function_params) {
  270. // For non-browser process, return and have the caller run the main loop.
  271. if (!process_type.empty())
  272. return std::move(main_function_params);
  273. #if !BUILDFLAG(IS_ANDROID)
  274. // On non-Android, we can return |main_function_params| back and have the
  275. // caller run BrowserMain() normally.
  276. return std::move(main_function_params);
  277. #else
  278. // On Android, we defer to the system message loop when the stack unwinds.
  279. // So here we only create (and leak) a BrowserMainRunner. The shutdown
  280. // of BrowserMainRunner doesn't happen in Chrome Android and doesn't work
  281. // properly on Android at all.
  282. auto main_runner = content::BrowserMainRunner::Create();
  283. // In browser tests, the |main_function_params| contains a |ui_task| which
  284. // will execute the testing. The task will be executed synchronously inside
  285. // Initialize() so we don't depend on the BrowserMainRunner being Run().
  286. int initialize_exit_code =
  287. main_runner->Initialize(std::move(main_function_params));
  288. DCHECK_LT(initialize_exit_code, 0)
  289. << "BrowserMainRunner::Initialize failed in MainDelegate";
  290. std::ignore = main_runner.release();
  291. // Return 0 as BrowserMain() should not be called after this, bounce up to
  292. // the system message loop for ContentShell, and we're already done thanks
  293. // to the |ui_task| for browser tests.
  294. return 0;
  295. #endif
  296. }
  297. void ContentMainDelegateImpl::InitializeResourceBundle() {
  298. #if BUILDFLAG(IS_ANDROID)
  299. const base::CommandLine& command_line =
  300. *base::CommandLine::ForCurrentProcess();
  301. bool is_browser_process =
  302. command_line.GetSwitchValueASCII(::switches::kProcessType).empty();
  303. if (is_browser_process) {
  304. // If we're not being loaded from a bundle, locales will be loaded from the
  305. // webview stored-locales directory. Otherwise, we are in Monochrome, and
  306. // we load both chrome and webview's locale assets.
  307. if (base::android::BundleUtils::IsBundle())
  308. ui::SetLoadSecondaryLocalePaks(true);
  309. else
  310. ui::SetLocalePaksStoredInApk(true);
  311. // Passing an empty |pref_locale| yields the system default locale.
  312. std::string locale = ui::ResourceBundle::InitSharedInstanceWithLocale(
  313. {} /*pref_locale*/, nullptr, ui::ResourceBundle::LOAD_COMMON_RESOURCES);
  314. if (locale.empty()) {
  315. LOG(WARNING) << "Failed to load locale .pak from apk.";
  316. }
  317. // Try to directly mmap the resources.pak from the apk. Fall back to load
  318. // from file, using PATH_SERVICE, otherwise.
  319. base::FilePath pak_file_path;
  320. base::PathService::Get(ui::DIR_RESOURCE_PAKS_ANDROID, &pak_file_path);
  321. pak_file_path = pak_file_path.AppendASCII("resources.pak");
  322. ui::LoadMainAndroidPackFile("assets/resources.pak", pak_file_path);
  323. // The English-only workaround is not needed for bundles, since bundles will
  324. // contain assets for all locales.
  325. if (!base::android::BundleUtils::IsBundle()) {
  326. constexpr char kWebLayerLocalePath[] =
  327. "assets/stored-locales/weblayer/en-US.pak";
  328. base::MemoryMappedFile::Region region;
  329. int fd = base::android::OpenApkAsset(kWebLayerLocalePath, &region);
  330. CHECK_GE(fd, 0) << "Could not find " << kWebLayerLocalePath << " in APK.";
  331. ui::ResourceBundle::GetSharedInstance()
  332. .LoadSecondaryLocaleDataWithPakFileRegion(base::File(fd), region);
  333. base::GlobalDescriptors::GetInstance()->Set(
  334. kWebLayerSecondaryLocalePakDescriptor, fd, region);
  335. }
  336. } else {
  337. base::i18n::SetICUDefaultLocale(
  338. command_line.GetSwitchValueASCII(::switches::kLang));
  339. auto* global_descriptors = base::GlobalDescriptors::GetInstance();
  340. int pak_fd = global_descriptors->Get(kWebLayerLocalePakDescriptor);
  341. base::MemoryMappedFile::Region pak_region =
  342. global_descriptors->GetRegion(kWebLayerLocalePakDescriptor);
  343. ui::ResourceBundle::InitSharedInstanceWithPakFileRegion(base::File(pak_fd),
  344. pak_region);
  345. pak_fd = global_descriptors->Get(kWebLayerSecondaryLocalePakDescriptor);
  346. pak_region =
  347. global_descriptors->GetRegion(kWebLayerSecondaryLocalePakDescriptor);
  348. ui::ResourceBundle::GetSharedInstance()
  349. .LoadSecondaryLocaleDataWithPakFileRegion(base::File(pak_fd),
  350. pak_region);
  351. std::vector<std::pair<int, ui::ResourceScaleFactor>> extra_paks = {
  352. {kWebLayerMainPakDescriptor, ui::kScaleFactorNone},
  353. {kWebLayer100PercentPakDescriptor, ui::k100Percent}};
  354. for (const auto& pak_info : extra_paks) {
  355. pak_fd = global_descriptors->Get(pak_info.first);
  356. pak_region = global_descriptors->GetRegion(pak_info.first);
  357. ui::ResourceBundle::GetSharedInstance().AddDataPackFromFileRegion(
  358. base::File(pak_fd), pak_region, pak_info.second);
  359. }
  360. }
  361. #else
  362. base::FilePath pak_file;
  363. bool r = base::PathService::Get(base::DIR_ASSETS, &pak_file);
  364. DCHECK(r);
  365. pak_file = pak_file.AppendASCII(params_.pak_name);
  366. ui::ResourceBundle::InitSharedInstanceWithPakPath(pak_file);
  367. #endif
  368. }
  369. content::ContentClient* ContentMainDelegateImpl::CreateContentClient() {
  370. content_client_ = std::make_unique<ContentClientImpl>();
  371. return content_client_.get();
  372. }
  373. content::ContentBrowserClient*
  374. ContentMainDelegateImpl::CreateContentBrowserClient() {
  375. browser_client_ = std::make_unique<ContentBrowserClientImpl>(&params_);
  376. return browser_client_.get();
  377. }
  378. content::ContentRendererClient*
  379. ContentMainDelegateImpl::CreateContentRendererClient() {
  380. renderer_client_ = std::make_unique<ContentRendererClientImpl>();
  381. return renderer_client_.get();
  382. }
  383. content::ContentUtilityClient*
  384. ContentMainDelegateImpl::CreateContentUtilityClient() {
  385. utility_client_ = std::make_unique<ContentUtilityClientImpl>();
  386. return utility_client_.get();
  387. }
  388. } // namespace weblayer