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/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/chromeos/login/users/user_manager.h"
     26 #include "chrome/browser/lifetime/application_lifetime.h"
     27 #include "chrome/common/chrome_constants.h"
     28 #include "chrome/common/chrome_paths.h"
     29 #include "chrome/common/chrome_switches.h"
     30 #include "chrome/common/url_constants.h"
     31 #include "chromeos/chromeos_switches.h"
     32 #include "chromeos/dbus/dbus_thread_manager.h"
     33 #include "chromeos/dbus/session_manager_client.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/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|;
     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::kDisableAcceleratedOverflowScroll,
     75     ::switches::kDisableAcceleratedVideoDecode,
     76     ::switches::kDisableDelegatedRenderer,
     77     ::switches::kDisableDistanceFieldText,
     78     ::switches::kDisableFastTextAutosizing,
     79     ::switches::kDisableGpuShaderDiskCache,
     80     ::switches::kDisableGpuWatchdog,
     81     ::switches::kDisableGpuCompositing,
     82     ::switches::kDisableGpuRasterization,
     83     ::switches::kDisableImplSidePainting,
     84     ::switches::kDisableLowResTiling,
     85     ::switches::kDisableMediaSource,
     86     ::switches::kDisablePrefixedEncryptedMedia,
     87     ::switches::kDisablePanelFitting,
     88     ::switches::kDisableRepaintAfterLayout,
     89     ::switches::kDisableSeccompFilterSandbox,
     90     ::switches::kDisableSetuidSandbox,
     91     ::switches::kDisableThreadedCompositing,
     92     ::switches::kDisableTouchDragDrop,
     93     ::switches::kDisableTouchEditing,
     94     ::switches::kDisableAcceleratedFixedRootBackground,
     95     ::switches::kDisableZeroCopy,
     96     ::switches::kEnableAcceleratedFixedRootBackground,
     97     ::switches::kEnableAcceleratedOverflowScroll,
     98     ::switches::kEnableBeginFrameScheduling,
     99     ::switches::kEnableCompositingForFixedPosition,
    100     ::switches::kEnableDelegatedRenderer,
    101     ::switches::kEnableEncryptedMedia,
    102     ::switches::kEnableFastTextAutosizing,
    103     ::switches::kEnableGestureTapHighlight,
    104     ::switches::kDisableGestureTapHighlight,
    105     ::switches::kDisableGpuSandbox,
    106     ::switches::kDisableDeferredFilters,
    107     ::switches::kEnableContainerCulling,
    108     ::switches::kEnableDistanceFieldText,
    109     ::switches::kEnableGpuRasterization,
    110     ::switches::kEnableImplSidePainting,
    111     ::switches::kEnableLogging,
    112     ::switches::kEnableLowResTiling,
    113     ::switches::kEnableOneCopy,
    114     ::switches::kEnablePinch,
    115     ::switches::kEnableRepaintAfterLayout,
    116     ::switches::kEnableThreadedCompositing,
    117     ::switches::kEnableTouchDragDrop,
    118     ::switches::kEnableTouchEditing,
    119     ::switches::kEnableViewport,
    120     ::switches::kEnableViewportMeta,
    121     ::switches::kEnableZeroCopy,
    122     ::switches::kMainFrameResizesAreOrientationChanges,
    123     ::switches::kForceDeviceScaleFactor,
    124     ::switches::kForceGpuRasterization,
    125     ::switches::kGpuStartupDialog,
    126     ::switches::kGpuSandboxAllowSysVShm,
    127     ::switches::kGpuSandboxFailuresFatal,
    128     ::switches::kGpuSandboxStartAfterInitialization,
    129     ::switches::kIgnoreResolutionLimitsForAcceleratedVideoDecode,
    130     ::switches::kNoSandbox,
    131     ::switches::kNumRasterThreads,
    132     ::switches::kPpapiFlashArgs,
    133     ::switches::kPpapiFlashPath,
    134     ::switches::kPpapiFlashVersion,
    135     ::switches::kPpapiInProcess,
    136     ::switches::kRendererStartupDialog,
    137     ::switches::kEnableShareGroupAsyncTextureUpload,
    138     ::switches::kTabCaptureUpscaleQuality,
    139     ::switches::kTabCaptureDownscaleQuality,
    140 #if defined(USE_XI2_MT)
    141     ::switches::kTouchCalibration,
    142 #endif
    143     ::switches::kTouchDevices,
    144     ::switches::kTouchEvents,
    145     ::switches::kUIDisableThreadedCompositing,
    146     ::switches::kUIPrioritizeInGpuProcess,
    147 #if defined(USE_CRAS)
    148     ::switches::kUseCras,
    149 #endif
    150     ::switches::kUseDiscardableMemory,
    151     ::switches::kUseGL,
    152     ::switches::kUserDataDir,
    153     ::switches::kV,
    154     ::switches::kVModule,
    155     ::switches::kEnableWebGLDraftExtensions,
    156     ::switches::kEnableWebGLImageChromium,
    157 #if defined(ENABLE_WEBRTC)
    158     ::switches::kDisableAudioTrackProcessing,
    159     ::switches::kDisableWebRtcHWDecoding,
    160     ::switches::kDisableWebRtcHWEncoding,
    161     ::switches::kEnableWebRtcHWVp8Encoding,
    162 #endif
    163 #if defined(USE_OZONE)
    164     ::switches::kOzonePlatform,
    165 #endif
    166     app_list::switches::kDisableSyncAppList,
    167     app_list::switches::kEnableSyncAppList,
    168     ash::switches::kAshDefaultWallpaperLarge,
    169     ash::switches::kAshDefaultWallpaperSmall,
    170     ash::switches::kAshGuestWallpaperLarge,
    171     ash::switches::kAshGuestWallpaperSmall,
    172     ash::switches::kAshHostWindowBounds,
    173     ash::switches::kAshTouchHud,
    174     ash::switches::kAuraLegacyPowerButton,
    175     // Please keep these in alphabetical order. Non-UI Compositor switches
    176     // here should also be added to
    177     // content/browser/renderer_host/render_process_host_impl.cc.
    178     cc::switches::kCompositeToMailbox,
    179     cc::switches::kDisableCompositedAntialiasing,
    180     cc::switches::kDisableCompositorTouchHitTesting,
    181     cc::switches::kDisableMainFrameBeforeActivation,
    182     cc::switches::kDisableMainFrameBeforeDraw,
    183     cc::switches::kDisablePinchVirtualViewport,
    184     cc::switches::kDisableThreadedAnimation,
    185     cc::switches::kEnableGpuBenchmarking,
    186     cc::switches::kEnablePinchVirtualViewport,
    187     cc::switches::kEnableMainFrameBeforeActivation,
    188     cc::switches::kEnableTopControlsPositionCalculation,
    189     cc::switches::kMaxTilesForInterestArea,
    190     cc::switches::kMaxUnusedResourceMemoryUsagePercentage,
    191     cc::switches::kShowCompositedLayerBorders,
    192     cc::switches::kShowFPSCounter,
    193     cc::switches::kShowLayerAnimationBounds,
    194     cc::switches::kShowNonOccludingRects,
    195     cc::switches::kShowOccludingRects,
    196     cc::switches::kShowPropertyChangedRects,
    197     cc::switches::kShowReplicaScreenSpaceRects,
    198     cc::switches::kShowScreenSpaceRects,
    199     cc::switches::kShowSurfaceDamageRects,
    200     cc::switches::kSlowDownRasterScaleFactor,
    201     cc::switches::kUIDisablePartialSwap,
    202     chromeos::switches::kConsumerDeviceManagementUrl,
    203     chromeos::switches::kDbusStub,
    204     chromeos::switches::kDisableLoginAnimations,
    205     chromeos::switches::kEnableConsumerManagement,
    206     chromeos::switches::kEnterpriseEnableForcedReEnrollment,
    207     chromeos::switches::kHasChromeOSDiamondKey,
    208     chromeos::switches::kHasChromeOSKeyboard,
    209     chromeos::switches::kLoginProfile,
    210     chromeos::switches::kNaturalScrollDefault,
    211     chromeos::switches::kSystemInDevMode,
    212     policy::switches::kDeviceManagementUrl,
    213     ::switches::kEnableBrowserTextSubpixelPositioning,
    214     ::switches::kEnableWebkitTextSubpixelPositioning,
    215     wm::switches::kWindowAnimationsDisabled,
    216   };
    217   command_line->CopySwitchesFrom(base_command_line,
    218                                  kForwardSwitches,
    219                                  arraysize(kForwardSwitches));
    220 
    221   if (start_url.is_valid())
    222     command_line->AppendArg(start_url.spec());
    223 
    224   for (base::DictionaryValue::Iterator it(new_switches);
    225        !it.IsAtEnd();
    226        it.Advance()) {
    227     std::string value;
    228     CHECK(it.value().GetAsString(&value));
    229     command_line->AppendSwitchASCII(it.key(), value);
    230   }
    231 
    232   std::string cmd_line_str = command_line->GetCommandLineString();
    233   // Special workaround for the arguments that should be quoted.
    234   // Copying switches won't be needed when Guest mode won't need restart
    235   // http://crosbug.com/6924
    236   if (base_command_line.HasSwitch(::switches::kRegisterPepperPlugins)) {
    237     cmd_line_str += base::StringPrintf(
    238         kSwitchFormatString,
    239         ::switches::kRegisterPepperPlugins,
    240         base_command_line.GetSwitchValueNative(
    241             ::switches::kRegisterPepperPlugins).c_str());
    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     bool is_oobe_completed,
    340     const CommandLine& base_command_line,
    341     CommandLine* command_line) {
    342   base::DictionaryValue otr_switches;
    343   otr_switches.SetString(switches::kGuestSession, std::string());
    344   otr_switches.SetString(::switches::kIncognito, std::string());
    345   otr_switches.SetString(::switches::kLoggingLevel, kGuestModeLoggingLevel);
    346   otr_switches.SetString(switches::kLoginUser, UserManager::kGuestUserName);
    347 
    348   // Override the home page.
    349   otr_switches.SetString(::switches::kHomePage,
    350                          GURL(chrome::kChromeUINewTabURL).spec());
    351 
    352   // If OOBE is not finished yet, lock down the guest session to not allow
    353   // surfing the web. Guest mode is still useful to inspect logs and run network
    354   // diagnostics.
    355   if (!is_oobe_completed)
    356     otr_switches.SetString(switches::kOobeGuestSession, std::string());
    357 
    358   return DeriveCommandLine(start_url,
    359                            base_command_line,
    360                            otr_switches,
    361                            command_line);
    362 }
    363 
    364 void RestartChrome(const std::string& command_line) {
    365   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    366   BootTimesLoader::Get()->set_restart_requested();
    367 
    368   static bool restart_requested = false;
    369   if (restart_requested) {
    370     NOTREACHED() << "Request chrome restart for more than once.";
    371   }
    372   restart_requested = true;
    373 
    374   if (!base::SysInfo::IsRunningOnChromeOS()) {
    375     // Relaunch chrome without session manager on dev box.
    376     ReLaunch(command_line);
    377     return;
    378   }
    379 
    380   // ChromeRestartRequest deletes itself after request sent to session manager.
    381   (new ChromeRestartRequest(command_line))->Start();
    382 }
    383 
    384 }  // namespace chromeos
    385