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