Revert of Add button to add new FSP services to Files app. (patchset #8 id:140001...
[chromium-blink-merge.git] / chrome / browser / chromeos / app_mode / startup_app_launcher.cc
blob00462959140e0cb9da04417a7968953c07b808c3
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
3 // found in the LICENSE file.
5 #include "chrome/browser/chromeos/app_mode/startup_app_launcher.h"
7 #include "base/command_line.h"
8 #include "base/files/file_path.h"
9 #include "base/json/json_file_value_serializer.h"
10 #include "base/path_service.h"
11 #include "base/time/time.h"
12 #include "base/values.h"
13 #include "chrome/browser/chrome_notification_types.h"
14 #include "chrome/browser/chromeos/app_mode/app_session_lifetime.h"
15 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
16 #include "chrome/browser/chromeos/app_mode/kiosk_diagnosis_runner.h"
17 #include "chrome/browser/chromeos/login/session/user_session_manager.h"
18 #include "chrome/browser/extensions/extension_service.h"
19 #include "chrome/browser/extensions/install_tracker.h"
20 #include "chrome/browser/extensions/install_tracker_factory.h"
21 #include "chrome/browser/extensions/updater/extension_updater.h"
22 #include "chrome/browser/lifetime/application_lifetime.h"
23 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
24 #include "chrome/browser/signin/signin_manager_factory.h"
25 #include "chrome/browser/ui/extensions/app_launch_params.h"
26 #include "chrome/browser/ui/extensions/application_launch.h"
27 #include "chrome/common/chrome_paths.h"
28 #include "chrome/common/chrome_switches.h"
29 #include "chrome/common/chrome_version_info.h"
30 #include "components/crx_file/id_util.h"
31 #include "components/signin/core/browser/profile_oauth2_token_service.h"
32 #include "components/signin/core/browser/signin_manager.h"
33 #include "components/user_manager/user_manager.h"
34 #include "content/public/browser/browser_thread.h"
35 #include "content/public/browser/notification_service.h"
36 #include "extensions/browser/extension_system.h"
37 #include "extensions/common/constants.h"
38 #include "extensions/common/extension.h"
39 #include "extensions/common/manifest_handlers/kiosk_mode_info.h"
40 #include "extensions/common/manifest_handlers/offline_enabled_info.h"
41 #include "extensions/common/manifest_url_handlers.h"
42 #include "google_apis/gaia/gaia_auth_consumer.h"
43 #include "google_apis/gaia/gaia_constants.h"
44 #include "net/base/load_flags.h"
45 #include "net/url_request/url_fetcher.h"
46 #include "net/url_request/url_fetcher_delegate.h"
47 #include "net/url_request/url_request_context_getter.h"
48 #include "net/url_request/url_request_status.h"
49 #include "url/gurl.h"
51 using content::BrowserThread;
52 using extensions::Extension;
54 namespace chromeos {
56 namespace {
58 const char kOAuthRefreshToken[] = "refresh_token";
59 const char kOAuthClientId[] = "client_id";
60 const char kOAuthClientSecret[] = "client_secret";
62 const base::FilePath::CharType kOAuthFileName[] =
63 FILE_PATH_LITERAL("kiosk_auth");
65 const int kMaxLaunchAttempt = 5;
67 } // namespace
69 StartupAppLauncher::StartupAppLauncher(Profile* profile,
70 const std::string& app_id,
71 bool diagnostic_mode,
72 StartupAppLauncher::Delegate* delegate)
73 : profile_(profile),
74 app_id_(app_id),
75 diagnostic_mode_(diagnostic_mode),
76 delegate_(delegate),
77 network_ready_handled_(false),
78 launch_attempt_(0),
79 ready_to_launch_(false),
80 wait_for_crx_update_(false) {
81 DCHECK(profile_);
82 DCHECK(crx_file::id_util::IdIsValid(app_id_));
83 KioskAppManager::Get()->AddObserver(this);
86 StartupAppLauncher::~StartupAppLauncher() {
87 KioskAppManager::Get()->RemoveObserver(this);
89 // StartupAppLauncher can be deleted at anytime during the launch process
90 // through a user bailout shortcut.
91 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_)
92 ->RemoveObserver(this);
93 extensions::InstallTrackerFactory::GetForBrowserContext(profile_)
94 ->RemoveObserver(this);
97 void StartupAppLauncher::Initialize() {
98 StartLoadingOAuthFile();
101 void StartupAppLauncher::ContinueWithNetworkReady() {
102 if (!network_ready_handled_) {
103 network_ready_handled_ = true;
104 // The network might not be ready when KioskAppManager tries to update
105 // external cache initially. Update the external cache now that the network
106 // is ready for sure.
107 wait_for_crx_update_ = true;
108 KioskAppManager::Get()->UpdateExternalCache();
112 void StartupAppLauncher::StartLoadingOAuthFile() {
113 delegate_->OnLoadingOAuthFile();
115 KioskOAuthParams* auth_params = new KioskOAuthParams();
116 BrowserThread::PostBlockingPoolTaskAndReply(
117 FROM_HERE,
118 base::Bind(&StartupAppLauncher::LoadOAuthFileOnBlockingPool,
119 auth_params),
120 base::Bind(&StartupAppLauncher::OnOAuthFileLoaded,
121 AsWeakPtr(),
122 base::Owned(auth_params)));
125 // static.
126 void StartupAppLauncher::LoadOAuthFileOnBlockingPool(
127 KioskOAuthParams* auth_params) {
128 int error_code = JSONFileValueDeserializer::JSON_NO_ERROR;
129 std::string error_msg;
130 base::FilePath user_data_dir;
131 CHECK(PathService::Get(chrome::DIR_USER_DATA, &user_data_dir));
132 base::FilePath auth_file = user_data_dir.Append(kOAuthFileName);
133 scoped_ptr<JSONFileValueDeserializer> deserializer(
134 new JSONFileValueDeserializer(user_data_dir.Append(kOAuthFileName)));
135 scoped_ptr<base::Value> value(
136 deserializer->Deserialize(&error_code, &error_msg));
137 base::DictionaryValue* dict = NULL;
138 if (error_code != JSONFileValueDeserializer::JSON_NO_ERROR ||
139 !value.get() || !value->GetAsDictionary(&dict)) {
140 LOG(WARNING) << "Can't find auth file at " << auth_file.value();
141 return;
144 dict->GetString(kOAuthRefreshToken, &auth_params->refresh_token);
145 dict->GetString(kOAuthClientId, &auth_params->client_id);
146 dict->GetString(kOAuthClientSecret, &auth_params->client_secret);
149 void StartupAppLauncher::OnOAuthFileLoaded(KioskOAuthParams* auth_params) {
150 auth_params_ = *auth_params;
151 // Override chrome client_id and secret that will be used for identity
152 // API token minting.
153 if (!auth_params_.client_id.empty() && !auth_params_.client_secret.empty()) {
154 UserSessionManager::GetInstance()->SetAppModeChromeClientOAuthInfo(
155 auth_params_.client_id,
156 auth_params_.client_secret);
159 // If we are restarting chrome (i.e. on crash), we need to initialize
160 // OAuth2TokenService as well.
161 InitializeTokenService();
164 void StartupAppLauncher::RestartLauncher() {
165 // If the installer is still running in the background, we don't need to
166 // restart the launch process. We will just wait until it completes and
167 // launches the kiosk app.
168 if (extensions::ExtensionSystem::Get(profile_)
169 ->extension_service()
170 ->pending_extension_manager()
171 ->IsIdPending(app_id_)) {
172 LOG(WARNING) << "Installer still running";
173 return;
176 MaybeInitializeNetwork();
179 void StartupAppLauncher::MaybeInitializeNetwork() {
180 network_ready_handled_ = false;
182 const Extension* extension = extensions::ExtensionSystem::Get(profile_)->
183 extension_service()->GetInstalledExtension(app_id_);
184 bool crx_cached = KioskAppManager::Get()->HasCachedCrx(app_id_);
185 const bool requires_network =
186 (!extension && !crx_cached) ||
187 (extension &&
188 !extensions::OfflineEnabledInfo::IsOfflineEnabled(extension));
190 if (requires_network) {
191 delegate_->InitializeNetwork();
192 return;
195 // Update the offline enabled crx cache if the network is ready;
196 // or just install the app.
197 if (delegate_->IsNetworkReady())
198 ContinueWithNetworkReady();
199 else
200 BeginInstall();
203 void StartupAppLauncher::InitializeTokenService() {
204 delegate_->OnInitializingTokenService();
206 ProfileOAuth2TokenService* profile_token_service =
207 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
208 SigninManagerBase* signin_manager =
209 SigninManagerFactory::GetForProfile(profile_);
210 const std::string primary_account_id =
211 signin_manager->GetAuthenticatedAccountId();
212 if (profile_token_service->RefreshTokenIsAvailable(primary_account_id) ||
213 auth_params_.refresh_token.empty()) {
214 MaybeInitializeNetwork();
215 } else {
216 // Pass oauth2 refresh token from the auth file.
217 // TODO(zelidrag): We should probably remove this option after M27.
218 // TODO(fgorski): This can go when we have persistence implemented on PO2TS.
219 // Unless the code is no longer needed.
220 // TODO(rogerta): Now that this CL implements token persistence in PO2TS, is
221 // this code still needed? See above two TODOs.
223 // ProfileOAuth2TokenService triggers either OnRefreshTokenAvailable or
224 // OnRefreshTokensLoaded. Given that we want to handle exactly one event,
225 // whichever comes first, both handlers call RemoveObserver on PO2TS.
226 // Handling any of the two events is the only way to resume the execution
227 // and enable Cleanup method to be called, self-invoking a destructor.
228 profile_token_service->AddObserver(this);
230 profile_token_service->UpdateCredentials(
231 primary_account_id,
232 auth_params_.refresh_token);
236 void StartupAppLauncher::OnRefreshTokenAvailable(
237 const std::string& account_id) {
238 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_)
239 ->RemoveObserver(this);
240 MaybeInitializeNetwork();
243 void StartupAppLauncher::OnRefreshTokensLoaded() {
244 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_)
245 ->RemoveObserver(this);
246 MaybeInitializeNetwork();
249 void StartupAppLauncher::MaybeLaunchApp() {
250 // Check if the app is offline enabled.
251 const Extension* extension = extensions::ExtensionSystem::Get(profile_)
252 ->extension_service()
253 ->GetInstalledExtension(app_id_);
254 DCHECK(extension);
255 const bool offline_enabled =
256 extensions::OfflineEnabledInfo::IsOfflineEnabled(extension);
257 if (offline_enabled || delegate_->IsNetworkReady()) {
258 BrowserThread::PostTask(
259 BrowserThread::UI,
260 FROM_HERE,
261 base::Bind(&StartupAppLauncher::OnReadyToLaunch, AsWeakPtr()));
262 } else {
263 ++launch_attempt_;
264 if (launch_attempt_ < kMaxLaunchAttempt) {
265 BrowserThread::PostTask(
266 BrowserThread::UI,
267 FROM_HERE,
268 base::Bind(&StartupAppLauncher::MaybeInitializeNetwork, AsWeakPtr()));
269 return;
271 OnLaunchFailure(KioskAppLaunchError::UNABLE_TO_LAUNCH);
275 void StartupAppLauncher::OnFinishCrxInstall(const std::string& extension_id,
276 bool success) {
277 // Wait for pending updates or dependent extensions to download.
278 if (extensions::ExtensionSystem::Get(profile_)
279 ->extension_service()
280 ->pending_extension_manager()
281 ->HasPendingExtensions()) {
282 return;
285 extensions::InstallTracker* tracker =
286 extensions::InstallTrackerFactory::GetForBrowserContext(profile_);
287 tracker->RemoveObserver(this);
288 if (delegate_->IsShowingNetworkConfigScreen()) {
289 LOG(WARNING) << "Showing network config screen";
290 return;
293 if (success) {
294 MaybeLaunchApp();
295 return;
298 LOG(ERROR) << "Failed to install the kiosk application app_id: "
299 << extension_id;
300 OnLaunchFailure(KioskAppLaunchError::UNABLE_TO_INSTALL);
303 void StartupAppLauncher::OnKioskExtensionLoadedInCache(
304 const std::string& app_id) {
305 OnKioskAppDataLoadStatusChanged(app_id);
308 void StartupAppLauncher::OnKioskExtensionDownloadFailed(
309 const std::string& app_id) {
310 OnKioskAppDataLoadStatusChanged(app_id);
313 void StartupAppLauncher::OnKioskAppDataLoadStatusChanged(
314 const std::string& app_id) {
315 if (app_id != app_id_ || !wait_for_crx_update_)
316 return;
318 wait_for_crx_update_ = false;
319 if (KioskAppManager::Get()->HasCachedCrx(app_id_))
320 BeginInstall();
321 else
322 OnLaunchFailure(KioskAppLaunchError::UNABLE_TO_DOWNLOAD);
325 void StartupAppLauncher::LaunchApp() {
326 if (!ready_to_launch_) {
327 NOTREACHED();
328 LOG(ERROR) << "LaunchApp() called but launcher is not initialized.";
331 const Extension* extension = extensions::ExtensionSystem::Get(profile_)->
332 extension_service()->GetInstalledExtension(app_id_);
333 CHECK(extension);
335 if (!extensions::KioskModeInfo::IsKioskEnabled(extension)) {
336 OnLaunchFailure(KioskAppLaunchError::NOT_KIOSK_ENABLED);
337 return;
340 // Always open the app in a window.
341 OpenApplication(AppLaunchParams(profile_, extension,
342 extensions::LAUNCH_CONTAINER_WINDOW,
343 NEW_WINDOW, extensions::SOURCE_KIOSK));
344 InitAppSession(profile_, app_id_);
346 user_manager::UserManager::Get()->SessionStarted();
348 content::NotificationService::current()->Notify(
349 chrome::NOTIFICATION_KIOSK_APP_LAUNCHED,
350 content::NotificationService::AllSources(),
351 content::NotificationService::NoDetails());
353 if (diagnostic_mode_)
354 KioskDiagnosisRunner::Run(profile_, app_id_);
356 OnLaunchSuccess();
359 void StartupAppLauncher::OnLaunchSuccess() {
360 delegate_->OnLaunchSucceeded();
363 void StartupAppLauncher::OnLaunchFailure(KioskAppLaunchError::Error error) {
364 LOG(ERROR) << "App launch failed, error: " << error;
365 DCHECK_NE(KioskAppLaunchError::NONE, error);
367 delegate_->OnLaunchFailed(error);
370 void StartupAppLauncher::BeginInstall() {
371 KioskAppManager::Get()->InstallFromCache(app_id_);
372 if (extensions::ExtensionSystem::Get(profile_)
373 ->extension_service()
374 ->pending_extension_manager()
375 ->IsIdPending(app_id_)) {
376 delegate_->OnInstallingApp();
377 // Observe the crx installation events.
378 extensions::InstallTracker* tracker =
379 extensions::InstallTrackerFactory::GetForBrowserContext(profile_);
380 tracker->AddObserver(this);
381 return;
384 if (extensions::ExtensionSystem::Get(profile_)
385 ->extension_service()
386 ->GetInstalledExtension(app_id_)) {
387 // Launch the app.
388 OnReadyToLaunch();
389 } else {
390 // The extension is skipped for installation due to some error.
391 OnLaunchFailure(KioskAppLaunchError::UNABLE_TO_INSTALL);
395 void StartupAppLauncher::OnReadyToLaunch() {
396 ready_to_launch_ = true;
397 UpdateAppData();
398 delegate_->OnReadyToLaunch();
401 void StartupAppLauncher::UpdateAppData() {
402 KioskAppManager::Get()->ClearAppData(app_id_);
403 KioskAppManager::Get()->UpdateAppDataFromProfile(app_id_, profile_, NULL);
406 } // namespace chromeos