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