[M85 Dev][EFL] Fix errors to generate ninja files
[platform/framework/web/chromium-efl.git] / chrome / browser / chrome_browser_main_mac.mm
1 // Copyright (c) 2012 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
5 #include "chrome/browser/chrome_browser_main_mac.h"
6
7 #import <Cocoa/Cocoa.h>
8
9 #include "base/bind.h"
10 #include "base/command_line.h"
11 #include "base/mac/bundle_locations.h"
12 #import "base/mac/foundation_util.h"
13 #include "base/mac/mac_util.h"
14 #include "base/mac/scoped_nsobject.h"
15 #include "base/metrics/histogram_functions.h"
16 #include "base/path_service.h"
17 #include "base/strings/sys_string_conversions.h"
18 #include "build/branding_buildflags.h"
19 #import "chrome/browser/app_controller_mac.h"
20 #include "chrome/browser/apps/app_shim/app_shim_listener.h"
21 #include "chrome/browser/browser_process.h"
22 #include "chrome/browser/browser_process_platform_part.h"
23 #import "chrome/browser/chrome_browser_application_mac.h"
24 #include "chrome/browser/first_run/first_run.h"
25 #include "chrome/browser/mac/install_from_dmg.h"
26 #import "chrome/browser/mac/keystone_glue.h"
27 #include "chrome/browser/mac/mac_startup_profiler.h"
28 #include "chrome/browser/ui/cocoa/main_menu_builder.h"
29 #include "chrome/common/channel_info.h"
30 #include "chrome/common/chrome_paths.h"
31 #include "chrome/common/chrome_switches.h"
32 #include "chrome/common/pref_names.h"
33 #include "chrome/grit/chromium_strings.h"
34 #include "components/crash/core/app/crashpad.h"
35 #include "components/metrics/metrics_service.h"
36 #include "components/os_crypt/os_crypt.h"
37 #include "components/version_info/channel.h"
38 #include "content/public/common/main_function_params.h"
39 #include "content/public/common/result_codes.h"
40 #include "ui/base/l10n/l10n_util.h"
41 #include "ui/base/resource/resource_bundle.h"
42 #include "ui/base/resource/resource_handle.h"
43 #include "ui/native_theme/native_theme_mac.h"
44
45 namespace {
46
47 #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
48
49 // These values are persisted to logs as OSXOtherChromeInstancesResult.
50 // Entries should not be renumbered and numeric values should never be reused.
51 enum class OtherInstancesResult {
52   kFailureDontKnowWhenOtherChromeUsed,
53   kFailureToReadPlist,
54   kNoOtherChrome,
55   kOneOtherChromeAndLastUsedWithinWeek,
56   kOneOtherChromeAndLastUsedWithinMonth,
57   kOneOtherChromeAndLastUsedMoreThanAMonthAgo,
58   kMoreThanOneOtherChromeAndLastUsedWithinWeek,
59   kMoreThanOneOtherChromeAndLastUsedWithinMonth,
60   kMoreThanOneOtherChromeAndLastUsedMoreThanAMonthAgo,
61   kMaxValue = kMoreThanOneOtherChromeAndLastUsedMoreThanAMonthAgo,
62 };
63
64 struct WhenLastUsed {
65   int within_last_week = 0;
66   int within_last_month = 0;
67   int before_last_month = 0;
68 };
69
70 OtherInstancesResult OtherInstancesResultForWhenLastUsed(
71     const WhenLastUsed& used) {
72   if (used.within_last_week + used.within_last_month + used.before_last_month ==
73       0) {
74     return OtherInstancesResult::kNoOtherChrome;
75   }
76
77   if (used.within_last_week + used.within_last_month + used.before_last_month ==
78       1) {
79     if (used.within_last_week)
80       return OtherInstancesResult::kOneOtherChromeAndLastUsedWithinWeek;
81
82     if (used.within_last_month)
83       return OtherInstancesResult::kOneOtherChromeAndLastUsedWithinMonth;
84
85     return OtherInstancesResult::kOneOtherChromeAndLastUsedMoreThanAMonthAgo;
86   }
87
88   if (used.within_last_week)
89     return OtherInstancesResult::kMoreThanOneOtherChromeAndLastUsedWithinWeek;
90
91   if (used.within_last_month)
92     return OtherInstancesResult::kMoreThanOneOtherChromeAndLastUsedWithinMonth;
93
94   return OtherInstancesResult::
95       kMoreThanOneOtherChromeAndLastUsedMoreThanAMonthAgo;
96 }
97
98 void RecordChromeQueryResults(NSMetadataQuery* query) {
99   __block bool other_chrome_last_used_unknown = false;
100   __block bool failed_to_read_plist = false;
101   __block WhenLastUsed same_channel;
102   __block WhenLastUsed different_channel;
103
104   NSURL* this_url = NSBundle.mainBundle.bundleURL;
105   std::string this_channel = chrome::GetChannelName();
106   NSDate* about_a_week_ago =
107       [[NSDate date] dateByAddingTimeInterval:-7 * 24 * 60 * 60];
108   NSDate* about_a_month_ago =
109       [[NSDate date] dateByAddingTimeInterval:-30 * 24 * 60 * 60];
110
111   [query enumerateResultsUsingBlock:^(id result, NSUInteger idx, BOOL* stop) {
112     // Skip this copy of Chrome. Note that NSMetadataItemURLKey is not used as
113     // it always returns nil while NSMetadataItemPathKey returns a legit path.
114     // Filed as FB7689234.
115     NSString* app_path = base::mac::ObjCCast<NSString>(
116         [result valueForAttribute:NSMetadataItemPathKey]);
117     if (!app_path) {
118       // It seems implausible, but there are Macs in the field for which
119       // Spotlight will find results for the query of locating Chrome but cannot
120       // actually return a path to the result. https://crbug.com/1086555
121       failed_to_read_plist = true;
122       *stop = YES;
123       return;
124     }
125
126     NSURL* app_url = [NSURL fileURLWithPath:app_path isDirectory:YES];
127     if ([app_url isEqual:this_url])
128       return;
129
130     NSURL* plist_url = [[app_url URLByAppendingPathComponent:@"Contents"
131                                                  isDirectory:YES]
132         URLByAppendingPathComponent:@"Info.plist"
133                         isDirectory:NO];
134     NSDictionary* plist = [NSDictionary dictionaryWithContentsOfURL:plist_url];
135     if (!plist) {
136       failed_to_read_plist = true;
137       *stop = YES;
138       return;
139     }
140
141     // Skip any SxS-capable copies of Chrome.
142     if (plist[@"CrProductDirName"])
143       return;
144
145     WhenLastUsed* when_last_used = &different_channel;
146     if (this_channel == base::SysNSStringToUTF8(plist[@"KSChannelID"]))
147       when_last_used = &same_channel;
148
149     NSDate* last_used = base::mac::ObjCCast<NSDate>(
150         [result valueForAttribute:NSMetadataItemLastUsedDateKey]);
151     if (!last_used) {
152       other_chrome_last_used_unknown = true;
153       *stop = YES;
154       return;
155     }
156
157     if ([last_used compare:about_a_week_ago] == NSOrderedDescending)
158       ++when_last_used->within_last_week;
159     else if ([last_used compare:about_a_month_ago] == NSOrderedDescending)
160       ++when_last_used->within_last_month;
161     else
162       ++when_last_used->before_last_month;
163   }];
164
165   if (other_chrome_last_used_unknown) {
166     base::UmaHistogramEnumeration(
167         "OSX.Installation.OtherChromeInstances.SameChannel",
168         OtherInstancesResult::kFailureDontKnowWhenOtherChromeUsed);
169     base::UmaHistogramEnumeration(
170         "OSX.Installation.OtherChromeInstances.DifferentChannel",
171         OtherInstancesResult::kFailureDontKnowWhenOtherChromeUsed);
172     return;
173   }
174
175   if (failed_to_read_plist) {
176     base::UmaHistogramEnumeration(
177         "OSX.Installation.OtherChromeInstances.SameChannel",
178         OtherInstancesResult::kFailureToReadPlist);
179     base::UmaHistogramEnumeration(
180         "OSX.Installation.OtherChromeInstances.DifferentChannel",
181         OtherInstancesResult::kFailureToReadPlist);
182     return;
183   }
184
185   base::UmaHistogramEnumeration(
186       "OSX.Installation.OtherChromeInstances.SameChannel",
187       OtherInstancesResultForWhenLastUsed(same_channel));
188   base::UmaHistogramEnumeration(
189       "OSX.Installation.OtherChromeInstances.DifferentChannel",
190       OtherInstancesResultForWhenLastUsed(different_channel));
191 }
192
193 void ExecuteChromeQuery() {
194   __block NSMetadataQuery* query = [[NSMetadataQuery alloc] init];
195
196   __block id token = [[NSNotificationCenter defaultCenter]
197       addObserverForName:NSMetadataQueryDidFinishGatheringNotification
198                   object:query
199                    queue:[NSOperationQueue mainQueue]
200               usingBlock:^(NSNotification* note) {
201                 [query stopQuery];
202                 RecordChromeQueryResults(query);
203                 [query release];
204                 [[NSNotificationCenter defaultCenter] removeObserver:token];
205               }];
206
207   query.predicate =
208       [NSPredicate predicateWithFormat:
209                        @"kMDItemContentType == 'com.apple.application-bundle'"
210                        @"AND kMDItemCFBundleIdentifier == 'com.google.Chrome'"];
211
212   [query startQuery];
213 }
214
215 // Records statistics about this install of Chromium if it is a Google Chrome
216 // Beta or Google Chrome Dev instance. This is to allow for decisions to be made
217 // about the migration of user data directories.
218 void RecordBetaAndDevStats() {
219   version_info::Channel channel = chrome::GetChannel();
220   if (channel != version_info::Channel::BETA &&
221       channel != version_info::Channel::DEV) {
222     return;
223   }
224
225   ExecuteChromeQuery();
226 }
227
228 #endif  // GOOGLE_CHROME_BRANDING
229
230 }  // namespace
231
232 // ChromeBrowserMainPartsMac ---------------------------------------------------
233
234 ChromeBrowserMainPartsMac::ChromeBrowserMainPartsMac(
235     const content::MainFunctionParams& parameters,
236     StartupData* startup_data)
237     : ChromeBrowserMainPartsPosix(parameters, startup_data) {}
238
239 ChromeBrowserMainPartsMac::~ChromeBrowserMainPartsMac() {
240 }
241
242 int ChromeBrowserMainPartsMac::PreEarlyInitialization() {
243   if (base::mac::WasLaunchedAsLoginItemRestoreState()) {
244     base::CommandLine* singleton_command_line =
245         base::CommandLine::ForCurrentProcess();
246     singleton_command_line->AppendSwitch(switches::kRestoreLastSession);
247   } else if (base::mac::WasLaunchedAsHiddenLoginItem()) {
248     base::CommandLine* singleton_command_line =
249         base::CommandLine::ForCurrentProcess();
250     singleton_command_line->AppendSwitch(switches::kNoStartupWindow);
251   }
252
253   return ChromeBrowserMainPartsPosix::PreEarlyInitialization();
254 }
255
256 void ChromeBrowserMainPartsMac::PreMainMessageLoopStart() {
257   MacStartupProfiler::GetInstance()->Profile(
258       MacStartupProfiler::PRE_MAIN_MESSAGE_LOOP_START);
259   ChromeBrowserMainPartsPosix::PreMainMessageLoopStart();
260
261   // ChromeBrowserMainParts should have loaded the resource bundle by this
262   // point (needed to load the nib).
263   CHECK(ui::ResourceBundle::HasSharedInstance());
264
265   // This is a no-op if the KeystoneRegistration framework is not present.
266   // The framework is only distributed with branded Google Chrome builds.
267   [[KeystoneGlue defaultKeystoneGlue] registerWithKeystone];
268
269   // Disk image installation is sort of a first-run task, so it shares the
270   // no first run switches.
271   //
272   // This needs to be done after the resource bundle is initialized (for
273   // access to localizations in the UI) and after Keystone is initialized
274   // (because the installation may need to promote Keystone) but before the
275   // app controller is set up (and thus before MainMenu.nib is loaded, because
276   // the app controller assumes that a browser has been set up and will crash
277   // upon receipt of certain notifications if no browser exists), before
278   // anyone tries doing anything silly like firing off an import job, and
279   // before anything creating preferences like Local State in order for the
280   // relaunched installed application to still consider itself as first-run.
281   if (!first_run::IsFirstRunSuppressed(parsed_command_line())) {
282     if (MaybeInstallFromDiskImage()) {
283       // The application was installed and the installed copy has been
284       // launched.  This process is now obsolete.  Exit.
285       exit(0);
286     }
287   }
288
289   // Create the app delegate. This object is intentionally leaked as a global
290   // singleton. It is accessed through -[NSApp delegate].
291   AppController* app_controller = [[AppController alloc] init];
292   [NSApp setDelegate:app_controller];
293
294   chrome::BuildMainMenu(NSApp, app_controller,
295                         l10n_util::GetStringUTF16(IDS_PRODUCT_NAME), false);
296   [app_controller mainMenuCreated];
297
298   PrefService* local_state = g_browser_process->local_state();
299   DCHECK(local_state);
300
301   // AppKit only restores windows to their original spaces when relaunching
302   // apps after a restart, and puts them all on the current space when an app
303   // is manually quit and relaunched. If Chrome restarted itself, ask AppKit to
304   // treat this launch like a system restart and restore everything.
305   if (local_state->GetBoolean(prefs::kWasRestarted)) {
306     [NSUserDefaults.standardUserDefaults registerDefaults:@{
307       @"NSWindowRestoresWorkspaceAtLaunch" : @YES
308     }];
309   }
310 }
311
312 void ChromeBrowserMainPartsMac::PostMainMessageLoopStart() {
313   MacStartupProfiler::GetInstance()->Profile(
314       MacStartupProfiler::POST_MAIN_MESSAGE_LOOP_START);
315   ChromeBrowserMainPartsPosix::PostMainMessageLoopStart();
316
317 #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
318   RecordBetaAndDevStats();
319 #endif  // GOOGLE_CHROME_BRANDING
320 }
321
322 void ChromeBrowserMainPartsMac::PreProfileInit() {
323   MacStartupProfiler::GetInstance()->Profile(
324       MacStartupProfiler::PRE_PROFILE_INIT);
325   ChromeBrowserMainPartsPosix::PreProfileInit();
326
327   // This is called here so that the app shim socket is only created after
328   // taking the singleton lock.
329   g_browser_process->platform_part()->app_shim_listener()->Init();
330 }
331
332 void ChromeBrowserMainPartsMac::PostProfileInit() {
333   MacStartupProfiler::GetInstance()->Profile(
334       MacStartupProfiler::POST_PROFILE_INIT);
335   ChromeBrowserMainPartsPosix::PostProfileInit();
336
337   g_browser_process->metrics_service()->RecordBreakpadRegistration(
338       crash_reporter::GetUploadsEnabled());
339
340   // Activation of Keystone is not automatic but done in response to the
341   // counting and reporting of profiles.
342   KeystoneGlue* glue = [KeystoneGlue defaultKeystoneGlue];
343   if (glue && ![glue isRegisteredAndActive]) {
344     // If profile loading has failed, we still need to handle other tasks
345     // like marking of the product as active.
346     [glue setRegistrationActive];
347   }
348 }
349
350 void ChromeBrowserMainPartsMac::DidEndMainMessageLoop() {
351   AppController* appController =
352       base::mac::ObjCCastStrict<AppController>([NSApp delegate]);
353   [appController didEndMainMessageLoop];
354 }