chrome_main_app_mode_mac.mm 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. // Copyright 2013 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. // On Mac, one can't make shortcuts with command-line arguments. Instead, we
  5. // produce small app bundles which locate the Chromium framework and load it,
  6. // passing the appropriate data. This is the entry point into the framework for
  7. // those app bundles.
  8. #import <Cocoa/Cocoa.h>
  9. #include <utility>
  10. #include <vector>
  11. #include "base/allocator/early_zone_registration_mac.h"
  12. #include "base/at_exit.h"
  13. #include "base/bind.h"
  14. #include "base/check.h"
  15. #include "base/command_line.h"
  16. #include "base/files/file_path.h"
  17. #include "base/files/file_util.h"
  18. #include "base/mac/bundle_locations.h"
  19. #include "base/mac/mac_logging.h"
  20. #include "base/message_loop/message_pump_type.h"
  21. #include "base/run_loop.h"
  22. #include "base/strings/sys_string_conversions.h"
  23. #include "base/strings/utf_string_conversions.h"
  24. #include "base/task/single_thread_task_executor.h"
  25. #include "base/threading/thread.h"
  26. #include "chrome/app/chrome_crash_reporter_client.h"
  27. #include "chrome/app_shim/app_shim_controller.h"
  28. #include "chrome/common/chrome_constants.h"
  29. #include "chrome/common/chrome_content_client.h"
  30. #include "chrome/common/chrome_paths.h"
  31. #include "chrome/common/chrome_paths_internal.h"
  32. #include "chrome/common/mac/app_mode_common.h"
  33. #include "components/crash/core/app/crashpad.h"
  34. #include "mojo/core/embedder/embedder.h"
  35. #include "mojo/core/embedder/scoped_ipc_support.h"
  36. #include "ui/accelerated_widget_mac/window_resize_helper_mac.h"
  37. #include "ui/base/l10n/l10n_util.h"
  38. #include "ui/base/resource/resource_bundle.h"
  39. #include "url/gurl.h"
  40. // The NSApplication for app shims is a vanilla NSApplication, but sub-class it
  41. // so that we can DCHECK that we know precisely when it is initialized.
  42. @interface AppShimApplication : NSApplication
  43. @end
  44. @implementation AppShimApplication
  45. @end
  46. extern "C" {
  47. // |ChromeAppModeStart()| is the point of entry into the framework from the app
  48. // mode loader. There are cases where the Chromium framework may have changed in
  49. // a way that is incompatible with an older shim (e.g. change to libc++ library
  50. // linking). The function name is versioned to provide a way to force shim
  51. // upgrades if they are launched before an updated version of Chromium can
  52. // upgrade them; the old shim will not be able to dyload the new
  53. // ChromeAppModeStart, so it will fall back to the upgrade path. See
  54. // https://crbug.com/561205.
  55. __attribute__((visibility("default"))) int APP_SHIM_ENTRY_POINT_NAME(
  56. const app_mode::ChromeAppModeInfo* info);
  57. } // extern "C"
  58. int APP_SHIM_ENTRY_POINT_NAME(const app_mode::ChromeAppModeInfo* info) {
  59. // The static constructor in //base will have registered PartitionAlloc as the
  60. // default zone. Allow the //base instance in the main library to register it
  61. // as well. Otherwise we end up passing memory to free() which was allocated
  62. // by an unknown zone. See crbug.com/1274236 for details.
  63. partition_alloc::AllowDoublePartitionAllocZoneRegistration();
  64. base::CommandLine::Init(info->argc, info->argv);
  65. @autoreleasepool {
  66. base::AtExitManager exit_manager;
  67. chrome::RegisterPathProvider();
  68. // Set bundle paths. This loads the bundles.
  69. base::mac::SetOverrideOuterBundlePath(
  70. base::FilePath(info->chrome_outer_bundle_path));
  71. base::mac::SetOverrideFrameworkBundlePath(
  72. base::FilePath(info->chrome_framework_path));
  73. // Note that `info->user_data_dir` for shims contains the app data path,
  74. // <user_data_dir>/<profile_dir>/Web Applications/_crx_extensionid/.
  75. const base::FilePath user_data_dir =
  76. base::FilePath(info->user_data_dir).DirName().DirName().DirName();
  77. // TODO(https://crbug.com/1274807): Specify `user_data_dir` to CrashPad.
  78. ChromeCrashReporterClient::Create();
  79. crash_reporter::InitializeCrashpad(true, "app_shim");
  80. // Calculate the preferred locale used by Chrome. We can't use
  81. // l10n_util::OverrideLocaleWithCocoaLocale() because it calls
  82. // [base::mac::OuterBundle() preferredLocalizations] which gets
  83. // localizations from the bundle of the running app (i.e. it is equivalent
  84. // to [[NSBundle mainBundle] preferredLocalizations]) instead of the target
  85. // bundle.
  86. NSArray* preferred_languages = [NSLocale preferredLanguages];
  87. NSArray* supported_languages = [base::mac::OuterBundle() localizations];
  88. std::string preferred_localization;
  89. for (NSString* language in preferred_languages) {
  90. // We must convert the "-" separator to "_" to be compatible with
  91. // NSBundle::localizations() e.g. "en-GB" becomes "en_GB".
  92. // See https://crbug.com/913345.
  93. language = [language stringByReplacingOccurrencesOfString:@"-"
  94. withString:@"_"];
  95. if ([supported_languages containsObject:language]) {
  96. preferred_localization = base::SysNSStringToUTF8(language);
  97. break;
  98. }
  99. // Check for language support without the region component.
  100. language = [language componentsSeparatedByString:@"_"][0];
  101. if ([supported_languages containsObject:language]) {
  102. preferred_localization = base::SysNSStringToUTF8(language);
  103. break;
  104. }
  105. }
  106. std::string locale = l10n_util::NormalizeLocale(
  107. l10n_util::GetApplicationLocale(preferred_localization));
  108. // Load localized strings and mouse cursor images.
  109. ui::ResourceBundle::InitSharedInstanceWithLocale(
  110. locale, NULL, ui::ResourceBundle::LOAD_COMMON_RESOURCES);
  111. ChromeContentClient chrome_content_client;
  112. content::SetContentClient(&chrome_content_client);
  113. // Launch the IO thread.
  114. base::Thread::Options io_thread_options;
  115. io_thread_options.message_pump_type = base::MessagePumpType::IO;
  116. base::Thread* io_thread = new base::Thread("CrAppShimIO");
  117. io_thread->StartWithOptions(std::move(io_thread_options));
  118. mojo::core::Init();
  119. mojo::core::ScopedIPCSupport ipc_support(
  120. io_thread->task_runner(),
  121. mojo::core::ScopedIPCSupport::ShutdownPolicy::FAST);
  122. // Initialize the NSApplication (and ensure that it was not previously
  123. // initialized).
  124. [AppShimApplication sharedApplication];
  125. CHECK([NSApp isKindOfClass:[AppShimApplication class]]);
  126. base::SingleThreadTaskExecutor main_task_executor(
  127. base::MessagePumpType::UI);
  128. ui::WindowResizeHelperMac::Get()->Init(main_task_executor.task_runner());
  129. base::PlatformThread::SetName("CrAppShimMain");
  130. AppShimController::Params controller_params;
  131. controller_params.user_data_dir = user_data_dir;
  132. // Similarly, extract the full profile path from |info->user_data_dir|.
  133. // Ignore |info->profile_dir| because it is only the relative path (unless
  134. // it is empty, in which case this is a profile-agnostic app).
  135. if (!base::FilePath(info->profile_dir).empty()) {
  136. controller_params.profile_dir =
  137. base::FilePath(info->user_data_dir).DirName().DirName();
  138. }
  139. controller_params.app_id = info->app_mode_id;
  140. controller_params.app_name = base::UTF8ToUTF16(info->app_mode_name);
  141. controller_params.app_url = GURL(info->app_mode_url);
  142. AppShimController controller(controller_params);
  143. base::RunLoop().Run();
  144. return 0;
  145. }
  146. }