OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/chromeos/app_mode/startup_app_launcher.h" | 5 #include "chrome/browser/chromeos/app_mode/startup_app_launcher.h" |
6 | 6 |
7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
8 #include "base/files/file_path.h" | 8 #include "base/files/file_path.h" |
9 #include "base/json/json_file_value_serializer.h" | 9 #include "base/json/json_file_value_serializer.h" |
10 #include "base/path_service.h" | 10 #include "base/path_service.h" |
11 #include "base/time/time.h" | 11 #include "base/time/time.h" |
12 #include "base/values.h" | 12 #include "base/values.h" |
13 #include "chrome/browser/chrome_notification_types.h" | 13 #include "chrome/browser/chrome_notification_types.h" |
14 #include "chrome/browser/chromeos/app_mode/app_session_lifetime.h" | 14 #include "chrome/browser/chromeos/app_mode/app_session_lifetime.h" |
15 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h" | 15 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h" |
16 #include "chrome/browser/chromeos/app_mode/kiosk_diagnosis_runner.h" | 16 #include "chrome/browser/chromeos/app_mode/kiosk_diagnosis_runner.h" |
17 #include "chrome/browser/chromeos/login/session/user_session_manager.h" | 17 #include "chrome/browser/chromeos/login/session/user_session_manager.h" |
18 #include "chrome/browser/chromeos/login/users/user_manager.h" | 18 #include "chrome/browser/chromeos/login/users/user_manager.h" |
19 #include "chrome/browser/extensions/extension_service.h" | 19 #include "chrome/browser/extensions/extension_service.h" |
| 20 #include "chrome/browser/extensions/install_tracker.h" |
| 21 #include "chrome/browser/extensions/install_tracker_factory.h" |
20 #include "chrome/browser/extensions/updater/extension_updater.h" | 22 #include "chrome/browser/extensions/updater/extension_updater.h" |
21 #include "chrome/browser/extensions/webstore_startup_installer.h" | |
22 #include "chrome/browser/lifetime/application_lifetime.h" | 23 #include "chrome/browser/lifetime/application_lifetime.h" |
23 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h" | 24 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h" |
24 #include "chrome/browser/signin/signin_manager_factory.h" | 25 #include "chrome/browser/signin/signin_manager_factory.h" |
25 #include "chrome/browser/ui/extensions/application_launch.h" | 26 #include "chrome/browser/ui/extensions/application_launch.h" |
26 #include "chrome/common/chrome_paths.h" | 27 #include "chrome/common/chrome_paths.h" |
27 #include "chrome/common/chrome_switches.h" | 28 #include "chrome/common/chrome_switches.h" |
28 #include "chrome/common/chrome_version_info.h" | 29 #include "chrome/common/chrome_version_info.h" |
29 #include "chrome/common/extensions/manifest_url_handler.h" | 30 #include "chrome/common/extensions/manifest_url_handler.h" |
30 #include "components/signin/core/browser/profile_oauth2_token_service.h" | 31 #include "components/signin/core/browser/profile_oauth2_token_service.h" |
31 #include "components/signin/core/browser/signin_manager.h" | 32 #include "components/signin/core/browser/signin_manager.h" |
32 #include "content/public/browser/browser_thread.h" | 33 #include "content/public/browser/browser_thread.h" |
33 #include "content/public/browser/notification_service.h" | 34 #include "content/public/browser/notification_service.h" |
34 #include "extensions/browser/extension_system.h" | 35 #include "extensions/browser/extension_system.h" |
35 #include "extensions/common/extension.h" | 36 #include "extensions/common/extension.h" |
36 #include "extensions/common/manifest_handlers/kiosk_mode_info.h" | 37 #include "extensions/common/manifest_handlers/kiosk_mode_info.h" |
37 #include "extensions/common/manifest_handlers/offline_enabled_info.h" | 38 #include "extensions/common/manifest_handlers/offline_enabled_info.h" |
38 #include "google_apis/gaia/gaia_auth_consumer.h" | 39 #include "google_apis/gaia/gaia_auth_consumer.h" |
39 #include "google_apis/gaia/gaia_constants.h" | 40 #include "google_apis/gaia/gaia_constants.h" |
40 #include "net/base/load_flags.h" | 41 #include "net/base/load_flags.h" |
41 #include "net/url_request/url_fetcher.h" | 42 #include "net/url_request/url_fetcher.h" |
42 #include "net/url_request/url_fetcher_delegate.h" | 43 #include "net/url_request/url_fetcher_delegate.h" |
43 #include "net/url_request/url_request_context_getter.h" | 44 #include "net/url_request/url_request_context_getter.h" |
44 #include "net/url_request/url_request_status.h" | 45 #include "net/url_request/url_request_status.h" |
45 #include "url/gurl.h" | 46 #include "url/gurl.h" |
46 | 47 |
47 using content::BrowserThread; | 48 using content::BrowserThread; |
48 using extensions::Extension; | 49 using extensions::Extension; |
49 using extensions::WebstoreStartupInstaller; | |
50 | 50 |
51 namespace chromeos { | 51 namespace chromeos { |
52 | 52 |
53 namespace { | 53 namespace { |
54 | 54 |
55 const char kOAuthRefreshToken[] = "refresh_token"; | 55 const char kOAuthRefreshToken[] = "refresh_token"; |
56 const char kOAuthClientId[] = "client_id"; | 56 const char kOAuthClientId[] = "client_id"; |
57 const char kOAuthClientSecret[] = "client_secret"; | 57 const char kOAuthClientSecret[] = "client_secret"; |
58 | 58 |
59 const base::FilePath::CharType kOAuthFileName[] = | 59 const base::FilePath::CharType kOAuthFileName[] = |
60 FILE_PATH_LITERAL("kiosk_auth"); | 60 FILE_PATH_LITERAL("kiosk_auth"); |
61 | 61 |
62 const int kMaxInstallAttempt = 5; | 62 const int kMaxLaunchAttempt = 5; |
63 | 63 |
64 } // namespace | 64 } // namespace |
65 | 65 |
66 StartupAppLauncher::StartupAppLauncher(Profile* profile, | 66 StartupAppLauncher::StartupAppLauncher(Profile* profile, |
67 const std::string& app_id, | 67 const std::string& app_id, |
68 bool diagnostic_mode, | 68 bool diagnostic_mode, |
69 StartupAppLauncher::Delegate* delegate) | 69 StartupAppLauncher::Delegate* delegate) |
70 : profile_(profile), | 70 : profile_(profile), |
71 app_id_(app_id), | 71 app_id_(app_id), |
72 diagnostic_mode_(diagnostic_mode), | 72 diagnostic_mode_(diagnostic_mode), |
73 delegate_(delegate), | 73 delegate_(delegate), |
74 network_ready_handled_(false), | 74 network_ready_handled_(false), |
75 install_attempt_(0), | 75 launch_attempt_(0), |
76 ready_to_launch_(false) { | 76 ready_to_launch_(false), |
| 77 wait_for_crx_update_(false) { |
77 DCHECK(profile_); | 78 DCHECK(profile_); |
78 DCHECK(Extension::IdIsValid(app_id_)); | 79 DCHECK(Extension::IdIsValid(app_id_)); |
| 80 KioskAppManager::Get()->AddObserver(this); |
79 } | 81 } |
80 | 82 |
81 StartupAppLauncher::~StartupAppLauncher() { | 83 StartupAppLauncher::~StartupAppLauncher() { |
| 84 KioskAppManager::Get()->RemoveObserver(this); |
| 85 |
82 // StartupAppLauncher can be deleted at anytime during the launch process | 86 // StartupAppLauncher can be deleted at anytime during the launch process |
83 // through a user bailout shortcut. | 87 // through a user bailout shortcut. |
84 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_) | 88 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_) |
85 ->RemoveObserver(this); | 89 ->RemoveObserver(this); |
86 } | 90 } |
87 | 91 |
88 void StartupAppLauncher::Initialize() { | 92 void StartupAppLauncher::Initialize() { |
89 StartLoadingOAuthFile(); | 93 StartLoadingOAuthFile(); |
90 } | 94 } |
91 | 95 |
92 void StartupAppLauncher::ContinueWithNetworkReady() { | 96 void StartupAppLauncher::ContinueWithNetworkReady() { |
93 // Starts install if it is not started. | |
94 if (!network_ready_handled_) { | 97 if (!network_ready_handled_) { |
95 network_ready_handled_ = true; | 98 network_ready_handled_ = true; |
96 MaybeInstall(); | 99 // The network might not be ready when KioskAppManager tries to update |
| 100 // external cache initially. Update the external cache now that the network |
| 101 // is ready for sure. |
| 102 wait_for_crx_update_ = true; |
| 103 KioskAppManager::Get()->UpdateExternalCache(); |
97 } | 104 } |
98 } | 105 } |
99 | 106 |
100 void StartupAppLauncher::StartLoadingOAuthFile() { | 107 void StartupAppLauncher::StartLoadingOAuthFile() { |
101 delegate_->OnLoadingOAuthFile(); | 108 delegate_->OnLoadingOAuthFile(); |
102 | 109 |
103 KioskOAuthParams* auth_params = new KioskOAuthParams(); | 110 KioskOAuthParams* auth_params = new KioskOAuthParams(); |
104 BrowserThread::PostBlockingPoolTaskAndReply( | 111 BrowserThread::PostBlockingPoolTaskAndReply( |
105 FROM_HERE, | 112 FROM_HERE, |
106 base::Bind(&StartupAppLauncher::LoadOAuthFileOnBlockingPool, | 113 base::Bind(&StartupAppLauncher::LoadOAuthFileOnBlockingPool, |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
145 } | 152 } |
146 | 153 |
147 // If we are restarting chrome (i.e. on crash), we need to initialize | 154 // If we are restarting chrome (i.e. on crash), we need to initialize |
148 // OAuth2TokenService as well. | 155 // OAuth2TokenService as well. |
149 InitializeTokenService(); | 156 InitializeTokenService(); |
150 } | 157 } |
151 | 158 |
152 void StartupAppLauncher::RestartLauncher() { | 159 void StartupAppLauncher::RestartLauncher() { |
153 // If the installer is still running in the background, we don't need to | 160 // If the installer is still running in the background, we don't need to |
154 // restart the launch process. We will just wait until it completes and | 161 // restart the launch process. We will just wait until it completes and |
155 // lunches the kiosk app. | 162 // launches the kiosk app. |
156 if (installer_ != NULL) { | 163 if (extensions::ExtensionSystem::Get(profile_) |
| 164 ->extension_service() |
| 165 ->pending_extension_manager() |
| 166 ->IsIdPending(app_id_)) { |
157 LOG(WARNING) << "Installer still running"; | 167 LOG(WARNING) << "Installer still running"; |
158 return; | 168 return; |
159 } | 169 } |
160 | 170 |
161 MaybeInitializeNetwork(); | 171 MaybeInitializeNetwork(); |
162 } | 172 } |
163 | 173 |
164 void StartupAppLauncher::MaybeInitializeNetwork() { | 174 void StartupAppLauncher::MaybeInitializeNetwork() { |
165 network_ready_handled_ = false; | 175 network_ready_handled_ = false; |
166 | 176 |
167 const Extension* extension = extensions::ExtensionSystem::Get(profile_)-> | 177 const Extension* extension = extensions::ExtensionSystem::Get(profile_)-> |
168 extension_service()->GetInstalledExtension(app_id_); | 178 extension_service()->GetInstalledExtension(app_id_); |
169 const bool requires_network = !extension || | 179 bool crx_cached = KioskAppManager::Get()->HasCachedCrx(app_id_); |
170 !extensions::OfflineEnabledInfo::IsOfflineEnabled(extension); | 180 const bool requires_network = |
| 181 (!extension && !crx_cached) || |
| 182 (extension && |
| 183 !extensions::OfflineEnabledInfo::IsOfflineEnabled(extension)); |
171 | 184 |
172 if (requires_network) { | 185 if (requires_network) { |
173 delegate_->InitializeNetwork(); | 186 delegate_->InitializeNetwork(); |
174 return; | 187 return; |
175 } | 188 } |
176 | 189 |
177 // Offline enabled app attempts update if network is ready. Otherwise, | 190 // Update the offline enabled crx cache if the network is ready; |
178 // go directly to launch. | 191 // or just install the app. |
179 if (delegate_->IsNetworkReady()) | 192 if (delegate_->IsNetworkReady()) |
180 ContinueWithNetworkReady(); | 193 ContinueWithNetworkReady(); |
181 else | 194 else |
182 OnReadyToLaunch(); | 195 BeginInstall(); |
183 } | 196 } |
184 | 197 |
185 void StartupAppLauncher::InitializeTokenService() { | 198 void StartupAppLauncher::InitializeTokenService() { |
186 delegate_->OnInitializingTokenService(); | 199 delegate_->OnInitializingTokenService(); |
187 | 200 |
188 ProfileOAuth2TokenService* profile_token_service = | 201 ProfileOAuth2TokenService* profile_token_service = |
189 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_); | 202 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_); |
190 SigninManagerBase* signin_manager = | 203 SigninManagerBase* signin_manager = |
191 SigninManagerFactory::GetForProfile(profile_); | 204 SigninManagerFactory::GetForProfile(profile_); |
192 const std::string primary_account_id = | 205 const std::string primary_account_id = |
(...skipping 28 matching lines...) Expand all Loading... |
221 ->RemoveObserver(this); | 234 ->RemoveObserver(this); |
222 MaybeInitializeNetwork(); | 235 MaybeInitializeNetwork(); |
223 } | 236 } |
224 | 237 |
225 void StartupAppLauncher::OnRefreshTokensLoaded() { | 238 void StartupAppLauncher::OnRefreshTokensLoaded() { |
226 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_) | 239 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_) |
227 ->RemoveObserver(this); | 240 ->RemoveObserver(this); |
228 MaybeInitializeNetwork(); | 241 MaybeInitializeNetwork(); |
229 } | 242 } |
230 | 243 |
| 244 void StartupAppLauncher::MaybeLaunchApp() { |
| 245 // Check if the app is offline enabled. |
| 246 const Extension* extension = extensions::ExtensionSystem::Get(profile_) |
| 247 ->extension_service() |
| 248 ->GetInstalledExtension(app_id_); |
| 249 DCHECK(extension); |
| 250 const bool offline_enabled = |
| 251 extensions::OfflineEnabledInfo::IsOfflineEnabled(extension); |
| 252 if (offline_enabled || delegate_->IsNetworkReady()) { |
| 253 BrowserThread::PostTask( |
| 254 BrowserThread::UI, |
| 255 FROM_HERE, |
| 256 base::Bind(&StartupAppLauncher::OnReadyToLaunch, AsWeakPtr())); |
| 257 } else { |
| 258 ++launch_attempt_; |
| 259 if (launch_attempt_ < kMaxLaunchAttempt) { |
| 260 BrowserThread::PostTask( |
| 261 BrowserThread::UI, |
| 262 FROM_HERE, |
| 263 base::Bind(&StartupAppLauncher::MaybeInitializeNetwork, AsWeakPtr())); |
| 264 return; |
| 265 } |
| 266 OnLaunchFailure(KioskAppLaunchError::UNABLE_TO_LAUNCH); |
| 267 } |
| 268 } |
| 269 |
| 270 void StartupAppLauncher::OnFinishCrxInstall(const std::string& extension_id, |
| 271 bool success) { |
| 272 if (extension_id != app_id_) |
| 273 return; |
| 274 |
| 275 extensions::InstallTracker* tracker = |
| 276 extensions::InstallTrackerFactory::GetForProfile(profile_); |
| 277 tracker->RemoveObserver(this); |
| 278 if (delegate_->IsShowingNetworkConfigScreen()) { |
| 279 LOG(WARNING) << "Showing network config screen"; |
| 280 return; |
| 281 } |
| 282 |
| 283 if (success) { |
| 284 MaybeLaunchApp(); |
| 285 return; |
| 286 } |
| 287 |
| 288 LOG(ERROR) << "Failed to install the kiosk application app_id: " |
| 289 << extension_id; |
| 290 OnLaunchFailure(KioskAppLaunchError::UNABLE_TO_INSTALL); |
| 291 } |
| 292 |
| 293 void StartupAppLauncher::OnKioskExtensionLoadedInCache( |
| 294 const std::string& app_id) { |
| 295 OnKioskAppDataLoadStatusChanged(app_id); |
| 296 } |
| 297 |
| 298 void StartupAppLauncher::OnKioskExtensionDownloadFailed( |
| 299 const std::string& app_id) { |
| 300 OnKioskAppDataLoadStatusChanged(app_id); |
| 301 } |
| 302 |
| 303 void StartupAppLauncher::OnKioskAppDataLoadStatusChanged( |
| 304 const std::string& app_id) { |
| 305 if (app_id != app_id_ || !wait_for_crx_update_) |
| 306 return; |
| 307 |
| 308 wait_for_crx_update_ = false; |
| 309 if (KioskAppManager::Get()->HasCachedCrx(app_id_)) |
| 310 BeginInstall(); |
| 311 else |
| 312 OnLaunchFailure(KioskAppLaunchError::UNABLE_TO_DOWNLOAD); |
| 313 } |
| 314 |
231 void StartupAppLauncher::LaunchApp() { | 315 void StartupAppLauncher::LaunchApp() { |
232 if (!ready_to_launch_) { | 316 if (!ready_to_launch_) { |
233 NOTREACHED(); | 317 NOTREACHED(); |
234 LOG(ERROR) << "LaunchApp() called but launcher is not initialized."; | 318 LOG(ERROR) << "LaunchApp() called but launcher is not initialized."; |
235 } | 319 } |
236 | 320 |
237 const Extension* extension = extensions::ExtensionSystem::Get(profile_)-> | 321 const Extension* extension = extensions::ExtensionSystem::Get(profile_)-> |
238 extension_service()->GetInstalledExtension(app_id_); | 322 extension_service()->GetInstalledExtension(app_id_); |
239 CHECK(extension); | 323 CHECK(extension); |
240 | 324 |
(...skipping 25 matching lines...) Expand all Loading... |
266 delegate_->OnLaunchSucceeded(); | 350 delegate_->OnLaunchSucceeded(); |
267 } | 351 } |
268 | 352 |
269 void StartupAppLauncher::OnLaunchFailure(KioskAppLaunchError::Error error) { | 353 void StartupAppLauncher::OnLaunchFailure(KioskAppLaunchError::Error error) { |
270 LOG(ERROR) << "App launch failed, error: " << error; | 354 LOG(ERROR) << "App launch failed, error: " << error; |
271 DCHECK_NE(KioskAppLaunchError::NONE, error); | 355 DCHECK_NE(KioskAppLaunchError::NONE, error); |
272 | 356 |
273 delegate_->OnLaunchFailed(error); | 357 delegate_->OnLaunchFailed(error); |
274 } | 358 } |
275 | 359 |
276 void StartupAppLauncher::MaybeInstall() { | |
277 delegate_->OnInstallingApp(); | |
278 | |
279 ExtensionService* extension_service = | |
280 extensions::ExtensionSystem::Get(profile_)->extension_service(); | |
281 if (!extension_service->GetInstalledExtension(app_id_)) { | |
282 BeginInstall(); | |
283 return; | |
284 } | |
285 | |
286 extensions::ExtensionUpdater::CheckParams check_params; | |
287 check_params.ids.push_back(app_id_); | |
288 check_params.install_immediately = true; | |
289 check_params.callback = | |
290 base::Bind(&StartupAppLauncher::OnUpdateCheckFinished, AsWeakPtr()); | |
291 extension_service->updater()->CheckNow(check_params); | |
292 } | |
293 | |
294 void StartupAppLauncher::OnUpdateCheckFinished() { | 360 void StartupAppLauncher::OnUpdateCheckFinished() { |
295 OnReadyToLaunch(); | 361 OnReadyToLaunch(); |
296 UpdateAppData(); | 362 UpdateAppData(); |
297 } | 363 } |
298 | 364 |
299 void StartupAppLauncher::BeginInstall() { | 365 void StartupAppLauncher::BeginInstall() { |
300 installer_ = new WebstoreStartupInstaller( | 366 KioskAppManager::Get()->InstallFromCache(app_id_); |
301 app_id_, | 367 if (extensions::ExtensionSystem::Get(profile_) |
302 profile_, | 368 ->extension_service() |
303 false, | 369 ->pending_extension_manager() |
304 base::Bind(&StartupAppLauncher::InstallCallback, AsWeakPtr())); | 370 ->IsIdPending(app_id_)) { |
305 installer_->BeginInstall(); | 371 delegate_->OnInstallingApp(); |
306 } | 372 // Observe the crx installation events. |
307 | 373 extensions::InstallTracker* tracker = |
308 void StartupAppLauncher::InstallCallback(bool success, | 374 extensions::InstallTrackerFactory::GetForProfile(profile_); |
309 const std::string& error) { | 375 tracker->AddObserver(this); |
310 installer_ = NULL; | |
311 if (delegate_->IsShowingNetworkConfigScreen()) { | |
312 LOG(WARNING) << "Showing network config screen"; | |
313 return; | 376 return; |
314 } | 377 } |
315 | 378 |
316 if (success) { | 379 if (extensions::ExtensionSystem::Get(profile_) |
317 // Finish initialization after the callback returns. | 380 ->extension_service() |
318 // So that the app finishes its installation. | 381 ->GetInstalledExtension(app_id_)) { |
319 BrowserThread::PostTask( | 382 // Launch the app. |
320 BrowserThread::UI, | 383 OnReadyToLaunch(); |
321 FROM_HERE, | 384 } else { |
322 base::Bind(&StartupAppLauncher::OnReadyToLaunch, | 385 // The extension is skipped for installation due to some error. |
323 AsWeakPtr())); | 386 OnLaunchFailure(KioskAppLaunchError::UNABLE_TO_INSTALL); |
324 return; | |
325 } | 387 } |
326 | |
327 LOG(ERROR) << "App install failed: " << error | |
328 << ", for attempt " << install_attempt_; | |
329 | |
330 ++install_attempt_; | |
331 if (install_attempt_ < kMaxInstallAttempt) { | |
332 BrowserThread::PostTask( | |
333 BrowserThread::UI, | |
334 FROM_HERE, | |
335 base::Bind(&StartupAppLauncher::MaybeInitializeNetwork, | |
336 AsWeakPtr())); | |
337 return; | |
338 } | |
339 | |
340 OnLaunchFailure(KioskAppLaunchError::UNABLE_TO_INSTALL); | |
341 } | 388 } |
342 | 389 |
343 void StartupAppLauncher::OnReadyToLaunch() { | 390 void StartupAppLauncher::OnReadyToLaunch() { |
344 ready_to_launch_ = true; | 391 ready_to_launch_ = true; |
345 delegate_->OnReadyToLaunch(); | 392 delegate_->OnReadyToLaunch(); |
346 } | 393 } |
347 | 394 |
348 void StartupAppLauncher::UpdateAppData() { | 395 void StartupAppLauncher::UpdateAppData() { |
349 KioskAppManager::Get()->ClearAppData(app_id_); | 396 KioskAppManager::Get()->ClearAppData(app_id_); |
350 KioskAppManager::Get()->UpdateAppDataFromProfile(app_id_, profile_, NULL); | 397 KioskAppManager::Get()->UpdateAppDataFromProfile(app_id_, profile_, NULL); |
351 } | 398 } |
352 | 399 |
353 } // namespace chromeos | 400 } // namespace chromeos |
OLD | NEW |