| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 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/kiosk_mode/kiosk_mode_screensaver.h" | |
| 6 | |
| 7 #include "ash/screensaver/screensaver_view.h" | |
| 8 #include "base/bind.h" | |
| 9 #include "base/callback.h" | |
| 10 #include "base/lazy_instance.h" | |
| 11 #include "base/logging.h" | |
| 12 #include "chrome/browser/browser_process.h" | |
| 13 #include "chrome/browser/chrome_notification_types.h" | |
| 14 #include "chrome/browser/chromeos/kiosk_mode/kiosk_mode_settings.h" | |
| 15 #include "chrome/browser/chromeos/login/existing_user_controller.h" | |
| 16 #include "chrome/browser/chromeos/login/signin_specifics.h" | |
| 17 #include "chrome/browser/chromeos/login/ui/login_display_host_impl.h" | |
| 18 #include "chrome/browser/chromeos/policy/app_pack_updater.h" | |
| 19 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h" | |
| 20 #include "chrome/browser/chromeos/profiles/profile_helper.h" | |
| 21 #include "chrome/browser/extensions/extension_garbage_collector_chromeos.h" | |
| 22 #include "chrome/browser/extensions/extension_service.h" | |
| 23 #include "chrome/browser/extensions/sandboxed_unpacker.h" | |
| 24 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h" | |
| 25 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h" | |
| 26 #include "chromeos/login/auth/user_context.h" | |
| 27 #include "chromeos/login/login_state.h" | |
| 28 #include "chromeos/login/user_names.h" | |
| 29 #include "components/user_manager/user_type.h" | |
| 30 #include "content/public/browser/browser_thread.h" | |
| 31 #include "content/public/browser/notification_service.h" | |
| 32 #include "extensions/browser/extension_system.h" | |
| 33 #include "extensions/common/extension.h" | |
| 34 #include "extensions/common/file_util.h" | |
| 35 #include "ui/wm/core/user_activity_detector.h" | |
| 36 | |
| 37 using extensions::Extension; | |
| 38 using extensions::ExtensionGarbageCollectorChromeOS; | |
| 39 using extensions::SandboxedUnpacker; | |
| 40 | |
| 41 namespace chromeos { | |
| 42 | |
| 43 namespace { | |
| 44 | |
| 45 ExtensionService* GetDefaultExtensionService() { | |
| 46 Profile* default_profile = ProfileHelper::GetSigninProfile(); | |
| 47 if (!default_profile) | |
| 48 return NULL; | |
| 49 return extensions::ExtensionSystem::Get( | |
| 50 default_profile)->extension_service(); | |
| 51 } | |
| 52 | |
| 53 ExtensionGarbageCollectorChromeOS* GetDefaultExtensionGarbageCollector() { | |
| 54 Profile* default_profile = ProfileHelper::GetSigninProfile(); | |
| 55 if (!default_profile) | |
| 56 return NULL; | |
| 57 return ExtensionGarbageCollectorChromeOS::Get(default_profile); | |
| 58 } | |
| 59 | |
| 60 typedef base::Callback<void( | |
| 61 scoped_refptr<Extension>, | |
| 62 const base::FilePath&)> UnpackCallback; | |
| 63 | |
| 64 class ScreensaverUnpackerClient | |
| 65 : public extensions::SandboxedUnpackerClient { | |
| 66 public: | |
| 67 ScreensaverUnpackerClient(const base::FilePath& crx_path, | |
| 68 const UnpackCallback& unpacker_callback) | |
| 69 : crx_path_(crx_path), | |
| 70 unpack_callback_(unpacker_callback) {} | |
| 71 | |
| 72 virtual void OnUnpackSuccess(const base::FilePath& temp_dir, | |
| 73 const base::FilePath& extension_root, | |
| 74 const base::DictionaryValue* original_manifest, | |
| 75 const Extension* extension, | |
| 76 const SkBitmap& install_icon) override; | |
| 77 virtual void OnUnpackFailure(const base::string16& error) override; | |
| 78 | |
| 79 protected: | |
| 80 virtual ~ScreensaverUnpackerClient() {} | |
| 81 | |
| 82 private: | |
| 83 void LoadScreensaverExtension( | |
| 84 const base::FilePath& extension_base_path, | |
| 85 const base::FilePath& screensaver_extension_path); | |
| 86 | |
| 87 void NotifyAppPackOfDamagedFile(); | |
| 88 | |
| 89 base::FilePath crx_path_; | |
| 90 UnpackCallback unpack_callback_; | |
| 91 | |
| 92 DISALLOW_COPY_AND_ASSIGN(ScreensaverUnpackerClient); | |
| 93 }; | |
| 94 | |
| 95 void ScreensaverUnpackerClient::OnUnpackSuccess( | |
| 96 const base::FilePath& temp_dir, | |
| 97 const base::FilePath& extension_root, | |
| 98 const base::DictionaryValue* original_manifest, | |
| 99 const Extension* extension, | |
| 100 const SkBitmap& install_icon) { | |
| 101 content::BrowserThread::PostTask( | |
| 102 content::BrowserThread::FILE, | |
| 103 FROM_HERE, | |
| 104 base::Bind(&ScreensaverUnpackerClient::LoadScreensaverExtension, | |
| 105 this, | |
| 106 temp_dir, | |
| 107 extension_root)); | |
| 108 } | |
| 109 | |
| 110 void ScreensaverUnpackerClient::OnUnpackFailure(const base::string16& error) { | |
| 111 LOG(ERROR) << "Couldn't unpack screensaver extension. Error: " << error; | |
| 112 NotifyAppPackOfDamagedFile(); | |
| 113 } | |
| 114 | |
| 115 void ScreensaverUnpackerClient::LoadScreensaverExtension( | |
| 116 const base::FilePath& extension_base_path, | |
| 117 const base::FilePath& screensaver_extension_path) { | |
| 118 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); | |
| 119 | |
| 120 // TODO(rkc): This is a HACK, please remove this method from extension | |
| 121 // service once this code is deprecated. See crbug.com/280363 | |
| 122 ExtensionGarbageCollectorChromeOS* gc = GetDefaultExtensionGarbageCollector(); | |
| 123 if (gc) | |
| 124 gc->disable_garbage_collection(); | |
| 125 | |
| 126 std::string error; | |
| 127 scoped_refptr<Extension> screensaver_extension = | |
| 128 extensions::file_util::LoadExtension(screensaver_extension_path, | |
| 129 extensions::Manifest::COMPONENT, | |
| 130 Extension::NO_FLAGS, | |
| 131 &error); | |
| 132 if (!screensaver_extension.get()) { | |
| 133 LOG(ERROR) << "Could not load screensaver extension from: " | |
| 134 << screensaver_extension_path.value() << " due to: " << error; | |
| 135 NotifyAppPackOfDamagedFile(); | |
| 136 return; | |
| 137 } | |
| 138 | |
| 139 content::BrowserThread::PostTask( | |
| 140 content::BrowserThread::UI, | |
| 141 FROM_HERE, | |
| 142 base::Bind( | |
| 143 unpack_callback_, | |
| 144 screensaver_extension, | |
| 145 extension_base_path)); | |
| 146 } | |
| 147 | |
| 148 void ScreensaverUnpackerClient::NotifyAppPackOfDamagedFile() { | |
| 149 if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) { | |
| 150 content::BrowserThread::PostTask( | |
| 151 content::BrowserThread::UI, FROM_HERE, | |
| 152 base::Bind(&ScreensaverUnpackerClient::NotifyAppPackOfDamagedFile, | |
| 153 this)); | |
| 154 return; | |
| 155 } | |
| 156 | |
| 157 policy::BrowserPolicyConnectorChromeOS* connector = | |
| 158 g_browser_process->platform_part()->browser_policy_connector_chromeos(); | |
| 159 policy::AppPackUpdater* updater = connector->GetAppPackUpdater(); | |
| 160 if (updater) | |
| 161 updater->OnDamagedFileDetected(crx_path_); | |
| 162 } | |
| 163 | |
| 164 } // namespace | |
| 165 | |
| 166 KioskModeScreensaver::KioskModeScreensaver() | |
| 167 : weak_ptr_factory_(this) { | |
| 168 chromeos::KioskModeSettings* kiosk_mode_settings = | |
| 169 chromeos::KioskModeSettings::Get(); | |
| 170 | |
| 171 if (kiosk_mode_settings->is_initialized()) { | |
| 172 GetScreensaverCrxPath(); | |
| 173 } else { | |
| 174 kiosk_mode_settings->Initialize(base::Bind( | |
| 175 &KioskModeScreensaver::GetScreensaverCrxPath, | |
| 176 weak_ptr_factory_.GetWeakPtr())); | |
| 177 } | |
| 178 } | |
| 179 | |
| 180 KioskModeScreensaver::~KioskModeScreensaver() { | |
| 181 // If we are shutting down the system might already be gone and we shouldn't | |
| 182 // do anything (see crbug.com/288216). | |
| 183 if (!g_browser_process || g_browser_process->IsShuttingDown()) | |
| 184 return; | |
| 185 | |
| 186 // If the extension was unpacked. | |
| 187 if (!extension_base_path_.empty()) { | |
| 188 // TODO(rkc): This is a HACK, please remove this method from extension | |
| 189 // service once this code is deprecated. See crbug.com/280363 | |
| 190 ExtensionGarbageCollectorChromeOS* gc = | |
| 191 GetDefaultExtensionGarbageCollector(); | |
| 192 if (gc) | |
| 193 gc->enable_garbage_collection(); | |
| 194 | |
| 195 // Delete it. | |
| 196 content::BrowserThread::PostTask( | |
| 197 content::BrowserThread::FILE, | |
| 198 FROM_HERE, | |
| 199 base::Bind( | |
| 200 &extensions::file_util::DeleteFile, extension_base_path_, true)); | |
| 201 } | |
| 202 | |
| 203 // In case we're shutting down without ever triggering the active | |
| 204 // notification and/or logging in. | |
| 205 wm::UserActivityDetector* user_activity_detector = | |
| 206 wm::UserActivityDetector::Get(); | |
| 207 if (user_activity_detector && user_activity_detector->HasObserver(this)) | |
| 208 user_activity_detector->RemoveObserver(this); | |
| 209 } | |
| 210 | |
| 211 void KioskModeScreensaver::GetScreensaverCrxPath() { | |
| 212 chromeos::KioskModeSettings::Get()->GetScreensaverPath( | |
| 213 base::Bind(&KioskModeScreensaver::ScreensaverPathCallback, | |
| 214 weak_ptr_factory_.GetWeakPtr())); | |
| 215 } | |
| 216 | |
| 217 void KioskModeScreensaver::ScreensaverPathCallback( | |
| 218 const base::FilePath& screensaver_crx) { | |
| 219 if (screensaver_crx.empty()) | |
| 220 return; | |
| 221 | |
| 222 ExtensionService* extension_service = GetDefaultExtensionService(); | |
| 223 if (!extension_service) | |
| 224 return; | |
| 225 base::FilePath extensions_dir = extension_service->install_directory(); | |
| 226 scoped_refptr<SandboxedUnpacker> screensaver_unpacker( | |
| 227 new SandboxedUnpacker( | |
| 228 screensaver_crx, | |
| 229 extensions::Manifest::COMPONENT, | |
| 230 Extension::NO_FLAGS, | |
| 231 extensions_dir, | |
| 232 content::BrowserThread::GetMessageLoopProxyForThread( | |
| 233 content::BrowserThread::FILE).get(), | |
| 234 new ScreensaverUnpackerClient( | |
| 235 screensaver_crx, | |
| 236 base::Bind( | |
| 237 &KioskModeScreensaver::SetupScreensaver, | |
| 238 weak_ptr_factory_.GetWeakPtr())))); | |
| 239 | |
| 240 // Fire off the unpacker on the file thread; don't need it to return. | |
| 241 content::BrowserThread::PostTask( | |
| 242 content::BrowserThread::FILE, | |
| 243 FROM_HERE, | |
| 244 base::Bind( | |
| 245 &SandboxedUnpacker::Start, screensaver_unpacker.get())); | |
| 246 } | |
| 247 | |
| 248 void KioskModeScreensaver::SetupScreensaver( | |
| 249 scoped_refptr<Extension> extension, | |
| 250 const base::FilePath& extension_base_path) { | |
| 251 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
| 252 extension_base_path_ = extension_base_path; | |
| 253 | |
| 254 // If the user is already logged in, don't need to display the screensaver. | |
| 255 if (chromeos::LoginState::Get()->IsUserLoggedIn()) | |
| 256 return; | |
| 257 | |
| 258 wm::UserActivityDetector::Get()->AddObserver(this); | |
| 259 | |
| 260 ExtensionService* extension_service = GetDefaultExtensionService(); | |
| 261 // Add the extension to the extension service and display the screensaver. | |
| 262 if (extension_service) { | |
| 263 extension_service->AddExtension(extension.get()); | |
| 264 ash::ShowScreensaver( | |
| 265 extensions::AppLaunchInfo::GetFullLaunchURL(extension.get())); | |
| 266 } else { | |
| 267 LOG(ERROR) << "Couldn't get extension system. Unable to load screensaver!"; | |
| 268 ShutdownKioskModeScreensaver(); | |
| 269 } | |
| 270 } | |
| 271 | |
| 272 void KioskModeScreensaver::OnUserActivity(const ui::Event* event) { | |
| 273 // We don't want to handle further user notifications; we'll either login | |
| 274 // the user and close out or or at least close the screensaver. | |
| 275 wm::UserActivityDetector::Get()->RemoveObserver(this); | |
| 276 | |
| 277 // Find the retail mode login page. | |
| 278 if (LoginDisplayHostImpl::default_host()) { | |
| 279 LoginDisplayHostImpl* webui_host = | |
| 280 static_cast<LoginDisplayHostImpl*>( | |
| 281 LoginDisplayHostImpl::default_host()); | |
| 282 OobeUI* oobe_ui = webui_host->GetOobeUI(); | |
| 283 | |
| 284 // Show the login spinner. | |
| 285 if (oobe_ui) | |
| 286 oobe_ui->ShowRetailModeLoginSpinner(); | |
| 287 | |
| 288 // Close the screensaver, our login spinner is already showing. | |
| 289 ash::CloseScreensaver(); | |
| 290 | |
| 291 // Log us in. | |
| 292 ExistingUserController* controller = | |
| 293 ExistingUserController::current_controller(); | |
| 294 if (controller && !chromeos::LoginState::Get()->IsUserLoggedIn()) { | |
| 295 controller->Login(UserContext(user_manager::USER_TYPE_RETAIL_MODE, | |
| 296 chromeos::login::kRetailModeUserName), | |
| 297 SigninSpecifics()); | |
| 298 } | |
| 299 } else { | |
| 300 // No default host for the WebUiLoginDisplay means that we're already in the | |
| 301 // process of logging in - shut down screensaver and do nothing else. | |
| 302 ash::CloseScreensaver(); | |
| 303 } | |
| 304 | |
| 305 ShutdownKioskModeScreensaver(); | |
| 306 } | |
| 307 | |
| 308 static KioskModeScreensaver* g_kiosk_mode_screensaver = NULL; | |
| 309 | |
| 310 void InitializeKioskModeScreensaver() { | |
| 311 if (g_kiosk_mode_screensaver) { | |
| 312 LOG(WARNING) << "Screensaver was already initialized"; | |
| 313 return; | |
| 314 } | |
| 315 | |
| 316 g_kiosk_mode_screensaver = new KioskModeScreensaver(); | |
| 317 } | |
| 318 | |
| 319 void ShutdownKioskModeScreensaver() { | |
| 320 delete g_kiosk_mode_screensaver; | |
| 321 g_kiosk_mode_screensaver = NULL; | |
| 322 } | |
| 323 | |
| 324 } // namespace chromeos | |
| OLD | NEW |