chrome_restart_request.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
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/chromeos/login/chrome_restart_request.h"
6
7#include <vector>
8
9#include "ash/ash_switches.h"
10#include "base/command_line.h"
11#include "base/memory/weak_ptr.h"
12#include "base/message_loop/message_loop.h"
13#include "base/path_service.h"
14#include "base/prefs/json_pref_store.h"
15#include "base/prefs/pref_service.h"
16#include "base/process/launch.h"
17#include "base/strings/string_split.h"
18#include "base/strings/stringprintf.h"
19#include "base/sys_info.h"
20#include "base/timer/timer.h"
21#include "base/values.h"
22#include "cc/base/switches.h"
23#include "chrome/browser/browser_process.h"
24#include "chrome/browser/chromeos/login/user_manager.h"
25#include "chrome/browser/lifetime/application_lifetime.h"
26#include "chrome/common/chrome_constants.h"
27#include "chrome/common/chrome_paths.h"
28#include "chrome/common/chrome_switches.h"
29#include "chrome/common/url_constants.h"
30#include "chromeos/chromeos_switches.h"
31#include "chromeos/dbus/dbus_thread_manager.h"
32#include "chromeos/dbus/session_manager_client.h"
33#include "components/policy/core/common/policy_switches.h"
34#include "content/public/browser/browser_thread.h"
35#include "content/public/common/content_switches.h"
36#include "gpu/command_buffer/service/gpu_switches.h"
37#include "media/base/media_switches.h"
38#include "ui/base/ui_base_switches.h"
39#include "ui/compositor/compositor_switches.h"
40#include "ui/events/event_switches.h"
41#include "ui/gfx/switches.h"
42#include "ui/gl/gl_switches.h"
43#include "ui/wm/core/wm_core_switches.h"
44#include "url/gurl.h"
45
46using content::BrowserThread;
47
48namespace chromeos {
49
50namespace {
51
52// Increase logging level for Guest mode to avoid INFO messages in logs.
53const char kGuestModeLoggingLevel[] = "1";
54
55// Format of command line switch.
56const char kSwitchFormatString[] = " --%s=\"%s\"";
57
58// Derives the new command line from |base_command_line| by doing the following:
59// - Forward a given switches list to new command;
60// - Set start url if given;
61// - Append/override switches using |new_switches|;
62std::string DeriveCommandLine(const GURL& start_url,
63                              const CommandLine& base_command_line,
64                              const base::DictionaryValue& new_switches,
65                              CommandLine* command_line) {
66  DCHECK_NE(&base_command_line, command_line);
67
68  static const char* kForwardSwitches[] = {
69      ::switches::kDisableAccelerated2dCanvas,
70      ::switches::kDisableAcceleratedOverflowScroll,
71      ::switches::kDisableAcceleratedVideoDecode,
72      ::switches::kDisableBrowserPluginCompositing,
73      ::switches::kDisableDelegatedRenderer,
74      ::switches::kDisableFiltersOverIPC,
75      ::switches::kDisableForceCompositingMode,
76      ::switches::kDisableGpuShaderDiskCache,
77      ::switches::kDisableGpuWatchdog,
78      ::switches::kDisableGpuCompositing,
79      ::switches::kDisableGpuRasterization,
80      ::switches::kDisableImplSidePainting,
81      ::switches::kDisableMapImage,
82      ::switches::kDisablePrefixedEncryptedMedia,
83      ::switches::kDisablePanelFitting,
84      ::switches::kDisableRepaintAfterLayout,
85      ::switches::kDisableSeccompFilterSandbox,
86      ::switches::kDisableSetuidSandbox,
87      ::switches::kDisableThreadedCompositing,
88      ::switches::kDisableTouchDragDrop,
89      ::switches::kDisableTouchEditing,
90      ::switches::kDisableUniversalAcceleratedOverflowScroll,
91      ::switches::kDisableUnprefixedMediaSource,
92      ::switches::kDisableWebKitMediaSource,
93      ::switches::kDisableAcceleratedFixedRootBackground,
94      ::switches::kEnableAcceleratedFixedRootBackground,
95      ::switches::kEnableAcceleratedOverflowScroll,
96      ::switches::kEnableBeginFrameScheduling,
97      ::switches::kEnableCompositingForFixedPosition,
98      ::switches::kEnableDelegatedRenderer,
99      ::switches::kEnableEncryptedMedia,
100      ::switches::kEnableGestureTapHighlight,
101      ::switches::kDisableGestureTapHighlight,
102      ::switches::kDisableGpuSandbox,
103      ::switches::kEnableDeferredFilters,
104      ::switches::kEnableGpuRasterization,
105      ::switches::kEnableImplSidePainting,
106      ::switches::kEnableLogging,
107      ::switches::kEnableMapImage,
108      ::switches::kEnablePinch,
109      ::switches::kEnableRepaintAfterLayout,
110      ::switches::kEnableThreadedCompositing,
111      ::switches::kEnableTouchDragDrop,
112      ::switches::kEnableTouchEditing,
113      ::switches::kEnableUniversalAcceleratedOverflowScroll,
114      ::switches::kEnableViewport,
115      ::switches::kEnableViewportMeta,
116      ::switches::kMainFrameResizesAreOrientationChanges,
117      ::switches::kForceDeviceScaleFactor,
118      ::switches::kForceGpuRasterization,
119      ::switches::kGpuStartupDialog,
120      ::switches::kGpuSandboxAllowSysVShm,
121      ::switches::kGpuSandboxFailuresFatal,
122      ::switches::kMultiProfiles,
123      ::switches::kNoSandbox,
124      ::switches::kNumRasterThreads,
125      ::switches::kPpapiFlashArgs,
126      ::switches::kPpapiFlashPath,
127      ::switches::kPpapiFlashVersion,
128      ::switches::kPpapiInProcess,
129      ::switches::kRendererStartupDialog,
130      ::switches::kEnableShareGroupAsyncTextureUpload,
131      ::switches::kTabCaptureUpscaleQuality,
132      ::switches::kTabCaptureDownscaleQuality,
133#if defined(USE_XI2_MT)
134      ::switches::kTouchCalibration,
135#endif
136      ::switches::kTouchDevices,
137      ::switches::kTouchEvents,
138      ::switches::kTouchOptimizedUI,
139      ::switches::kUIDisableThreadedCompositing,
140      ::switches::kUIPrioritizeInGpuProcess,
141#if defined(USE_CRAS)
142      ::switches::kUseCras,
143#endif
144      ::switches::kUseDiscardableMemory,
145      ::switches::kUseGL,
146      ::switches::kUserDataDir,
147      ::switches::kV,
148      ::switches::kVModule,
149      ::switches::kWebGLCommandBufferSizeKb,
150      ::switches::kEnableWebGLDraftExtensions,
151#if defined(ENABLE_WEBRTC)
152      ::switches::kDisableWebRtcHWDecoding,
153      ::switches::kDisableWebRtcHWEncoding,
154      ::switches::kEnableAudioTrackProcessing,
155      ::switches::kEnableWebRtcHWVp8Encoding,
156#endif
157      ash::switches::kAshDefaultWallpaperLarge,
158      ash::switches::kAshDefaultWallpaperSmall,
159      ash::switches::kAshGuestWallpaperLarge,
160      ash::switches::kAshGuestWallpaperSmall,
161      ash::switches::kAshHostWindowBounds,
162      ash::switches::kAshTouchHud,
163      ash::switches::kAuraLegacyPowerButton,
164      // Please keep these in alphabetical order. Non-UI Compositor switches
165      // here should also be added to
166      // content/browser/renderer_host/render_process_host_impl.cc.
167      cc::switches::kCompositeToMailbox,
168      cc::switches::kDisableCompositedAntialiasing,
169      cc::switches::kDisableCompositorTouchHitTesting,
170      cc::switches::kDisableMainFrameBeforeActivation,
171      cc::switches::kDisableMainFrameBeforeDraw,
172      cc::switches::kDisableThreadedAnimation,
173      cc::switches::kEnableGpuBenchmarking,
174      cc::switches::kEnablePinchVirtualViewport,
175      cc::switches::kEnableMainFrameBeforeActivation,
176      cc::switches::kEnableTopControlsPositionCalculation,
177      cc::switches::kMaxTilesForInterestArea,
178      cc::switches::kMaxUnusedResourceMemoryUsagePercentage,
179      cc::switches::kShowCompositedLayerBorders,
180      cc::switches::kShowFPSCounter,
181      cc::switches::kShowLayerAnimationBounds,
182      cc::switches::kShowNonOccludingRects,
183      cc::switches::kShowOccludingRects,
184      cc::switches::kShowPropertyChangedRects,
185      cc::switches::kShowReplicaScreenSpaceRects,
186      cc::switches::kShowScreenSpaceRects,
187      cc::switches::kShowSurfaceDamageRects,
188      cc::switches::kSlowDownRasterScaleFactor,
189      cc::switches::kUIDisablePartialSwap,
190      chromeos::switches::kDbusStub,
191      chromeos::switches::kDisableLoginAnimations,
192      chromeos::switches::kHasChromeOSDiamondKey,
193      chromeos::switches::kHasChromeOSKeyboard,
194      chromeos::switches::kLoginProfile,
195      chromeos::switches::kNaturalScrollDefault,
196      ::switches::kEnableBrowserTextSubpixelPositioning,
197      ::switches::kEnableWebkitTextSubpixelPositioning,
198      policy::switches::kDeviceManagementUrl,
199      wm::switches::kWindowAnimationsDisabled,
200  };
201  command_line->CopySwitchesFrom(base_command_line,
202                                 kForwardSwitches,
203                                 arraysize(kForwardSwitches));
204
205  if (start_url.is_valid())
206    command_line->AppendArg(start_url.spec());
207
208  for (base::DictionaryValue::Iterator it(new_switches);
209       !it.IsAtEnd();
210       it.Advance()) {
211    std::string value;
212    CHECK(it.value().GetAsString(&value));
213    command_line->AppendSwitchASCII(it.key(), value);
214  }
215
216  std::string cmd_line_str = command_line->GetCommandLineString();
217  // Special workaround for the arguments that should be quoted.
218  // Copying switches won't be needed when Guest mode won't need restart
219  // http://crosbug.com/6924
220  if (base_command_line.HasSwitch(::switches::kRegisterPepperPlugins)) {
221    cmd_line_str += base::StringPrintf(
222        kSwitchFormatString,
223        ::switches::kRegisterPepperPlugins,
224        base_command_line.GetSwitchValueNative(
225            ::switches::kRegisterPepperPlugins).c_str());
226  }
227
228  return cmd_line_str;
229}
230
231// Simulates a session manager restart by launching give command line
232// and exit current process.
233void ReLaunch(const std::string& command_line) {
234  std::vector<std::string> argv;
235
236  // This is not a proper way to get |argv| but it's good enough for debugging.
237  base::SplitString(command_line, ' ', &argv);
238
239  base::LaunchProcess(argv, base::LaunchOptions(), NULL);
240  chrome::AttemptUserExit();
241}
242
243// Empty function that run by the local state task runner to ensure last
244// commit goes through.
245void EnsureLocalStateIsWritten() {}
246
247// Wraps the work of sending chrome restart request to session manager.
248// If local state is present, try to commit it first. The request is fired when
249// the commit goes through or some time (3 seconds) has elapsed.
250class ChromeRestartRequest
251    : public base::SupportsWeakPtr<ChromeRestartRequest> {
252 public:
253  explicit ChromeRestartRequest(const std::string& command_line);
254  ~ChromeRestartRequest();
255
256  // Starts the request.
257  void Start();
258
259 private:
260  // Fires job restart request to session manager.
261  void RestartJob();
262
263  const int pid_;
264  const std::string command_line_;
265  base::OneShotTimer<ChromeRestartRequest> timer_;
266
267  DISALLOW_COPY_AND_ASSIGN(ChromeRestartRequest);
268};
269
270ChromeRestartRequest::ChromeRestartRequest(const std::string& command_line)
271    : pid_(getpid()),
272      command_line_(command_line) {}
273
274ChromeRestartRequest::~ChromeRestartRequest() {}
275
276void ChromeRestartRequest::Start() {
277  VLOG(1) << "Requesting a restart with PID " << pid_
278          << " and command line: " << command_line_;
279
280  // Session Manager may kill the chrome anytime after this point.
281  // Write exit_cleanly and other stuff to the disk here.
282  g_browser_process->EndSession();
283
284  PrefService* local_state = g_browser_process->local_state();
285  if (!local_state) {
286    RestartJob();
287    return;
288  }
289
290  // XXX: normally this call must not be needed, however RestartJob
291  // just kills us so settings may be lost. See http://crosbug.com/13102
292  local_state->CommitPendingWrite();
293  timer_.Start(
294      FROM_HERE, base::TimeDelta::FromSeconds(3), this,
295      &ChromeRestartRequest::RestartJob);
296
297  // Post a task to local state task runner thus it occurs last on the task
298  // queue, so it would be executed after committing pending write on that
299  // thread.
300  scoped_refptr<base::SequencedTaskRunner> local_state_task_runner =
301      JsonPrefStore::GetTaskRunnerForFile(
302          base::FilePath(chrome::kLocalStorePoolName),
303          BrowserThread::GetBlockingPool());
304  local_state_task_runner->PostTaskAndReply(
305      FROM_HERE,
306      base::Bind(&EnsureLocalStateIsWritten),
307      base::Bind(&ChromeRestartRequest::RestartJob, AsWeakPtr()));
308}
309
310void ChromeRestartRequest::RestartJob() {
311  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
312
313  DBusThreadManager::Get()->GetSessionManagerClient()->RestartJob(
314      pid_, command_line_);
315
316  delete this;
317}
318
319}  // namespace
320
321std::string GetOffTheRecordCommandLine(
322    const GURL& start_url,
323    const CommandLine& base_command_line,
324    CommandLine* command_line) {
325  base::DictionaryValue otr_switches;
326  otr_switches.SetString(switches::kGuestSession, std::string());
327  otr_switches.SetString(::switches::kIncognito, std::string());
328  otr_switches.SetString(::switches::kLoggingLevel, kGuestModeLoggingLevel);
329  otr_switches.SetString(switches::kLoginUser, UserManager::kGuestUserName);
330
331  // Override the home page.
332  otr_switches.SetString(::switches::kHomePage,
333                         GURL(chrome::kChromeUINewTabURL).spec());
334
335  return DeriveCommandLine(start_url,
336                           base_command_line,
337                           otr_switches,
338                           command_line);
339}
340
341void RestartChrome(const std::string& command_line) {
342  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
343
344  static bool restart_requested = false;
345  if (restart_requested) {
346    NOTREACHED() << "Request chrome restart for more than once.";
347  }
348  restart_requested = true;
349
350  if (!base::SysInfo::IsRunningOnChromeOS()) {
351    // Relaunch chrome without session manager on dev box.
352    ReLaunch(command_line);
353    return;
354  }
355
356  // ChromeRestartRequest deletes itself after request sent to session manager.
357  (new ChromeRestartRequest(command_line))->Start();
358}
359
360}  // namespace chromeos
361