Home | History | Annotate | Download | only in extensions
      1 // Copyright 2014 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.
      4 
      5 #include "chrome/browser/extensions/extension_gcm_app_handler.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/lazy_instance.h"
      9 #include "base/location.h"
     10 #include "chrome/browser/chrome_notification_types.h"
     11 #include "chrome/browser/profiles/profile.h"
     12 #include "chrome/browser/services/gcm/gcm_profile_service.h"
     13 #include "chrome/browser/services/gcm/gcm_profile_service_factory.h"
     14 #include "components/gcm_driver/gcm_driver.h"
     15 #include "extensions/browser/extension_registry.h"
     16 #include "extensions/browser/extension_system.h"
     17 #include "extensions/common/extension.h"
     18 #include "extensions/common/permissions/permissions_data.h"
     19 
     20 #if !defined(OS_ANDROID)
     21 #include "chrome/browser/extensions/api/gcm/gcm_api.h"
     22 #endif
     23 
     24 namespace extensions {
     25 
     26 namespace {
     27 
     28 const char kDummyAppId[] = "extension.guard.dummy.id";
     29 
     30 base::LazyInstance<BrowserContextKeyedAPIFactory<ExtensionGCMAppHandler> >
     31     g_factory = LAZY_INSTANCE_INITIALIZER;
     32 
     33 bool IsGCMPermissionEnabled(const Extension* extension) {
     34   return extension->permissions_data()->HasAPIPermission(APIPermission::kGcm);
     35 }
     36 
     37 }  // namespace
     38 
     39 
     40 // static
     41 BrowserContextKeyedAPIFactory<ExtensionGCMAppHandler>*
     42 ExtensionGCMAppHandler::GetFactoryInstance() {
     43   return g_factory.Pointer();
     44 }
     45 
     46 ExtensionGCMAppHandler::ExtensionGCMAppHandler(content::BrowserContext* context)
     47     : profile_(Profile::FromBrowserContext(context)),
     48       extension_registry_observer_(this),
     49       weak_factory_(this) {
     50   extension_registry_observer_.Add(ExtensionRegistry::Get(profile_));
     51 #if !defined(OS_ANDROID)
     52   js_event_router_.reset(new extensions::GcmJsEventRouter(profile_));
     53 #endif
     54 }
     55 
     56 ExtensionGCMAppHandler::~ExtensionGCMAppHandler() {
     57   const ExtensionSet& enabled_extensions =
     58       ExtensionRegistry::Get(profile_)->enabled_extensions();
     59   for (ExtensionSet::const_iterator extension = enabled_extensions.begin();
     60        extension != enabled_extensions.end();
     61        ++extension) {
     62     if (IsGCMPermissionEnabled(extension->get()))
     63       GetGCMDriver()->RemoveAppHandler((*extension)->id());
     64   }
     65 }
     66 
     67 void ExtensionGCMAppHandler::ShutdownHandler() {
     68 #if !defined(OS_ANDROID)
     69   js_event_router_.reset();
     70 #endif
     71 }
     72 
     73 void ExtensionGCMAppHandler::OnMessage(
     74     const std::string& app_id,
     75     const gcm::GCMClient::IncomingMessage& message) {
     76 #if !defined(OS_ANDROID)
     77   js_event_router_->OnMessage(app_id, message);
     78 #endif
     79 }
     80 
     81 void ExtensionGCMAppHandler::OnMessagesDeleted(const std::string& app_id) {
     82 #if !defined(OS_ANDROID)
     83   js_event_router_->OnMessagesDeleted(app_id);
     84 #endif
     85 }
     86 
     87 void ExtensionGCMAppHandler::OnSendError(
     88     const std::string& app_id,
     89     const gcm::GCMClient::SendErrorDetails& send_error_details) {
     90 #if !defined(OS_ANDROID)
     91   js_event_router_->OnSendError(app_id, send_error_details);
     92 #endif
     93 }
     94 
     95 void ExtensionGCMAppHandler::OnExtensionLoaded(
     96     content::BrowserContext* browser_context,
     97     const Extension* extension) {
     98   if (IsGCMPermissionEnabled(extension))
     99     AddAppHandler(extension->id());
    100 }
    101 
    102 void ExtensionGCMAppHandler::OnExtensionUnloaded(
    103     content::BrowserContext* browser_context,
    104     const Extension* extension,
    105     UnloadedExtensionInfo::Reason reason) {
    106   if (!IsGCMPermissionEnabled(extension))
    107     return;
    108 
    109   if (reason == UnloadedExtensionInfo::REASON_UPDATE &&
    110       GetGCMDriver()->app_handlers().size() == 1) {
    111     // When the extension is being updated, it will be first unloaded and then
    112     // loaded again by ExtensionService::AddExtension. If the app handler for
    113     // this extension is the only handler, removing it and adding it again will
    114     // cause the GCM service being stopped and restarted unnecessarily. To work
    115     // around this, we add a dummy app handler to guard against it. This dummy
    116     // app handler will be removed once the extension loading logic is done.
    117     //
    118     // Also note that the GCM message routing will not be interruptted during
    119     // the update process since unloading and reloading extension are done in
    120     // the single function ExtensionService::AddExtension.
    121     AddDummyAppHandler();
    122 
    123     base::MessageLoop::current()->PostTask(
    124         FROM_HERE,
    125         base::Bind(&ExtensionGCMAppHandler::RemoveDummyAppHandler,
    126                    weak_factory_.GetWeakPtr()));
    127   }
    128 
    129   RemoveAppHandler(extension->id());
    130 }
    131 
    132 void ExtensionGCMAppHandler::OnExtensionUninstalled(
    133     content::BrowserContext* browser_context,
    134     const Extension* extension) {
    135   if (IsGCMPermissionEnabled(extension)) {
    136     GetGCMDriver()->Unregister(
    137         extension->id(),
    138         base::Bind(&ExtensionGCMAppHandler::OnUnregisterCompleted,
    139                    weak_factory_.GetWeakPtr(),
    140                    extension->id()));
    141     RemoveAppHandler(extension->id());
    142   }
    143 }
    144 
    145 void ExtensionGCMAppHandler::AddDummyAppHandler() {
    146   AddAppHandler(kDummyAppId);
    147 }
    148 
    149 void ExtensionGCMAppHandler::RemoveDummyAppHandler() {
    150   RemoveAppHandler(kDummyAppId);
    151 }
    152 
    153 gcm::GCMDriver* ExtensionGCMAppHandler::GetGCMDriver() const {
    154   return gcm::GCMProfileServiceFactory::GetForProfile(profile_)->driver();
    155 }
    156 
    157 void ExtensionGCMAppHandler::OnUnregisterCompleted(
    158     const std::string& app_id, gcm::GCMClient::Result result) {
    159   // Nothing to do.
    160 }
    161 
    162 void ExtensionGCMAppHandler::AddAppHandler(const std::string& app_id) {
    163   GetGCMDriver()->AddAppHandler(app_id, this);
    164 }
    165 
    166 void ExtensionGCMAppHandler::RemoveAppHandler(const std::string& app_id) {
    167   GetGCMDriver()->RemoveAppHandler(app_id);
    168 }
    169 
    170 }  // namespace extensions
    171