| 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 |