Home | History | Annotate | Download | only in login
      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/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/launch.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 
     44 using content::BrowserThread;
     45 
     46 namespace chromeos {
     47 
     48 namespace {
     49 
     50 // Increase logging level for Guest mode to avoid LOG(INFO) messages in logs.
     51 const char kGuestModeLoggingLevel[] = "1";
     52 
     53 // Format of command line switch.
     54 const char kSwitchFormatString[] = " --%s=\"%s\"";
     55 
     56 // User name which is used in the Guest session.
     57 const char kGuestUserName[] = "";
     58 
     59 // Derives the new command line from |base_command_line| by doing the following:
     60 // - Forward a given switches list to new command;
     61 // - Set start url if given;
     62 // - Append/override switches using |new_switches|;
     63 std::string DeriveCommandLine(const GURL& start_url,
     64                               const CommandLine& base_command_line,
     65                               const base::DictionaryValue& new_switches,
     66                               CommandLine* command_line) {
     67   DCHECK_NE(&base_command_line, command_line);
     68 
     69   static const char* kForwardSwitches[] = {
     70       ::switches::kAllowFiltersOverIPC,
     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::kDisableGpuCompositing,
     83       ::switches::kDisableLegacyEncryptedMedia,
     84       ::switches::kDisablePanelFitting,
     85       ::switches::kDisableSeccompFilterSandbox,
     86       ::switches::kDisableSetuidSandbox,
     87       ::switches::kDisableThreadedCompositing,
     88       ::switches::kDisableTouchDragDrop,
     89       ::switches::kDisableTouchEditing,
     90       ::switches::kDisableWebKitMediaSource,
     91       ::switches::kDisableAcceleratedFixedRootBackground,
     92       ::switches::kEnableAcceleratedFixedRootBackground,
     93       ::switches::kEnableAcceleratedOverflowScroll,
     94       ::switches::kEnableBeginFrameScheduling,
     95       ::switches::kEnableBrowserInputController,
     96       ::switches::kEnableCompositingForFixedPosition,
     97       ::switches::kEnableDelegatedRenderer,
     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::kGpuSandboxAllowSysVShm,
    111       ::switches::kMultiProfiles,
    112       ::switches::kNoSandbox,
    113       ::switches::kPpapiFlashArgs,
    114       ::switches::kPpapiFlashInProcess,
    115       ::switches::kPpapiFlashPath,
    116       ::switches::kPpapiFlashVersion,
    117       ::switches::kPpapiInProcess,
    118       ::switches::kRendererStartupDialog,
    119       ::switches::kEnableShareGroupAsyncTextureUpload,
    120       ::switches::kTabCaptureUpscaleQuality,
    121       ::switches::kTabCaptureDownscaleQuality,
    122 #if defined(USE_XI2_MT)
    123       ::switches::kTouchCalibration,
    124 #endif
    125       ::switches::kTouchDevices,
    126       ::switches::kTouchEvents,
    127       ::switches::kTouchOptimizedUI,
    128       ::switches::kUIDisableThreadedCompositing,
    129       ::switches::kUIMaxFramesPending,
    130       ::switches::kUIPrioritizeInGpuProcess,
    131 #if defined(USE_CRAS)
    132       ::switches::kUseCras,
    133 #endif
    134       ::switches::kUseGL,
    135       ::switches::kUserDataDir,
    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 #endif
    145       ash::switches::kAshHostWindowBounds,
    146       ash::switches::kAshTouchHud,
    147       ash::switches::kAuraLegacyPowerButton,
    148       // Please keep these in alphabetical order. Non-UI Compositor switches
    149       // here should also be added to
    150       // content/browser/renderer_host/render_process_host_impl.cc.
    151       cc::switches::kBackgroundColorInsteadOfCheckerboard,
    152       cc::switches::kCompositeToMailbox,
    153       cc::switches::kDisableCompositedAntialiasing,
    154       cc::switches::kDisableCompositorTouchHitTesting,
    155       cc::switches::kDisableImplSidePainting,
    156       cc::switches::kDisableThreadedAnimation,
    157       cc::switches::kEnableImplSidePainting,
    158       cc::switches::kEnablePartialSwap,
    159       cc::switches::kEnablePerTilePainting,
    160       cc::switches::kEnablePinchVirtualViewport,
    161       cc::switches::kEnableTopControlsPositionCalculation,
    162       cc::switches::kForceDirectLayerDrawing,
    163       cc::switches::kLowResolutionContentsScaleFactor,
    164       cc::switches::kMaxTilesForInterestArea,
    165       cc::switches::kMaxUnusedResourceMemoryUsagePercentage,
    166       cc::switches::kNumRasterThreads,
    167       cc::switches::kShowCompositedLayerBorders,
    168       cc::switches::kShowFPSCounter,
    169       cc::switches::kShowNonOccludingRects,
    170       cc::switches::kShowOccludingRects,
    171       cc::switches::kShowPropertyChangedRects,
    172       cc::switches::kShowReplicaScreenSpaceRects,
    173       cc::switches::kShowScreenSpaceRects,
    174       cc::switches::kShowSurfaceDamageRects,
    175       cc::switches::kSlowDownRasterScaleFactor,
    176       cc::switches::kTraceOverdraw,
    177       cc::switches::kUIDisablePartialSwap,
    178       cc::switches::kUIEnablePerTilePainting,
    179       cc::switches::kUseMapImage,
    180       chromeos::switches::kDbusStub,
    181       chromeos::switches::kDisableLoginAnimations,
    182       chromeos::switches::kDisableOobeAnimation,
    183       chromeos::switches::kHasChromeOSDiamondKey,
    184       chromeos::switches::kHasChromeOSKeyboard,
    185       chromeos::switches::kLoginProfile,
    186       chromeos::switches::kNaturalScrollDefault,
    187       chromeos::switches::kUseNewNetworkConfigurationHandlers,
    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.
    234 void 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.
    246 void 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.
    251 class 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 
    271 ChromeRestartRequest::ChromeRestartRequest(const std::string& command_line)
    272     : pid_(getpid()),
    273       command_line_(command_line) {}
    274 
    275 ChromeRestartRequest::~ChromeRestartRequest() {}
    276 
    277 void 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 
    311 void 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 
    322 std::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 
    342 void 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