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