1868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
2868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// found in the LICENSE file.
4868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
5868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "apps/app_load_service.h"
6868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
7868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "apps/app_load_service_factory.h"
85f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "apps/app_restore_service.h"
9bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include "apps/launcher.h"
10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/browser/extensions/extension_service.h"
115e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "chrome/browser/extensions/unpacked_installer.h"
125e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "chrome/browser/profiles/profile.h"
13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/public/browser/notification_details.h"
14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/public/browser/notification_service.h"
15868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/public/browser/notification_types.h"
161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "extensions/browser/app_window/app_window_registry.h"
1723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#include "extensions/browser/extension_host.h"
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/extension_prefs.h"
191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "extensions/browser/extension_registry.h"
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/extension_system.h"
215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "extensions/browser/notification_types.h"
22f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/common/extension.h"
23868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
24868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)using extensions::Extension;
25868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)using extensions::ExtensionPrefs;
26a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)using extensions::ExtensionSystem;
27868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
28868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)namespace apps {
29868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
305e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)AppLoadService::PostReloadAction::PostReloadAction()
311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    : action_type(LAUNCH),
321e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      command_line(CommandLine::NO_PROGRAM) {
335e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)}
345e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)
35868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)AppLoadService::AppLoadService(Profile* profile)
36868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    : profile_(profile) {
375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  registrar_.Add(this,
385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                 extensions::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING,
395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                 content::NotificationService::AllSources());
401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  extensions::ExtensionRegistry::Get(profile_)->AddObserver(this);
41868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
42868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciAppLoadService::~AppLoadService() {
441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  extensions::ExtensionRegistry::Get(profile_)->RemoveObserver(this);
451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
46868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
47868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void AppLoadService::RestartApplication(const std::string& extension_id) {
485e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)  post_reload_actions_[extension_id].action_type = RESTART;
49868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  ExtensionService* service = extensions::ExtensionSystem::Get(profile_)->
50868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      extension_service();
51868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(service);
52868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  service->ReloadExtension(extension_id);
53868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
54868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void AppLoadService::RestartApplicationIfRunning(
565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const std::string& extension_id) {
575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (apps::AppRestoreService::Get(profile_)->IsAppRestorable(extension_id))
585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    RestartApplication(extension_id);
595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
615e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)bool AppLoadService::LoadAndLaunch(const base::FilePath& extension_path,
625e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)                                   const CommandLine& command_line,
635e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)                                   const base::FilePath& current_dir) {
64a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  ExtensionService* extension_service =
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ExtensionSystem::Get(profile_)->extension_service();
665e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)  std::string extension_id;
67a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (!extensions::UnpackedInstaller::Create(extension_service)->
685e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)          LoadFromCommandLine(base::FilePath(extension_path), &extension_id)) {
695e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)    return false;
705e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)  }
715e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)
725e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)  // Schedule the app to be launched once loaded.
735e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)  PostReloadAction& action = post_reload_actions_[extension_id];
745e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)  action.action_type = LAUNCH_WITH_COMMAND_LINE;
755e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)  action.command_line = command_line;
765e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)  action.current_dir = current_dir;
775e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)  return true;
78868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
79868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
80868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// static
81868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)AppLoadService* AppLoadService::Get(Profile* profile) {
82868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return apps::AppLoadServiceFactory::GetForProfile(profile);
83868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
84868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
85868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void AppLoadService::Observe(int type,
86868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                             const content::NotificationSource& source,
87868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                             const content::NotificationDetails& details) {
881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK_EQ(type, extensions::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING);
891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  extensions::ExtensionHost* host =
901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      content::Details<extensions::ExtensionHost>(details).ptr();
911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  const Extension* extension = host->extension();
921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // It is possible for an extension to be unloaded before it stops loading.
931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!extension)
941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  std::map<std::string, PostReloadAction>::iterator it =
961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      post_reload_actions_.find(extension->id());
971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (it == post_reload_actions_.end())
981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  switch (it->second.action_type) {
1011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    case LAUNCH:
1021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      LaunchPlatformApp(profile_, extension);
1031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      break;
1041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    case RESTART:
1051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      RestartPlatformApp(profile_, extension);
106868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      break;
1071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    case LAUNCH_WITH_COMMAND_LINE:
1081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      LaunchPlatformAppWithCommandLine(
1091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          profile_, extension, it->second.command_line, it->second.current_dir);
110868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      break;
111868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    default:
112868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      NOTREACHED();
113868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
1141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  post_reload_actions_.erase(it);
1161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid AppLoadService::OnExtensionUnloaded(
1191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    content::BrowserContext* browser_context,
1201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const Extension* extension,
1211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    extensions::UnloadedExtensionInfo::Reason reason) {
1221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!extension->is_platform_app())
1231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
1241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  extensions::ExtensionPrefs* extension_prefs =
1261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      extensions::ExtensionPrefs::Get(browser_context);
1271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (WasUnloadedForReload(extension->id(), reason) &&
1281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      extension_prefs->IsActive(extension->id()) &&
1291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      !HasPostReloadAction(extension->id())) {
1301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    post_reload_actions_[extension->id()].action_type = LAUNCH;
1311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
132868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
133868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
1347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochbool AppLoadService::WasUnloadedForReload(
1351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const extensions::ExtensionId& extension_id,
1361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const extensions::UnloadedExtensionInfo::Reason reason) {
1371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (reason == extensions::UnloadedExtensionInfo::REASON_DISABLE) {
1387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    ExtensionPrefs* prefs = ExtensionPrefs::Get(profile_);
1391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return (prefs->GetDisableReasons(extension_id) &
1401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            Extension::DISABLE_RELOAD) != 0;
1417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
1427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return false;
1437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
1447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochbool AppLoadService::HasPostReloadAction(const std::string& extension_id) {
1467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return post_reload_actions_.find(extension_id) != post_reload_actions_.end();
1477dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
1487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
149868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}  // namespace apps
150