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