Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(23)

Side by Side Diff: chrome/browser/chromeos/app_mode/startup_app_launcher.cc

Issue 300843013: Install and launch kiosk app from cached crx file at start up. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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/users/user_manager.h" 17 #include "chrome/browser/chromeos/login/users/user_manager.h"
18 #include "chrome/browser/extensions/crx_installer.h"
18 #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"
19 #include "chrome/browser/extensions/updater/extension_updater.h" 22 #include "chrome/browser/extensions/updater/extension_updater.h"
20 #include "chrome/browser/extensions/webstore_startup_installer.h"
21 #include "chrome/browser/lifetime/application_lifetime.h" 23 #include "chrome/browser/lifetime/application_lifetime.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/signin_manager_factory.h" 25 #include "chrome/browser/signin/signin_manager_factory.h"
24 #include "chrome/browser/ui/extensions/application_launch.h" 26 #include "chrome/browser/ui/extensions/application_launch.h"
25 #include "chrome/common/chrome_paths.h" 27 #include "chrome/common/chrome_paths.h"
26 #include "chrome/common/chrome_switches.h" 28 #include "chrome/common/chrome_switches.h"
27 #include "chrome/common/chrome_version_info.h" 29 #include "chrome/common/chrome_version_info.h"
28 #include "chrome/common/extensions/manifest_url_handler.h" 30 #include "chrome/common/extensions/manifest_url_handler.h"
29 #include "components/signin/core/browser/profile_oauth2_token_service.h" 31 #include "components/signin/core/browser/profile_oauth2_token_service.h"
30 #include "components/signin/core/browser/signin_manager.h" 32 #include "components/signin/core/browser/signin_manager.h"
31 #include "content/public/browser/browser_thread.h" 33 #include "content/public/browser/browser_thread.h"
32 #include "content/public/browser/notification_service.h" 34 #include "content/public/browser/notification_service.h"
33 #include "extensions/browser/extension_system.h" 35 #include "extensions/browser/extension_system.h"
34 #include "extensions/common/extension.h" 36 #include "extensions/common/extension.h"
35 #include "extensions/common/manifest_handlers/kiosk_mode_info.h" 37 #include "extensions/common/manifest_handlers/kiosk_mode_info.h"
36 #include "extensions/common/manifest_handlers/offline_enabled_info.h" 38 #include "extensions/common/manifest_handlers/offline_enabled_info.h"
37 #include "google_apis/gaia/gaia_auth_consumer.h" 39 #include "google_apis/gaia/gaia_auth_consumer.h"
38 #include "google_apis/gaia/gaia_constants.h" 40 #include "google_apis/gaia/gaia_constants.h"
39 #include "net/base/load_flags.h" 41 #include "net/base/load_flags.h"
40 #include "net/url_request/url_fetcher.h" 42 #include "net/url_request/url_fetcher.h"
41 #include "net/url_request/url_fetcher_delegate.h" 43 #include "net/url_request/url_fetcher_delegate.h"
42 #include "net/url_request/url_request_context_getter.h" 44 #include "net/url_request/url_request_context_getter.h"
43 #include "net/url_request/url_request_status.h" 45 #include "net/url_request/url_request_status.h"
44 #include "url/gurl.h" 46 #include "url/gurl.h"
45 47
46 using content::BrowserThread; 48 using content::BrowserThread;
47 using extensions::Extension; 49 using extensions::Extension;
48 using extensions::WebstoreStartupInstaller;
49 50
50 namespace chromeos { 51 namespace chromeos {
51 52
52 namespace { 53 namespace {
53 54
54 const char kOAuthRefreshToken[] = "refresh_token"; 55 const char kOAuthRefreshToken[] = "refresh_token";
55 const char kOAuthClientId[] = "client_id"; 56 const char kOAuthClientId[] = "client_id";
56 const char kOAuthClientSecret[] = "client_secret"; 57 const char kOAuthClientSecret[] = "client_secret";
57 58
58 const base::FilePath::CharType kOAuthFileName[] = 59 const base::FilePath::CharType kOAuthFileName[] =
59 FILE_PATH_LITERAL("kiosk_auth"); 60 FILE_PATH_LITERAL("kiosk_auth");
60 61
61 const int kMaxInstallAttempt = 5; 62 const int kMaxDownloadAttempt = 5;
63 const int kMaxLaunchAttempt = 5;
62 64
63 } // namespace 65 } // namespace
64 66
65 StartupAppLauncher::StartupAppLauncher(Profile* profile, 67 StartupAppLauncher::StartupAppLauncher(Profile* profile,
66 const std::string& app_id, 68 const std::string& app_id,
67 bool diagnostic_mode, 69 bool diagnostic_mode,
68 StartupAppLauncher::Delegate* delegate) 70 StartupAppLauncher::Delegate* delegate)
69 : profile_(profile), 71 : profile_(profile),
70 app_id_(app_id), 72 app_id_(app_id),
71 diagnostic_mode_(diagnostic_mode), 73 diagnostic_mode_(diagnostic_mode),
72 delegate_(delegate), 74 delegate_(delegate),
73 network_ready_handled_(false), 75 network_ready_handled_(false),
74 install_attempt_(0), 76 download_attempt_(0),
75 ready_to_launch_(false) { 77 launch_attempt_(0),
78 ready_to_launch_(false),
79 update_check_pending_(false),
80 crx_cache_pending_(false) {
76 DCHECK(profile_); 81 DCHECK(profile_);
77 DCHECK(Extension::IdIsValid(app_id_)); 82 DCHECK(Extension::IdIsValid(app_id_));
83
84 KioskAppManager::Get()->AddObserver(this);
78 } 85 }
79 86
80 StartupAppLauncher::~StartupAppLauncher() { 87 StartupAppLauncher::~StartupAppLauncher() {
88 KioskAppManager::Get()->RemoveObserver(this);
89
81 // StartupAppLauncher can be deleted at anytime during the launch process 90 // StartupAppLauncher can be deleted at anytime during the launch process
82 // through a user bailout shortcut. 91 // through a user bailout shortcut.
83 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_) 92 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_)
84 ->RemoveObserver(this); 93 ->RemoveObserver(this);
85 } 94 }
86 95
87 void StartupAppLauncher::Initialize() { 96 void StartupAppLauncher::Initialize() {
88 StartLoadingOAuthFile(); 97 StartLoadingOAuthFile();
89 } 98 }
90 99
91 void StartupAppLauncher::ContinueWithNetworkReady() { 100 void StartupAppLauncher::ContinueWithNetworkReady() {
92 // Starts install if it is not started. 101 // Starts install if it is not started.
93 if (!network_ready_handled_) { 102 if (!network_ready_handled_) {
94 network_ready_handled_ = true; 103 network_ready_handled_ = true;
95 MaybeInstall(); 104 base::FilePath crx_path;
105 std::string version;
106 bool crx_cached =
107 KioskAppManager::Get()->GetCachedCrx(app_id_, &crx_path, &version);
108 bool installed = extensions::ExtensionSystem::Get(profile_)
109 ->extension_service()
110 ->GetInstalledExtension(app_id_);
111 KioskAppManager* kiosk_app_manager = KioskAppManager::Get();
112 if (installed || crx_cached) {
113 // If KioskAppManager is still checking update for |app_id_|, wait until
114 // it completes.
115 if (kiosk_app_manager->IsExtensionPendingForUpdateCheck(app_id_)) {
116 update_check_pending_ = true;
117 return;
118 }
119 // If the app is installed or its crx file is cached, either check update
120 // or install the app.
121 MaybeInstall();
122 } else {
123 // If the app is still being downloaded, wait until it completes.
124 if (kiosk_app_manager->IsExtensionPendingForCache(app_id_)) {
125 crx_cache_pending_ = true;
126 return;
127 }
128 LOG(ERROR) << "Failed to download the app: app_id=" << app_id_;
129 OnLaunchFailure(KioskAppLaunchError::UNABLE_TO_DOWNLOAD);
130 }
96 } 131 }
97 } 132 }
98 133
99 void StartupAppLauncher::StartLoadingOAuthFile() { 134 void StartupAppLauncher::StartLoadingOAuthFile() {
100 delegate_->OnLoadingOAuthFile(); 135 delegate_->OnLoadingOAuthFile();
101 136
102 KioskOAuthParams* auth_params = new KioskOAuthParams(); 137 KioskOAuthParams* auth_params = new KioskOAuthParams();
103 BrowserThread::PostBlockingPoolTaskAndReply( 138 BrowserThread::PostBlockingPoolTaskAndReply(
104 FROM_HERE, 139 FROM_HERE,
105 base::Bind(&StartupAppLauncher::LoadOAuthFileOnBlockingPool, 140 base::Bind(&StartupAppLauncher::LoadOAuthFileOnBlockingPool,
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
144 } 179 }
145 180
146 // If we are restarting chrome (i.e. on crash), we need to initialize 181 // If we are restarting chrome (i.e. on crash), we need to initialize
147 // OAuth2TokenService as well. 182 // OAuth2TokenService as well.
148 InitializeTokenService(); 183 InitializeTokenService();
149 } 184 }
150 185
151 void StartupAppLauncher::RestartLauncher() { 186 void StartupAppLauncher::RestartLauncher() {
152 // If the installer is still running in the background, we don't need to 187 // If the installer is still running in the background, we don't need to
153 // restart the launch process. We will just wait until it completes and 188 // restart the launch process. We will just wait until it completes and
154 // lunches the kiosk app. 189 // launches the kiosk app.
155 if (installer_ != NULL) { 190 if (crx_installer_ != NULL) {
156 LOG(WARNING) << "Installer still running"; 191 LOG(WARNING) << "Installer still running";
157 return; 192 return;
158 } 193 }
159 194
160 MaybeInitializeNetwork(); 195 MaybeInitializeNetwork();
161 } 196 }
162 197
163 void StartupAppLauncher::MaybeInitializeNetwork() { 198 void StartupAppLauncher::MaybeInitializeNetwork() {
164 network_ready_handled_ = false; 199 network_ready_handled_ = false;
165 200
166 const Extension* extension = extensions::ExtensionSystem::Get(profile_)-> 201 const Extension* extension = extensions::ExtensionSystem::Get(profile_)->
167 extension_service()->GetInstalledExtension(app_id_); 202 extension_service()->GetInstalledExtension(app_id_);
168 const bool requires_network = !extension || 203 base::FilePath crx_path;
169 !extensions::OfflineEnabledInfo::IsOfflineEnabled(extension); 204 std::string version;
205 bool crx_cached =
206 KioskAppManager::Get()->GetCachedCrx(app_id_, &crx_path, &version);
207 const bool requires_network =
208 (!extension && !crx_cached) ||
209 (extension &&
210 !extensions::OfflineEnabledInfo::IsOfflineEnabled(extension));
170 211
171 if (requires_network) { 212 if (requires_network) {
172 delegate_->InitializeNetwork(); 213 delegate_->InitializeNetwork();
173 return; 214 return;
174 } 215 }
175 216
176 // Offline enabled app attempts update if network is ready. Otherwise, 217 // Install the extension if it is not installed yet, or update the extension
177 // go directly to launch. 218 // if it is already installed and the network is ready; otherwise, launch the
178 if (delegate_->IsNetworkReady()) 219 // offline enabled app.
220 if (!extension)
221 MaybeInstall();
222 else if (delegate_->IsNetworkReady())
179 ContinueWithNetworkReady(); 223 ContinueWithNetworkReady();
180 else 224 else
181 OnReadyToLaunch(); 225 OnReadyToLaunch();
182 } 226 }
183 227
184 void StartupAppLauncher::InitializeTokenService() { 228 void StartupAppLauncher::InitializeTokenService() {
185 delegate_->OnInitializingTokenService(); 229 delegate_->OnInitializingTokenService();
186 230
187 ProfileOAuth2TokenService* profile_token_service = 231 ProfileOAuth2TokenService* profile_token_service =
188 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_); 232 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
220 ->RemoveObserver(this); 264 ->RemoveObserver(this);
221 MaybeInitializeNetwork(); 265 MaybeInitializeNetwork();
222 } 266 }
223 267
224 void StartupAppLauncher::OnRefreshTokensLoaded() { 268 void StartupAppLauncher::OnRefreshTokensLoaded() {
225 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_) 269 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_)
226 ->RemoveObserver(this); 270 ->RemoveObserver(this);
227 MaybeInitializeNetwork(); 271 MaybeInitializeNetwork();
228 } 272 }
229 273
274 void StartupAppLauncher::OnFinishCrxInstall(const std::string& extension_id,
275 bool success) {
276 DCHECK(extension_id == app_id_);
277 if (extension_id != app_id_)
278 return;
279
280 extensions::InstallTracker* tracker =
281 extensions::InstallTrackerFactory::GetForProfile(profile_);
282 tracker->RemoveObserver(this);
283 crx_installer_ = NULL;
284 if (delegate_->IsShowingNetworkConfigScreen()) {
285 LOG(WARNING) << "Showing network config screen";
286 return;
287 }
288
289 if (success) {
290 // Check if the app is offline enabled.
291 const Extension* extension = extensions::ExtensionSystem::Get(profile_)
292 ->extension_service()
293 ->GetInstalledExtension(extension_id);
294 DCHECK(extension);
295 const bool offline_enabled =
296 extensions::OfflineEnabledInfo::IsOfflineEnabled(extension);
297 if (offline_enabled || delegate_->IsNetworkReady()) {
298 BrowserThread::PostTask(
299 BrowserThread::UI,
300 FROM_HERE,
301 base::Bind(&StartupAppLauncher::OnReadyToLaunch, AsWeakPtr()));
302 } else {
303 ++launch_attempt_;
304 if (launch_attempt_ < kMaxLaunchAttempt) {
305 BrowserThread::PostTask(
306 BrowserThread::UI,
307 FROM_HERE,
308 base::Bind(&StartupAppLauncher::MaybeInitializeNetwork,
309 AsWeakPtr()));
310 return;
311 }
312 OnLaunchFailure(KioskAppLaunchError::UNABLE_TO_LAUNCH);
313 }
314 return;
315 }
316
317 LOG(ERROR) << "Failed to install the kiosk application app_id: "
318 << extension_id;
319 OnLaunchFailure(KioskAppLaunchError::UNABLE_TO_INSTALL);
320 }
321
322 void StartupAppLauncher::OnKioskAppDataChanged(const std::string& app_id) {
323 OnKioskAppDataLoadStatusChanged(app_id);
324 }
325
326 void StartupAppLauncher::OnKioskAppDataLoadFailure(const std::string& app_id) {
327 OnKioskAppDataLoadStatusChanged(app_id);
328 }
329
330 void StartupAppLauncher::OnKioskAppDataLoadStatusChanged(
331 const std::string& app_id) {
332 if (app_id != app_id_)
333 return;
334
335 if (crx_cache_pending_ &&
336 !KioskAppManager::Get()->IsExtensionPendingForCache(app_id_)) {
337 crx_cache_pending_ = false;
338 network_ready_handled_ = false;
339 ContinueWithNetworkReady();
340 } else if (update_check_pending_ &&
341 !KioskAppManager::Get()->IsExtensionPendingForUpdateCheck(
342 app_id_)) {
343 update_check_pending_ = false;
xiyuan 2014/05/29 19:49:01 We probably could consolidate |crx_cache_pending_|
jennyz 2014/07/07 21:11:12 Done.
344 network_ready_handled_ = false;
345 ContinueWithNetworkReady();
346 }
347 }
348
230 void StartupAppLauncher::LaunchApp() { 349 void StartupAppLauncher::LaunchApp() {
231 if (!ready_to_launch_) { 350 if (!ready_to_launch_) {
232 NOTREACHED(); 351 NOTREACHED();
233 LOG(ERROR) << "LaunchApp() called but launcher is not initialized."; 352 LOG(ERROR) << "LaunchApp() called but launcher is not initialized.";
234 } 353 }
235 354
236 const Extension* extension = extensions::ExtensionSystem::Get(profile_)-> 355 const Extension* extension = extensions::ExtensionSystem::Get(profile_)->
237 extension_service()->GetInstalledExtension(app_id_); 356 extension_service()->GetInstalledExtension(app_id_);
238 CHECK(extension); 357 CHECK(extension);
239 358
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
289 base::Bind(&StartupAppLauncher::OnUpdateCheckFinished, AsWeakPtr()); 408 base::Bind(&StartupAppLauncher::OnUpdateCheckFinished, AsWeakPtr());
290 extension_service->updater()->CheckNow(check_params); 409 extension_service->updater()->CheckNow(check_params);
291 } 410 }
292 411
293 void StartupAppLauncher::OnUpdateCheckFinished() { 412 void StartupAppLauncher::OnUpdateCheckFinished() {
294 OnReadyToLaunch(); 413 OnReadyToLaunch();
295 UpdateAppData(); 414 UpdateAppData();
296 } 415 }
297 416
298 void StartupAppLauncher::BeginInstall() { 417 void StartupAppLauncher::BeginInstall() {
299 installer_ = new WebstoreStartupInstaller( 418 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
300 app_id_, 419 DCHECK(!crx_installer_.get());
301 profile_, 420
302 false, 421 base::FilePath crx_path;
303 base::Bind(&StartupAppLauncher::InstallCallback, AsWeakPtr())); 422 std::string version;
304 installer_->BeginInstall(); 423 KioskAppManager::Get()->GetCachedCrx(app_id_, &crx_path, &version);
424 base::Version crx_version(version);
425
426 crx_installer_ = CreateCrxInstaller(profile_);
xiyuan 2014/05/29 19:49:01 Sorry that I did not mention this earlier. We shou
jennyz 2014/07/07 21:11:12 Removed CrxInstaller from StartupAppLauncher, used
427 crx_installer_->set_expected_id(app_id_);
428 crx_installer_->set_expected_version(crx_version);
429 crx_installer_->set_is_gallery_install(true);
430 crx_installer_->set_allow_silent_install(true);
431
432 crx_installer_->InstallCrx(crx_path);
305 } 433 }
306 434
307 void StartupAppLauncher::InstallCallback(bool success, 435 scoped_refptr<extensions::CrxInstaller> StartupAppLauncher::CreateCrxInstaller(
xiyuan 2014/05/29 19:49:01 Consider merge this into BeginInstall.
jennyz 2014/07/07 21:11:12 This function has been removed.
308 const std::string& error) { 436 Profile* profile) {
309 installer_ = NULL; 437 ExtensionService* service =
310 if (delegate_->IsShowingNetworkConfigScreen()) { 438 extensions::ExtensionSystem::Get(profile)->extension_service();
311 LOG(WARNING) << "Showing network config screen"; 439 CHECK(service);
312 return;
313 }
314 440
315 if (success) { 441 scoped_refptr<extensions::CrxInstaller> installer(
316 // Finish initialization after the callback returns. 442 extensions::CrxInstaller::CreateSilent(service));
317 // So that the app finishes its installation.
318 BrowserThread::PostTask(
319 BrowserThread::UI,
320 FROM_HERE,
321 base::Bind(&StartupAppLauncher::OnReadyToLaunch,
322 AsWeakPtr()));
323 return;
324 }
325 443
326 LOG(ERROR) << "App install failed: " << error 444 installer->set_error_on_unsupported_requirements(true);
327 << ", for attempt " << install_attempt_; 445 installer->set_delete_source(false);
446 installer->set_install_cause(extension_misc::INSTALL_CAUSE_USER_DOWNLOAD);
xiyuan 2014/05/29 19:49:01 How about use INSTALL_CAUSE_EXTERNAL_FILE? INSTALL
jennyz 2014/07/07 21:11:12 Function has been removed.
328 447
329 ++install_attempt_; 448 // Observe the crx installation events.
330 if (install_attempt_ < kMaxInstallAttempt) { 449 extensions::InstallTracker* tracker =
331 BrowserThread::PostTask( 450 extensions::InstallTrackerFactory::GetForProfile(profile_);
332 BrowserThread::UI, 451 tracker->AddObserver(this);
xiyuan 2014/05/29 19:49:01 This should be moved out of CreateCrxInstaller.
jennyz 2014/07/07 21:11:12 Done.
333 FROM_HERE,
334 base::Bind(&StartupAppLauncher::MaybeInitializeNetwork,
335 AsWeakPtr()));
336 return;
337 }
338 452
339 OnLaunchFailure(KioskAppLaunchError::UNABLE_TO_INSTALL); 453 return installer;
340 } 454 }
341 455
342 void StartupAppLauncher::OnReadyToLaunch() { 456 void StartupAppLauncher::OnReadyToLaunch() {
343 ready_to_launch_ = true; 457 ready_to_launch_ = true;
344 delegate_->OnReadyToLaunch(); 458 delegate_->OnReadyToLaunch();
345 } 459 }
346 460
347 void StartupAppLauncher::UpdateAppData() { 461 void StartupAppLauncher::UpdateAppData() {
348 KioskAppManager::Get()->ClearAppData(app_id_); 462 KioskAppManager::Get()->ClearAppData(app_id_);
349 KioskAppManager::Get()->UpdateAppDataFromProfile(app_id_, profile_, NULL); 463 KioskAppManager::Get()->UpdateAppDataFromProfile(app_id_, profile_, NULL);
350 } 464 }
351 465
352 } // namespace chromeos 466 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698