app_list_service.cc revision 116680a4aac90f2aa7413d9095a592090648e557
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
5#include "chrome/browser/ui/app_list/app_list_service.h"
6
7#include "base/command_line.h"
8#include "base/metrics/histogram.h"
9#include "base/prefs/pref_registry_simple.h"
10#include "base/process/process_info.h"
11#include "base/strings/string_number_conversions.h"
12#include "base/time/time.h"
13#include "chrome/common/chrome_switches.h"
14#include "chrome/common/pref_names.h"
15
16namespace {
17
18enum StartupType {
19  COLD_START,
20  WARM_START,
21  WARM_START_FAST,
22};
23
24// For when an app list show request is received via CommandLine. Indicates
25// whether the Profile the app list was previously showing was the SAME, OTHER
26// or NONE with respect to the new Profile to show.
27enum ProfileLoadState {
28  PROFILE_LOADED_SAME,
29  PROFILE_LOADED_OTHER,
30  PROFILE_LOADED_NONE,
31};
32
33base::Time GetOriginalProcessStartTime(const CommandLine& command_line) {
34  if (command_line.HasSwitch(switches::kOriginalProcessStartTime)) {
35    std::string start_time_string =
36        command_line.GetSwitchValueASCII(switches::kOriginalProcessStartTime);
37    int64 remote_start_time;
38    base::StringToInt64(start_time_string, &remote_start_time);
39    return base::Time::FromInternalValue(remote_start_time);
40  }
41
42// base::CurrentProcessInfo::CreationTime() is only defined on some
43// platforms.
44#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
45  return base::CurrentProcessInfo::CreationTime();
46#else
47  return base::Time();
48#endif
49}
50
51StartupType GetStartupType(const CommandLine& command_line) {
52  // The presence of kOriginalProcessStartTime implies that another process
53  // has sent us its command line to handle, ie: we are already running.
54  if (command_line.HasSwitch(switches::kOriginalProcessStartTime)) {
55    return command_line.HasSwitch(switches::kFastStart) ?
56        WARM_START_FAST : WARM_START;
57  }
58  return COLD_START;
59}
60
61// The time the process that caused the app list to be shown started. This isn't
62// necessarily the currently executing process as we may be processing a command
63// line given to a short-lived Chrome instance.
64int64 g_original_process_start_time;
65
66// The type of startup the the current app list show has gone through.
67StartupType g_app_show_startup_type;
68
69// The state of the active app list profile at the most recent launch.
70ProfileLoadState g_profile_load_state;
71
72void RecordFirstPaintTiming() {
73  base::Time start_time(
74      base::Time::FromInternalValue(g_original_process_start_time));
75  base::TimeDelta elapsed = base::Time::Now() - start_time;
76  switch (g_app_show_startup_type) {
77    case COLD_START:
78      DCHECK_EQ(PROFILE_LOADED_NONE, g_profile_load_state);
79      UMA_HISTOGRAM_LONG_TIMES("Startup.AppListFirstPaintColdStart", elapsed);
80      break;
81    case WARM_START:
82      // For warm starts, only record showing the same profile. "NONE" should
83      // only occur in the first 30 seconds after startup. "OTHER" only occurs
84      // for multi-profile cases. In these cases, timings are also affected by
85      // whether or not a profile has been loaded from disk, which makes the
86      // profile load asynchronous and skews results unpredictably.
87      if (g_profile_load_state == PROFILE_LOADED_SAME)
88        UMA_HISTOGRAM_LONG_TIMES("Startup.AppListFirstPaintWarmStart", elapsed);
89      break;
90    case WARM_START_FAST:
91      if (g_profile_load_state == PROFILE_LOADED_SAME) {
92        UMA_HISTOGRAM_LONG_TIMES("Startup.AppListFirstPaintWarmStartFast",
93                                 elapsed);
94      }
95      break;
96  }
97}
98
99void RecordStartupInfo(AppListService* service,
100                       const CommandLine& command_line,
101                       Profile* launch_profile) {
102  base::Time start_time = GetOriginalProcessStartTime(command_line);
103  if (start_time.is_null())
104    return;
105
106  base::TimeDelta elapsed = base::Time::Now() - start_time;
107  StartupType startup_type = GetStartupType(command_line);
108  switch (startup_type) {
109    case COLD_START:
110      UMA_HISTOGRAM_LONG_TIMES("Startup.ShowAppListColdStart", elapsed);
111      break;
112    case WARM_START:
113      UMA_HISTOGRAM_LONG_TIMES("Startup.ShowAppListWarmStart", elapsed);
114      break;
115    case WARM_START_FAST:
116      UMA_HISTOGRAM_LONG_TIMES("Startup.ShowAppListWarmStartFast", elapsed);
117      break;
118  }
119
120  g_original_process_start_time = start_time.ToInternalValue();
121  g_app_show_startup_type = startup_type;
122
123  Profile* current_profile = service->GetCurrentAppListProfile();
124  if (!current_profile)
125    g_profile_load_state = PROFILE_LOADED_NONE;
126  else if (current_profile == launch_profile)
127    g_profile_load_state = PROFILE_LOADED_SAME;
128  else
129    g_profile_load_state = PROFILE_LOADED_OTHER;
130
131  service->SetAppListNextPaintCallback(RecordFirstPaintTiming);
132}
133
134}  // namespace
135
136// static
137void AppListService::RegisterPrefs(PrefRegistrySimple* registry) {
138  registry->RegisterInt64Pref(prefs::kLastAppListLaunchPing, 0);
139  registry->RegisterIntegerPref(prefs::kAppListLaunchCount, 0);
140  registry->RegisterInt64Pref(prefs::kLastAppListAppLaunchPing, 0);
141  registry->RegisterIntegerPref(prefs::kAppListAppLaunchCount, 0);
142  registry->RegisterStringPref(prefs::kAppListProfile, std::string());
143  registry->RegisterBooleanPref(prefs::kAppLauncherIsEnabled, false);
144  registry->RegisterBooleanPref(prefs::kAppLauncherHasBeenEnabled, false);
145  registry->RegisterIntegerPref(prefs::kAppListEnableMethod,
146                                ENABLE_NOT_RECORDED);
147  registry->RegisterInt64Pref(prefs::kAppListEnableTime, 0);
148
149#if defined(OS_MACOSX)
150  registry->RegisterIntegerPref(prefs::kAppLauncherShortcutVersion, 0);
151#endif
152
153  // Identifies whether we should show the app launcher promo or not.
154  // Note that a field trial also controls the showing, so the promo won't show
155  // unless the pref is set AND the field trial is set to a proper group.
156  registry->RegisterBooleanPref(prefs::kShowAppLauncherPromo, true);
157}
158
159// static
160bool AppListService::HandleLaunchCommandLine(
161    const base::CommandLine& command_line,
162    Profile* launch_profile) {
163  InitAll(launch_profile);
164  if (!command_line.HasSwitch(switches::kShowAppList))
165    return false;
166
167  // The --show-app-list switch is used for shortcuts on the native desktop.
168  AppListService* service = Get(chrome::HOST_DESKTOP_TYPE_NATIVE);
169  DCHECK(service);
170  RecordStartupInfo(service, command_line, launch_profile);
171  service->ShowForProfile(launch_profile);
172  return true;
173}
174