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