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/login/user_manager.h" | 16 #include "chrome/browser/chromeos/login/user_manager.h" |
17 #include "chrome/browser/extensions/extension_service.h" | 17 #include "chrome/browser/extensions/extension_service.h" |
18 #include "chrome/browser/extensions/extension_system.h" | 18 #include "chrome/browser/extensions/extension_system.h" |
| 19 #include "chrome/browser/extensions/updater/manifest_fetch_data.h" |
| 20 #include "chrome/browser/extensions/updater/safe_manifest_parser.h" |
19 #include "chrome/browser/extensions/webstore_startup_installer.h" | 21 #include "chrome/browser/extensions/webstore_startup_installer.h" |
20 #include "chrome/browser/lifetime/application_lifetime.h" | 22 #include "chrome/browser/lifetime/application_lifetime.h" |
21 #include "chrome/browser/signin/profile_oauth2_token_service.h" | 23 #include "chrome/browser/signin/profile_oauth2_token_service.h" |
22 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h" | 24 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h" |
23 #include "chrome/browser/signin/token_service.h" | 25 #include "chrome/browser/signin/token_service.h" |
24 #include "chrome/browser/signin/token_service_factory.h" | 26 #include "chrome/browser/signin/token_service_factory.h" |
25 #include "chrome/browser/ui/extensions/application_launch.h" | 27 #include "chrome/browser/ui/extensions/application_launch.h" |
26 #include "chrome/common/chrome_paths.h" | 28 #include "chrome/common/chrome_paths.h" |
27 #include "chrome/common/chrome_switches.h" | 29 #include "chrome/common/chrome_switches.h" |
28 #include "chrome/common/extensions/extension.h" | 30 #include "chrome/common/extensions/extension.h" |
29 #include "chrome/common/extensions/manifest_handlers/kiosk_mode_info.h" | 31 #include "chrome/common/extensions/manifest_handlers/kiosk_mode_info.h" |
| 32 #include "chrome/common/chrome_version_info.h" |
| 33 #include "chrome/common/extensions/manifest_url_handler.h" |
30 #include "content/public/browser/browser_thread.h" | 34 #include "content/public/browser/browser_thread.h" |
31 #include "content/public/browser/notification_service.h" | 35 #include "content/public/browser/notification_service.h" |
32 #include "google_apis/gaia/gaia_auth_consumer.h" | 36 #include "google_apis/gaia/gaia_auth_consumer.h" |
33 #include "google_apis/gaia/gaia_constants.h" | 37 #include "google_apis/gaia/gaia_constants.h" |
| 38 #include "net/base/load_flags.h" |
| 39 #include "net/url_request/url_fetcher.h" |
| 40 #include "net/url_request/url_fetcher_delegate.h" |
| 41 #include "net/url_request/url_request_context_getter.h" |
| 42 #include "net/url_request/url_request_status.h" |
| 43 #include "url/gurl.h" |
34 | 44 |
35 using content::BrowserThread; | 45 using content::BrowserThread; |
36 using extensions::Extension; | 46 using extensions::Extension; |
37 using extensions::WebstoreStartupInstaller; | 47 using extensions::WebstoreStartupInstaller; |
38 | 48 |
39 namespace chromeos { | 49 namespace chromeos { |
40 | 50 |
41 namespace { | 51 namespace { |
42 | 52 |
43 const char kOAuthRefreshToken[] = "refresh_token"; | 53 const char kOAuthRefreshToken[] = "refresh_token"; |
44 const char kOAuthClientId[] = "client_id"; | 54 const char kOAuthClientId[] = "client_id"; |
45 const char kOAuthClientSecret[] = "client_secret"; | 55 const char kOAuthClientSecret[] = "client_secret"; |
46 | 56 |
47 const base::FilePath::CharType kOAuthFileName[] = | 57 const base::FilePath::CharType kOAuthFileName[] = |
48 FILE_PATH_LITERAL("kiosk_auth"); | 58 FILE_PATH_LITERAL("kiosk_auth"); |
49 | 59 |
50 bool IsAppInstalled(Profile* profile, const std::string& app_id) { | |
51 return extensions::ExtensionSystem::Get(profile)->extension_service()-> | |
52 GetInstalledExtension(app_id); | |
53 } | |
54 | |
55 } // namespace | 60 } // namespace |
56 | 61 |
| 62 class StartupAppLauncher::AppUpdateChecker |
| 63 : public base::SupportsWeakPtr<AppUpdateChecker>, |
| 64 public net::URLFetcherDelegate { |
| 65 public: |
| 66 explicit AppUpdateChecker(StartupAppLauncher* launcher) |
| 67 : launcher_(launcher), |
| 68 profile_(launcher->profile_), |
| 69 app_id_(launcher->app_id_) {} |
| 70 virtual ~AppUpdateChecker() {} |
| 71 |
| 72 void Start() { |
| 73 const Extension* app = GetInstalledApp(); |
| 74 if (!app) { |
| 75 launcher_->OnUpdateCheckNotInstalled(); |
| 76 return; |
| 77 } |
| 78 |
| 79 GURL update_url = extensions::ManifestURL::GetUpdateURL(app); |
| 80 if (update_url.is_empty()) |
| 81 update_url = extension_urls::GetWebstoreUpdateUrl(); |
| 82 if (!update_url.is_valid()) { |
| 83 launcher_->OnUpdateCheckNoUpdate(); |
| 84 return; |
| 85 } |
| 86 |
| 87 manifest_fetch_data_.reset( |
| 88 new extensions::ManifestFetchData(update_url, 0)); |
| 89 manifest_fetch_data_->AddExtension( |
| 90 app_id_, app->version()->GetString(), NULL, "", ""); |
| 91 |
| 92 manifest_fetcher_.reset(net::URLFetcher::Create( |
| 93 manifest_fetch_data_->full_url(), net::URLFetcher::GET, this)); |
| 94 manifest_fetcher_->SetRequestContext(profile_->GetRequestContext()); |
| 95 manifest_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | |
| 96 net::LOAD_DO_NOT_SAVE_COOKIES | |
| 97 net::LOAD_DISABLE_CACHE); |
| 98 manifest_fetcher_->SetAutomaticallyRetryOnNetworkChanges(3); |
| 99 manifest_fetcher_->Start(); |
| 100 } |
| 101 |
| 102 private: |
| 103 const Extension* GetInstalledApp() { |
| 104 ExtensionService* extension_service = |
| 105 extensions::ExtensionSystem::Get(profile_)->extension_service(); |
| 106 return extension_service->GetInstalledExtension(app_id_); |
| 107 } |
| 108 |
| 109 void HandleManifestResults(const extensions::ManifestFetchData& fetch_data, |
| 110 const UpdateManifest::Results* results) { |
| 111 if (!results || results->list.empty()) { |
| 112 launcher_->OnUpdateCheckNoUpdate(); |
| 113 return; |
| 114 } |
| 115 |
| 116 DCHECK_EQ(1u, results->list.size()); |
| 117 |
| 118 const UpdateManifest::Result& update = results->list[0]; |
| 119 |
| 120 if (update.browser_min_version.length() > 0) { |
| 121 Version browser_version; |
| 122 chrome::VersionInfo version_info; |
| 123 if (version_info.is_valid()) |
| 124 browser_version = Version(version_info.Version()); |
| 125 |
| 126 Version browser_min_version(update.browser_min_version); |
| 127 if (browser_version.IsValid() && |
| 128 browser_min_version.IsValid() && |
| 129 browser_min_version.CompareTo(browser_version) > 0) { |
| 130 launcher_->OnUpdateCheckNoUpdate(); |
| 131 return; |
| 132 } |
| 133 } |
| 134 |
| 135 const Version& existing_version = *GetInstalledApp()->version(); |
| 136 Version update_version(update.version); |
| 137 if (existing_version.IsValid() && |
| 138 update_version.IsValid() && |
| 139 update_version.CompareTo(existing_version) <= 0) { |
| 140 launcher_->OnUpdateCheckNoUpdate(); |
| 141 return; |
| 142 } |
| 143 |
| 144 launcher_->OnUpdateCheckUpdateAvailable(); |
| 145 } |
| 146 |
| 147 // net::URLFetcherDelegate implementation. |
| 148 virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE { |
| 149 DCHECK_EQ(source, manifest_fetcher_.get()); |
| 150 |
| 151 if (source->GetStatus().status() != net::URLRequestStatus::SUCCESS || |
| 152 source->GetResponseCode() != 200) { |
| 153 launcher_->OnUpdateCheckNoUpdate(); |
| 154 return; |
| 155 } |
| 156 |
| 157 std::string data; |
| 158 source->GetResponseAsString(&data); |
| 159 scoped_refptr<extensions::SafeManifestParser> safe_parser( |
| 160 new extensions::SafeManifestParser( |
| 161 data, |
| 162 manifest_fetch_data_.release(), |
| 163 base::Bind(&AppUpdateChecker::HandleManifestResults, |
| 164 AsWeakPtr()))); |
| 165 safe_parser->Start(); |
| 166 } |
| 167 |
| 168 StartupAppLauncher* launcher_; |
| 169 Profile* profile_; |
| 170 const std::string app_id_; |
| 171 |
| 172 scoped_ptr<extensions::ManifestFetchData> manifest_fetch_data_; |
| 173 scoped_ptr<net::URLFetcher> manifest_fetcher_; |
| 174 |
| 175 DISALLOW_COPY_AND_ASSIGN(AppUpdateChecker); |
| 176 }; |
57 | 177 |
58 StartupAppLauncher::StartupAppLauncher(Profile* profile, | 178 StartupAppLauncher::StartupAppLauncher(Profile* profile, |
59 const std::string& app_id) | 179 const std::string& app_id) |
60 : profile_(profile), | 180 : profile_(profile), |
61 app_id_(app_id), | 181 app_id_(app_id), |
62 ready_to_launch_(false) { | 182 ready_to_launch_(false) { |
63 DCHECK(profile_); | 183 DCHECK(profile_); |
64 DCHECK(Extension::IdIsValid(app_id_)); | 184 DCHECK(Extension::IdIsValid(app_id_)); |
65 } | 185 } |
66 | 186 |
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
235 UserManager::Get()->SessionStarted(); | 355 UserManager::Get()->SessionStarted(); |
236 | 356 |
237 content::NotificationService::current()->Notify( | 357 content::NotificationService::current()->Notify( |
238 chrome::NOTIFICATION_KIOSK_APP_LAUNCHED, | 358 chrome::NOTIFICATION_KIOSK_APP_LAUNCHED, |
239 content::NotificationService::AllSources(), | 359 content::NotificationService::AllSources(), |
240 content::NotificationService::NoDetails()); | 360 content::NotificationService::NoDetails()); |
241 | 361 |
242 OnLaunchSuccess(); | 362 OnLaunchSuccess(); |
243 } | 363 } |
244 | 364 |
245 void StartupAppLauncher::BeginInstall() { | 365 void StartupAppLauncher::MaybeInstall() { |
246 FOR_EACH_OBSERVER(Observer, observer_list_, OnInstallingApp()); | 366 FOR_EACH_OBSERVER(Observer, observer_list_, OnInstallingApp()); |
247 | 367 |
248 DVLOG(1) << "BeginInstall... connection = " | 368 update_checker_.reset(new AppUpdateChecker(this)); |
249 << net::NetworkChangeNotifier::GetConnectionType(); | 369 update_checker_->Start(); |
| 370 } |
250 | 371 |
251 if (IsAppInstalled(profile_, app_id_)) { | 372 void StartupAppLauncher::OnUpdateCheckNotInstalled() { |
252 OnReadyToLaunch(); | 373 BeginInstall(); |
253 return; | 374 } |
254 } | |
255 | 375 |
| 376 void StartupAppLauncher::OnUpdateCheckUpdateAvailable() { |
| 377 // Uninstall to force a re-install. |
| 378 // TODO(xiyuan): Find a better way. Either download CRX and install it |
| 379 // directly or integrate with ExtensionUpdater in someway. |
| 380 ExtensionService* extension_service = |
| 381 extensions::ExtensionSystem::Get(profile_)->extension_service(); |
| 382 extension_service->UninstallExtension(app_id_, false, NULL); |
| 383 |
| 384 OnUpdateCheckNotInstalled(); |
| 385 } |
| 386 |
| 387 void StartupAppLauncher::OnUpdateCheckNoUpdate() { |
| 388 OnReadyToLaunch(); |
| 389 } |
| 390 |
| 391 void StartupAppLauncher::BeginInstall() { |
256 installer_ = new WebstoreStartupInstaller( | 392 installer_ = new WebstoreStartupInstaller( |
257 app_id_, | 393 app_id_, |
258 profile_, | 394 profile_, |
259 false, | 395 false, |
260 base::Bind(&StartupAppLauncher::InstallCallback, AsWeakPtr())); | 396 base::Bind(&StartupAppLauncher::InstallCallback, AsWeakPtr())); |
261 installer_->BeginInstall(); | 397 installer_->BeginInstall(); |
262 } | 398 } |
263 | 399 |
264 void StartupAppLauncher::InstallCallback(bool success, | 400 void StartupAppLauncher::InstallCallback(bool success, |
265 const std::string& error) { | 401 const std::string& error) { |
266 installer_ = NULL; | 402 installer_ = NULL; |
267 if (success) { | 403 if (success) { |
268 // Finish initialization after the callback returns. | 404 // Finish initialization after the callback returns. |
269 // So that the app finishes its installation. | 405 // So that the app finishes its installation. |
270 BrowserThread::PostTask( | 406 BrowserThread::PostTask( |
271 BrowserThread::UI, | 407 BrowserThread::UI, |
272 FROM_HERE, | 408 FROM_HERE, |
273 base::Bind(&StartupAppLauncher::OnReadyToLaunch, | 409 base::Bind(&StartupAppLauncher::OnReadyToLaunch, |
274 AsWeakPtr())); | 410 AsWeakPtr())); |
| 411 |
| 412 // Schedule app data update after installation. |
| 413 BrowserThread::PostTask( |
| 414 BrowserThread::UI, |
| 415 FROM_HERE, |
| 416 base::Bind(&StartupAppLauncher::UpdateAppData, |
| 417 AsWeakPtr())); |
275 return; | 418 return; |
276 } | 419 } |
277 | 420 |
278 LOG(ERROR) << "App install failed: " << error; | 421 LOG(ERROR) << "App install failed: " << error; |
279 OnLaunchFailure(KioskAppLaunchError::UNABLE_TO_INSTALL); | 422 OnLaunchFailure(KioskAppLaunchError::UNABLE_TO_INSTALL); |
280 } | 423 } |
281 | 424 |
282 void StartupAppLauncher::OnReadyToLaunch() { | 425 void StartupAppLauncher::OnReadyToLaunch() { |
283 ready_to_launch_ = true; | 426 ready_to_launch_ = true; |
284 FOR_EACH_OBSERVER(Observer, observer_list_, OnReadyToLaunch()); | 427 FOR_EACH_OBSERVER(Observer, observer_list_, OnReadyToLaunch()); |
285 } | 428 } |
286 | 429 |
287 void StartupAppLauncher::OnNetworkChanged( | 430 void StartupAppLauncher::OnNetworkChanged( |
288 net::NetworkChangeNotifier::ConnectionType type) { | 431 net::NetworkChangeNotifier::ConnectionType type) { |
289 DVLOG(1) << "OnNetworkChanged... connection = " | 432 DVLOG(1) << "OnNetworkChanged... connection = " |
290 << net::NetworkChangeNotifier::GetConnectionType(); | 433 << net::NetworkChangeNotifier::GetConnectionType(); |
291 if (!net::NetworkChangeNotifier::IsOffline()) { | 434 if (!net::NetworkChangeNotifier::IsOffline()) { |
292 DVLOG(1) << "Network up and running!"; | 435 DVLOG(1) << "Network up and running!"; |
293 net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this); | 436 net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this); |
294 | 437 |
295 BeginInstall(); | 438 MaybeInstall(); |
296 } else { | 439 } else { |
297 DVLOG(1) << "Network not running yet!"; | 440 DVLOG(1) << "Network not running yet!"; |
298 } | 441 } |
299 } | 442 } |
300 | 443 |
| 444 void StartupAppLauncher::UpdateAppData() { |
| 445 KioskAppManager::Get()->ClearAppData(app_id_); |
| 446 KioskAppManager::Get()->UpdateAppDataFromProfile(app_id_, profile_, NULL); |
| 447 } |
| 448 |
301 } // namespace chromeos | 449 } // namespace chromeos |
OLD | NEW |