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

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: Fix ExternalProviderImplChromeOSTest.AppMode test case. Created 6 years, 5 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/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 crx_ready_for_install_(true) {
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. 97 // Starts install if it is not started.
94 if (!network_ready_handled_) { 98 if (!network_ready_handled_) {
95 network_ready_handled_ = true; 99 network_ready_handled_ = true;
96 MaybeInstall(); 100 base::FilePath crx_path;
xiyuan 2014/07/08 21:50:59 The network might take sometime to be up and initi
jennyz 2014/07/12 00:03:20 Done.
101 std::string version;
102 bool crx_cached =
103 KioskAppManager::Get()->GetCachedCrx(app_id_, &crx_path, &version);
104 bool installed = extensions::ExtensionSystem::Get(profile_)
105 ->extension_service()
106 ->GetInstalledExtension(app_id_);
107 KioskAppManager* kiosk_app_manager = KioskAppManager::Get();
108 if (installed || crx_cached) {
109 // If KioskAppManager is still checking update for |app_id_|, wait until
110 // it completes.
111 if (kiosk_app_manager->IsExtensionPendingForUpdateCheck(app_id_)) {
112 crx_ready_for_install_ = false;
113 return;
114 }
115 // If the app is installed or its crx file is cached, either check update
116 // or install the app.
117 MaybeInstall();
118 } else {
119 // If the app is still being downloaded, wait until it completes.
120 if (kiosk_app_manager->IsExtensionPendingForCache(app_id_)) {
121 crx_ready_for_install_ = false;
122 return;
123 }
124 LOG(ERROR) << "Failed to download the app: app_id=" << app_id_;
125 OnLaunchFailure(KioskAppLaunchError::UNABLE_TO_DOWNLOAD);
126 }
97 } 127 }
98 } 128 }
99 129
100 void StartupAppLauncher::StartLoadingOAuthFile() { 130 void StartupAppLauncher::StartLoadingOAuthFile() {
101 delegate_->OnLoadingOAuthFile(); 131 delegate_->OnLoadingOAuthFile();
102 132
103 KioskOAuthParams* auth_params = new KioskOAuthParams(); 133 KioskOAuthParams* auth_params = new KioskOAuthParams();
104 BrowserThread::PostBlockingPoolTaskAndReply( 134 BrowserThread::PostBlockingPoolTaskAndReply(
105 FROM_HERE, 135 FROM_HERE,
106 base::Bind(&StartupAppLauncher::LoadOAuthFileOnBlockingPool, 136 base::Bind(&StartupAppLauncher::LoadOAuthFileOnBlockingPool,
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
145 } 175 }
146 176
147 // If we are restarting chrome (i.e. on crash), we need to initialize 177 // If we are restarting chrome (i.e. on crash), we need to initialize
148 // OAuth2TokenService as well. 178 // OAuth2TokenService as well.
149 InitializeTokenService(); 179 InitializeTokenService();
150 } 180 }
151 181
152 void StartupAppLauncher::RestartLauncher() { 182 void StartupAppLauncher::RestartLauncher() {
153 // If the installer is still running in the background, we don't need to 183 // 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 184 // restart the launch process. We will just wait until it completes and
155 // lunches the kiosk app. 185 // launches the kiosk app.
156 if (installer_ != NULL) { 186 if (extensions::ExtensionSystem::Get(profile_)
187 ->extension_service()
188 ->pending_extension_manager()
189 ->IsIdPending(app_id_)) {
157 LOG(WARNING) << "Installer still running"; 190 LOG(WARNING) << "Installer still running";
158 return; 191 return;
159 } 192 }
160 193
161 MaybeInitializeNetwork(); 194 MaybeInitializeNetwork();
162 } 195 }
163 196
164 void StartupAppLauncher::MaybeInitializeNetwork() { 197 void StartupAppLauncher::MaybeInitializeNetwork() {
165 network_ready_handled_ = false; 198 network_ready_handled_ = false;
166 199
167 const Extension* extension = extensions::ExtensionSystem::Get(profile_)-> 200 const Extension* extension = extensions::ExtensionSystem::Get(profile_)->
168 extension_service()->GetInstalledExtension(app_id_); 201 extension_service()->GetInstalledExtension(app_id_);
169 const bool requires_network = !extension || 202 base::FilePath crx_path;
170 !extensions::OfflineEnabledInfo::IsOfflineEnabled(extension); 203 std::string version;
204 bool crx_cached =
205 KioskAppManager::Get()->GetCachedCrx(app_id_, &crx_path, &version);
206 const bool requires_network =
207 (!extension && !crx_cached) ||
208 (extension &&
209 !extensions::OfflineEnabledInfo::IsOfflineEnabled(extension));
171 210
172 if (requires_network) { 211 if (requires_network) {
173 delegate_->InitializeNetwork(); 212 delegate_->InitializeNetwork();
174 return; 213 return;
175 } 214 }
176 215
177 // Offline enabled app attempts update if network is ready. Otherwise, 216 // Install the extension if it is not installed yet, or update the extension
178 // go directly to launch. 217 // if it is already installed and the network is ready; otherwise, launch the
179 if (delegate_->IsNetworkReady()) 218 // offline enabled app.
219 if (!extension)
220 MaybeInstall();
221 else if (delegate_->IsNetworkReady())
180 ContinueWithNetworkReady(); 222 ContinueWithNetworkReady();
181 else 223 else
182 OnReadyToLaunch(); 224 OnReadyToLaunch();
183 } 225 }
184 226
185 void StartupAppLauncher::InitializeTokenService() { 227 void StartupAppLauncher::InitializeTokenService() {
186 delegate_->OnInitializingTokenService(); 228 delegate_->OnInitializingTokenService();
187 229
188 ProfileOAuth2TokenService* profile_token_service = 230 ProfileOAuth2TokenService* profile_token_service =
189 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_); 231 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
221 ->RemoveObserver(this); 263 ->RemoveObserver(this);
222 MaybeInitializeNetwork(); 264 MaybeInitializeNetwork();
223 } 265 }
224 266
225 void StartupAppLauncher::OnRefreshTokensLoaded() { 267 void StartupAppLauncher::OnRefreshTokensLoaded() {
226 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_) 268 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_)
227 ->RemoveObserver(this); 269 ->RemoveObserver(this);
228 MaybeInitializeNetwork(); 270 MaybeInitializeNetwork();
229 } 271 }
230 272
273 void StartupAppLauncher::OnFinishCrxInstall(const std::string& extension_id,
274 bool success) {
275 DCHECK(extension_id == app_id_);
xiyuan 2014/07/08 21:50:59 nit: Remove the DCHECK since "if" below handles th
jennyz 2014/07/12 00:03:21 Done.
276 if (extension_id != app_id_)
277 return;
278
279 extensions::InstallTracker* tracker =
280 extensions::InstallTrackerFactory::GetForProfile(profile_);
281 tracker->RemoveObserver(this);
282 if (delegate_->IsShowingNetworkConfigScreen()) {
283 LOG(WARNING) << "Showing network config screen";
284 return;
285 }
286
287 if (success) {
288 // Check if the app is offline enabled.
289 const Extension* extension = extensions::ExtensionSystem::Get(profile_)
290 ->extension_service()
291 ->GetInstalledExtension(extension_id);
292 DCHECK(extension);
293 const bool offline_enabled =
294 extensions::OfflineEnabledInfo::IsOfflineEnabled(extension);
295 if (offline_enabled || delegate_->IsNetworkReady()) {
296 BrowserThread::PostTask(
297 BrowserThread::UI,
298 FROM_HERE,
299 base::Bind(&StartupAppLauncher::OnReadyToLaunch, AsWeakPtr()));
300 } else {
301 ++launch_attempt_;
302 if (launch_attempt_ < kMaxLaunchAttempt) {
303 BrowserThread::PostTask(
304 BrowserThread::UI,
305 FROM_HERE,
306 base::Bind(&StartupAppLauncher::MaybeInitializeNetwork,
307 AsWeakPtr()));
308 return;
309 }
310 OnLaunchFailure(KioskAppLaunchError::UNABLE_TO_LAUNCH);
311 }
312 return;
313 }
314
315 LOG(ERROR) << "Failed to install the kiosk application app_id: "
316 << extension_id;
317 OnLaunchFailure(KioskAppLaunchError::UNABLE_TO_INSTALL);
318 }
319
320 void StartupAppLauncher::OnKioskAppDataChanged(const std::string& app_id) {
321 OnKioskAppDataLoadStatusChanged(app_id);
322 }
323
324 void StartupAppLauncher::OnKioskAppDataLoadFailure(const std::string& app_id) {
325 OnKioskAppDataLoadStatusChanged(app_id);
326 }
327
328 void StartupAppLauncher::OnKioskAppDataLoadStatusChanged(
329 const std::string& app_id) {
330 if (app_id != app_id_)
331 return;
332
333 if (!crx_ready_for_install_ &&
334 !KioskAppManager::Get()->IsExtensionPendingForCache(app_id_) &&
335 !KioskAppManager::Get()->IsExtensionPendingForUpdateCheck(app_id_)) {
336 crx_ready_for_install_ = true;
337 network_ready_handled_ = false;
338 ContinueWithNetworkReady();
339 }
340 }
341
231 void StartupAppLauncher::LaunchApp() { 342 void StartupAppLauncher::LaunchApp() {
232 if (!ready_to_launch_) { 343 if (!ready_to_launch_) {
233 NOTREACHED(); 344 NOTREACHED();
234 LOG(ERROR) << "LaunchApp() called but launcher is not initialized."; 345 LOG(ERROR) << "LaunchApp() called but launcher is not initialized.";
235 } 346 }
236 347
237 const Extension* extension = extensions::ExtensionSystem::Get(profile_)-> 348 const Extension* extension = extensions::ExtensionSystem::Get(profile_)->
238 extension_service()->GetInstalledExtension(app_id_); 349 extension_service()->GetInstalledExtension(app_id_);
239 CHECK(extension); 350 CHECK(extension);
240 351
(...skipping 30 matching lines...) Expand all
271 DCHECK_NE(KioskAppLaunchError::NONE, error); 382 DCHECK_NE(KioskAppLaunchError::NONE, error);
272 383
273 delegate_->OnLaunchFailed(error); 384 delegate_->OnLaunchFailed(error);
274 } 385 }
275 386
276 void StartupAppLauncher::MaybeInstall() { 387 void StartupAppLauncher::MaybeInstall() {
277 delegate_->OnInstallingApp(); 388 delegate_->OnInstallingApp();
278 389
279 ExtensionService* extension_service = 390 ExtensionService* extension_service =
280 extensions::ExtensionSystem::Get(profile_)->extension_service(); 391 extensions::ExtensionSystem::Get(profile_)->extension_service();
392 // The extension with be installed by external loader only when it is not
393 // installed yet, so the extension loader will not skip the installation
394 // due to the version comparison logic.
395 // TODO(jennyz): If the extension is installed, but crx is updated to a newer
396 // version, should we reinstall it again?
281 if (!extension_service->GetInstalledExtension(app_id_)) { 397 if (!extension_service->GetInstalledExtension(app_id_)) {
282 BeginInstall(); 398 BeginInstall();
283 return; 399 return;
284 } 400 }
285 401
286 extensions::ExtensionUpdater::CheckParams check_params; 402 extensions::ExtensionUpdater::CheckParams check_params;
287 check_params.ids.push_back(app_id_); 403 check_params.ids.push_back(app_id_);
288 check_params.install_immediately = true; 404 check_params.install_immediately = true;
289 check_params.callback = 405 check_params.callback =
290 base::Bind(&StartupAppLauncher::OnUpdateCheckFinished, AsWeakPtr()); 406 base::Bind(&StartupAppLauncher::OnUpdateCheckFinished, AsWeakPtr());
291 extension_service->updater()->CheckNow(check_params); 407 extension_service->updater()->CheckNow(check_params);
292 } 408 }
293 409
294 void StartupAppLauncher::OnUpdateCheckFinished() { 410 void StartupAppLauncher::OnUpdateCheckFinished() {
295 OnReadyToLaunch(); 411 OnReadyToLaunch();
296 UpdateAppData(); 412 UpdateAppData();
297 } 413 }
298 414
299 void StartupAppLauncher::BeginInstall() { 415 void StartupAppLauncher::BeginInstall() {
300 installer_ = new WebstoreStartupInstaller( 416 KioskAppManager::Get()->InstallKioskApp(app_id_);
301 app_id_,
302 profile_,
303 false,
304 base::Bind(&StartupAppLauncher::InstallCallback, AsWeakPtr()));
305 installer_->BeginInstall();
306 }
307 417
308 void StartupAppLauncher::InstallCallback(bool success, 418 if (extensions::ExtensionSystem::Get(profile_)
309 const std::string& error) { 419 ->extension_service()
310 installer_ = NULL; 420 ->pending_extension_manager()
311 if (delegate_->IsShowingNetworkConfigScreen()) { 421 ->IsIdPending(app_id_)) {
312 LOG(WARNING) << "Showing network config screen"; 422 // Observe the crx installation events.
423 extensions::InstallTracker* tracker =
424 extensions::InstallTrackerFactory::GetForProfile(profile_);
425 tracker->AddObserver(this);
313 return; 426 return;
314 } 427 }
315 428
316 if (success) { 429 // The extension is skipped for installation due to some error.
317 // Finish initialization after the callback returns. 430 OnLaunchFailure(KioskAppLaunchError::UNABLE_TO_LAUNCH);
318 // So that the app finishes its installation.
319 BrowserThread::PostTask(
320 BrowserThread::UI,
321 FROM_HERE,
322 base::Bind(&StartupAppLauncher::OnReadyToLaunch,
323 AsWeakPtr()));
324 return;
325 }
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 } 431 }
342 432
343 void StartupAppLauncher::OnReadyToLaunch() { 433 void StartupAppLauncher::OnReadyToLaunch() {
344 ready_to_launch_ = true; 434 ready_to_launch_ = true;
345 delegate_->OnReadyToLaunch(); 435 delegate_->OnReadyToLaunch();
346 } 436 }
347 437
348 void StartupAppLauncher::UpdateAppData() { 438 void StartupAppLauncher::UpdateAppData() {
349 KioskAppManager::Get()->ClearAppData(app_id_); 439 KioskAppManager::Get()->ClearAppData(app_id_);
350 KioskAppManager::Get()->UpdateAppDataFromProfile(app_id_, profile_, NULL); 440 KioskAppManager::Get()->UpdateAppDataFromProfile(app_id_, profile_, NULL);
351 } 441 }
352 442
353 } // namespace chromeos 443 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698